Studio:Working with pointers to target-resident functions

From STRIDE Wiki
(Redirected from Working with pointers to target-resident functions)
Jump to navigation Jump to search

A technique for calling target-resident functions through opaque function pointers

Occasionally it is desirable to execute functions on the target that are unknown to the host; that is, the functions to be called are implemented on the target and not exposed to the host through an interface. For example, a target-based function, TaskCreate, could accept as input a function pointer that it uses to start a task. These task functions are unknown to the caller of TaskCreate on the host. The pointer passed into TaskCreate is opaque from the caller's perspective. As far as the caller knows, a task handle is gotten from somewhere, and calls TaskCreate in order to start it.

So how can a task handle be obtained by the host? A target-based inline helper function could be written to pass back an opaque pointer to an appropriate function, based on criteria passed in by the caller.

The following code sample illustrates our example:

  typedef enum {
      TASK_SETUP,
      TASK_READ,
      TASK_SHUTDOWN
  } ETaskTypes;
  
  typedef void (*TaskHandle)(void);
  
  void TaskCreate(TaskHandle handle);
  void Setup(void);
  void Read(void);
  void Shutdown(void);
  
  __inline void* getTaskHandle(ETaskTypes eChoice)
  {
      switch (eChoice) {
      case TASK_SETUP:
          return &Setup;
      case TASK_READ:
          return &Read;
      case TASK_SHUTDOWN:
          return &Shutdown;
      default:
          return 0;
      }
  }
  
  #pragma scl_function(getTaskHandle)
  #pragma scl_function(TaskCreate)

Here, TaskCreate is our captured function on the target that accepts task handles to start. getTaskHandle is our helper function that takes a choice as input and returns a pointer to one of the on-target functions Setup, Read, and Shutdown. The only interfaces to the host are the captured functions getTaskHandle and TaskCreate.

Finally, we show how these interfaces are called from a host script:

  studio.Workspace.Interfaces.Item("getTaskHandle").Owner.Register();
  studio.Workspace.Interfaces.Item("TaskCreate").Owner.Register();
  
  var fnGetTaskHandle = ascript.Functions.Item("getTaskHandle");
  var fnTaskCreate = ascript.Functions.Item("TaskCreate");
  
  // get and call the setup task
  fnGetTaskHandle.User.ParameterList.eChoice = "TASK_SETUP";
  fnGetTaskHandle.User.Call();
  ascript.MessageBox(fnGetTaskHandle.User.ReturnValue);
  fnTaskCreate.User.ParameterList.handle = fnGetTaskHandle.User.ReturnValue;
  fnTaskCreate.User.Call();
  
  // get and call the read task
  fnGetTaskHandle.User.ParameterList.eChoice = "TASK_READ";
  fnGetTaskHandle.User.Call();
  ascript.MessageBox(fnGetTaskHandle.User.ReturnValue);
  fnTaskCreate.User.ParameterList.handle = fnGetTaskHandle.User.ReturnValue;
  fnTaskCreate.User.Call();
  
  // get and call the shutdown task
  fnGetTaskHandle.User.ParameterList.eChoice = "TASK_SHUTDOWN";
  fnGetTaskHandle.User.Call();
  ascript.MessageBox(fnGetTaskHandle.User.ReturnValue);
  fnTaskCreate.User.ParameterList.handle = fnGetTaskHandle.User.ReturnValue;
  fnTaskCreate.User.Call();