@@ -175,100 +175,115 @@ where
175
175
& mut request_id,
176
176
& mut request_rmw as * mut RmwRequest < T > as * mut _ ,
177
177
)
178
- } . ok ( ) ?;
178
+ }
179
+ . ok ( ) ?;
179
180
180
181
Ok ( ( request_rmw, request_id) )
181
182
}
182
183
183
- fn send_goal_response ( & self , response : GoalResponse , request : & <<T :: SendGoalService as Service >:: Request as Message >:: RmwMsg , mut request_id : rmw_request_id_t ) -> Result < ( ) , RclrsError > {
184
- let accepted = response != GoalResponse :: Reject ;
184
+ fn send_goal_response (
185
+ & self ,
186
+ mut request_id : rmw_request_id_t ,
187
+ accepted : bool ,
188
+ ) -> Result < ( ) , RclrsError > {
189
+ type RmwResponse < T > = <<<T as rosidl_runtime_rs:: ActionImpl >:: SendGoalService as Service >:: Response as Message >:: RmwMsg ;
190
+ let mut response_rmw = RmwResponse :: < T > :: default ( ) ;
191
+ // TODO(nwn): Set the `accepted` field through a trait, similarly to how we extracted the UUID.
192
+ // response_rmw.accepted = accepted;
193
+ let handle = & * self . handle . lock ( ) ;
194
+ let result = unsafe {
195
+ // SAFETY: The action server handle is locked and so synchronized with other
196
+ // functions. The request_id and response message are uniquely owned, and so will
197
+ // not mutate during this function call.
198
+ // Also, when appropriate, `rcl_action_accept_new_goal()` has been called beforehand,
199
+ // as specified in the `rcl_action` docs.
200
+ rcl_action_send_goal_response (
201
+ handle,
202
+ & mut request_id,
203
+ & mut response_rmw as * mut RmwResponse < T > as * mut _ ,
204
+ )
205
+ }
206
+ . ok ( ) ;
207
+ match result {
208
+ Ok ( ( ) ) => Ok ( ( ) ) ,
209
+ Err ( RclrsError :: RclError {
210
+ code : RclReturnCode :: Timeout ,
211
+ ..
212
+ } ) => {
213
+ // TODO(nwn): Log an error and continue.
214
+ // (See https://github.com/ros2/rclcpp/pull/2215 for reasoning.)
215
+ Ok ( ( ) )
216
+ }
217
+ _ => result,
218
+ }
219
+ }
220
+
221
+ fn execute_goal_request ( & self ) -> Result < ( ) , RclrsError > {
222
+ let ( request, request_id) = match self . take_goal_request ( ) {
223
+ Ok ( res) => res,
224
+ Err ( RclrsError :: RclError {
225
+ code : RclReturnCode :: ServiceTakeFailed ,
226
+ ..
227
+ } ) => {
228
+ // Spurious wakeup – this may happen even when a waitset indicated that this
229
+ // action was ready, so it shouldn't be an error.
230
+ return Ok ( ( ) ) ;
231
+ }
232
+ Err ( err) => return Err ( err) ,
233
+ } ;
234
+
235
+ let mut uuid = GoalUuid :: default ( ) ;
236
+ rosidl_runtime_rs:: ExtractUuid :: extract_uuid ( & request, & mut uuid. 0 ) ;
237
+
238
+ let response: GoalResponse = {
239
+ todo ! ( "Optionally convert request to an idiomatic type for the user's callback." ) ;
240
+ todo ! ( "Call self.goal_callback(uuid, request)" ) ;
241
+ } ;
242
+
243
+ // Don't continue if the goal was rejected by the user.
244
+ if response == GoalResponse :: Reject {
245
+ return self . send_goal_response ( request_id, false ) ;
246
+ }
185
247
186
248
// SAFETY: No preconditions
187
249
let mut goal_info = unsafe { rcl_action_get_zero_initialized_goal_info ( ) } ;
188
250
// Populate the goal UUID; the other fields will be populated by rcl_action later on.
189
251
// TODO(nwn): Check this claim.
190
- rosidl_runtime_rs :: ExtractUuid :: extract_uuid ( request , & mut goal_info. goal_id . uuid ) ;
252
+ goal_info. goal_id . uuid = uuid . 0 ;
191
253
192
- let goal_handle = if accepted {
254
+ let goal_handle = {
193
255
let server_handle = & mut * self . handle . lock ( ) ;
194
256
let goal_handle_ptr = unsafe {
195
257
// SAFETY: The action server handle is locked and so synchronized with other
196
258
// functions. The request_id and response message are uniquely owned, and so will
197
259
// not mutate during this function call. The returned goal handle pointer should be
198
260
// valid unless it is null.
199
- rcl_action_accept_new_goal (
200
- server_handle,
201
- & goal_info,
202
- )
261
+ rcl_action_accept_new_goal ( server_handle, & goal_info)
203
262
} ;
204
263
if goal_handle_ptr. is_null ( ) {
205
264
// Other than rcl_get_error_string(), there's no indication what happened.
206
265
panic ! ( "Failed to accept goal" ) ;
207
266
} else {
208
- Some ( ServerGoalHandle :: < T > :: new ( goal_handle_ptr, todo ! ( "" ) , GoalUuid ( goal_info. goal_id . uuid ) ) )
267
+ ServerGoalHandle :: < T > :: new (
268
+ goal_handle_ptr,
269
+ todo ! ( "" ) ,
270
+ GoalUuid ( goal_info. goal_id . uuid ) ,
271
+ )
209
272
}
210
- } else {
211
- None
212
273
} ;
213
274
214
- {
215
- type RmwResponse < T > = <<<T as rosidl_runtime_rs:: ActionImpl >:: SendGoalService as Service >:: Response as Message >:: RmwMsg ;
216
- let mut response_rmw = RmwResponse :: < T > :: default ( ) ;
217
- // TODO(nwn): Set the `accepted` field through a trait, similarly to how we extracted the UUID.
218
- // response_rmw.accepted = accepted;
219
- let handle = & * self . handle . lock ( ) ;
220
- unsafe {
221
- // SAFETY: The action server handle is locked and so synchronized with other
222
- // functions. The request_id and response message are uniquely owned, and so will
223
- // not mutate during this function call.
224
- // Also, `rcl_action_accept_new_goal()` has been called beforehand, as specified in
225
- // the `rcl_action` docs.
226
- rcl_action_send_goal_response (
227
- handle,
228
- & mut request_id,
229
- & mut response_rmw as * mut RmwResponse < T > as * mut _ ,
230
- )
231
- } . ok ( ) ?; // TODO(nwn): Suppress RclReturnCode::Timeout?
232
- }
233
-
234
- if let Some ( goal_handle) = goal_handle {
235
- // Goal was accepted
236
-
237
- // TODO: Add a UUID->goal_handle entry to a server goal map.
275
+ self . send_goal_response ( request_id, true ) ?;
238
276
239
- if response == GoalResponse :: AcceptAndExecute {
240
- goal_handle. execute ( ) ?;
241
- }
242
-
243
- // TODO: Call publish_status()
277
+ // TODO: Add a UUID->goal_handle entry to a server goal map.
244
278
245
- // TODO: Call the goal_accepted callback
279
+ if response == GoalResponse :: AcceptAndExecute {
280
+ goal_handle. execute ( ) ?;
246
281
}
247
282
248
- Ok ( ( ) )
249
- }
283
+ self . publish_status ( ) ?;
250
284
251
- fn execute_goal_request ( & self ) -> Result < ( ) , RclrsError > {
252
- let ( request, request_id) = match self . take_goal_request ( ) {
253
- Ok ( res) => res,
254
- Err ( RclrsError :: RclError { code : RclReturnCode :: ServiceTakeFailed , .. } ) => {
255
- // Spurious wakeup – this may happen even when a waitset indicated that this
256
- // action was ready, so it shouldn't be an error.
257
- return Ok ( ( ) ) ;
258
- } ,
259
- Err ( err) => return Err ( err) ,
260
- } ;
261
-
262
- let response: GoalResponse =
263
- {
264
- let mut uuid = GoalUuid :: default ( ) ;
265
- rosidl_runtime_rs:: ExtractUuid :: extract_uuid ( & request, & mut uuid. 0 ) ;
266
-
267
- todo ! ( "Optionally convert request to an idiomatic type for the user's callback." ) ;
268
- todo ! ( "Call self.goal_callback(uuid, request)" ) ;
269
- } ;
270
-
271
- self . send_goal_response ( response, & request, request_id) ?;
285
+ // TODO: Call the user's goal_accepted callback.
286
+ todo ! ( "Call self.accepted_callback(goal_handle)" ) ;
272
287
273
288
Ok ( ( ) )
274
289
}
@@ -286,26 +301,34 @@ where
286
301
}
287
302
288
303
fn publish_status ( & self ) -> Result < ( ) , RclrsError > {
289
- let mut goal_statuses = DropGuard :: new ( unsafe {
290
- // SAFETY: No preconditions
291
- rcl_action_get_zero_initialized_goal_status_array ( )
292
- } , |mut goal_status| unsafe {
293
- // SAFETY: The goal_status array is either zero-initialized and empty or populated by
294
- // `rcl_action_get_goal_status_array`. In either case, it can be safely finalized.
295
- rcl_action_goal_status_array_fini ( & mut goal_status) ;
296
- } ) ;
304
+ let mut goal_statuses = DropGuard :: new (
305
+ unsafe {
306
+ // SAFETY: No preconditions
307
+ rcl_action_get_zero_initialized_goal_status_array ( )
308
+ } ,
309
+ |mut goal_statuses| unsafe {
310
+ // SAFETY: The goal_status array is either zero-initialized and empty or populated by
311
+ // `rcl_action_get_goal_status_array`. In either case, it can be safely finalized.
312
+ rcl_action_goal_status_array_fini ( & mut goal_statuses) ;
313
+ } ,
314
+ ) ;
297
315
298
316
unsafe {
299
317
// SAFETY: The action server is locked through the handle and goal_statuses is
300
318
// zero-initialized.
301
319
rcl_action_get_goal_status_array ( & * self . handle . lock ( ) , & mut * goal_statuses)
302
- } . ok ( ) ?;
320
+ }
321
+ . ok ( ) ?;
303
322
304
323
unsafe {
305
324
// SAFETY: The action server is locked through the handle and goal_statuses.msg is a
306
325
// valid `action_msgs__msg__GoalStatusArray` by construction.
307
- rcl_action_publish_status ( & * self . handle . lock ( ) , & goal_statuses. msg as * const _ as * const std:: ffi:: c_void )
308
- } . ok ( )
326
+ rcl_action_publish_status (
327
+ & * self . handle . lock ( ) ,
328
+ & goal_statuses. msg as * const _ as * const std:: ffi:: c_void ,
329
+ )
330
+ }
331
+ . ok ( )
309
332
}
310
333
}
311
334
0 commit comments