Read value of variables from outside of Storyboard

Hi, so I have been trying to use iogen and iorcv to set and get variable values from the Storyboard. I tried this by first running the iorcv to listen to the "test" channel (shown in picture below) which corresponds to my application, running my application in Storyboard as normally, and then running iogen in a separate command prompt to toggle the variable "toggle" of Checkbox inside Layer to 1. However, with this setup, the iogen is unable to get to "verification OK!" part and is stuck, with the iorcv command prompt showing a greio.iodata_set data value that is not equal to what I want.

This is also evident if I run the debugger and check the value of Layer.Checkbox.toggle manually; it is not changed/toggled to 1.

The command prompt commands I executed is shown below:

But if I run only the iogen command (without first running iorcv), it works fine.

Thus my problem is that I can set values in the Storyboard externally, but I cannot read or verify variable values in the Storyboard. Can anyone help me with how to read variable values from an external source (like the cmd prompt above or even better probably from a Python script)?

0

Comments

1 comment
  • Official comment

    Hi Aldo,

    It is certainly possible to also write to and read back the values of application variables using Storyboard IO API:

    https://support.cranksoftware.com/hc/en-us/articles/360056943772-Storyboard-IO-Utilities 

    https://support.cranksoftware.com/hc/en-us/articles/360057413451-Setting-Application-Data

    You can test the set data operation by using for example  the ClusterIO sample that is included with Storyboard Designer.  I can set the speed value variable (speedometer_content.speed.text) to value '123' directly using iogen:

    c:\Program Files\Crank_Software\Storyboard_Engine\7.0.202102180533.39538\win32-x86-opengles_2.0-obj\bin>iogen cluster speedometer_content.speed.text greio.iodata_set 1s0 "123"
    Connecting to Storyboard IO channel [cluster]
    Verification OK!

    As you can see the iogen utility automatically verifies the result of the greio.iodata-set request by issuing a second request of type greio.iodata-get with one string parameter which is the name of the receive channel to send the response to - in this case 'iogen_receive':

    c:\Program Files\Crank_Software\Storyboard_Engine\7.0.202102180533.39538\win32-x86-opengles_2.0-obj\bin>iorcv -r cluster
    Waiting on channel [cluster]
    Event Received [greio.iodata_set] on channel [cluster]:
     Event Target: [speedometer_content.speed.text]
     Event Format: [1s0 ]
     Event Data (4 bytes):
      0x00000000: 31 32 33 00                                    123.............
    Event Received [greio.iodata_get] on channel [cluster]:
     Event Target: [speedometer_content.speed.text]
     Event Format: [1s0 ]
     Event Data (25 bytes):
      0x00000000: 69 6f 67 65 6e 2d 72 65 63 65 69 76 65 00 00 00 iogen.receive...
      0x00000010: 00 00 00 00 00 00 00 00 00                      ................

    This behaviour is hard coded in the iogen utility and so it cannot be used to do what you are trying to do in its-own.  What iogen actually does is open a receive channel 'iogen_receive' temporarily to receive the response and then validates that the variable when read back is the same value as what you sent and hence the Verification OK! message.

    Note that the receive channel parameter is fixed length must be exactly 25 bytes long so you may need to pad with NULL or space characters.

    What you actually get sent back from the request via the receive channel specified in the request is an event greio.iodata_get_reply containing the value: 

    c:\Program Files\Crank_Software\Storyboard_Engine\7.0.202102180533.39538\win32-x86-opengles_2.0-obj\bin>iorcv -r iogen_receive
    Waiting on channel [iogen_receive]
    Event Received [greio.iodata_get_reply] on channel [iogen_receive]:
     Event Target: [speedometer_content.speed.text]
     Event Format: [1s0]
     Event Data (4 bytes):
      0x00000000: 31 32 33 00                                    123.............
    Event Received [greio.iodata_get_reply] on channel [iogen_receive]:
     Event Target: [speedometer_content.speed.text]
     Event Format: [1s0]
     Event Data (4 bytes):
      0x00000000: 34 35 36 00                                    456.............

    Now you should have all the pieces and can call this from C/C++ quite easily.  This is the code fragment from iogen which does it:

    #include <gre/iodata.h>

    :
    static void
    verify_event(gre_io_t *shandle, gre_io_serialized_data_t *buffer) {
        gre_io_t *          rhandle;
        char                *event_name, *revent_name;
        char                *event_target, *revent_target;
        char                *event_format, *revent_format;
        void                *event_data, *revent_data;
        int                ret, nbytes, rnbytes;

      gre_io_serialized_data_t *nbuffer;
        iodata_get_event_t        nevent;

        //Take apart the sent message for comparison
        nbytes = gre_io_unserialize(buffer, &event_target,
                                    &event_name, &event_format, &event_data);

        //If we didn't send a set event, then don't do the verification
        if(nbytes < 0 || event_name == NULL || strcmp(event_name, GREIO_EVENT_DATA_SET) != 0) {
            return;
        }

        //Put our reply channel information in the 'get' event
        memset(&nevent, 0, sizeof(nevent));
        strcpy(nevent.reply_channel, "iogen-receive");

        rhandle = gre_io_open(nevent.reply_channel, GRE_IO_TYPE_RDONLY);
        if(rhandle == NULL) {
            printf("Can't open receive handle [%s], error %d\n", nevent.reply_channel, errno);
            return;
        }

        nbuffer = gre_io_serialize(NULL, event_target,
                                  GREIO_EVENT_DATA_GET, event_format, &nevent, sizeof(nevent));

        //Send the get message, then wait for the reply
        ret = gre_io_send(shandle, nbuffer);
        if (ret < 0) {
            printf("Can't send using handle, error %d\n", errno);
        }
        ret = gre_io_receive(rhandle, &nbuffer);
        if (ret < 0) {
            printf("Can't receive on handle, error %d\n", errno);
        }

        rnbytes = gre_io_unserialize(nbuffer, &revent_target,
                                    &revent_name, &revent_format, &revent_data);

        if(revent_target == NULL || event_target == NULL || strcmp(revent_target, event_target) != 0) {
            printf("FAIL: Event targets don't match %s vs %s\n",
                    (event_target) ? event_target : "NULL",
                    (revent_target) ? revent_target : "NULL");
        } else if(rnbytes != nbytes) {
            printf("FAIL: Number of bytes don't match %d vs %d\n", nbytes, rnbytes);
        } else if((revent_data && !event_data) ||
                  (!revent_data && event_data) ||
                  (revent_data && (memcmp(revent_data, event_data, nbytes) != 0))) {
            printf("FAIL: Event data is not equivalent \n");
        } else {
            printf("Verification OK!\n");
        }

     gre_io_free_buffer(nbuffer);
     gre_io_close(rhandle);
    }

    If you wish to experiment with Python then we have a prototype Python 3 wrapper library around Storyboard IO API.  It is available on request and there is a post on the forum here:

    https://support.cranksoftware.com/hc/en-us/community/posts/360077162471-Writing-SBIO-backend-in-Python

    Hopefully this answers your query.

    Regards,

    Garry

Please sign in to leave a comment.

Didn't find what you were looking for?

New post