Skip to content

READVAL WRITEVAL codes Coding explanation

btsimonh edited this page May 26, 2019 · 2 revisions

Controlling/Configuring the hoverboard firmware through READVAL/WRITEVAL

protocol.c contains code to read and write data from the howverboard firmware in a generic way.

The table 'params' defines what happens when a specific code is sent as the code entry for READVAL or WRITEVAL.

Each entry in the table is in the form of a PARAMSTAT entry:

struct tag_PARAMSTAT {
    unsigned char code;     // code in protocol to refer to this
    char *description;      // if non-null, description
    char *uistr;            // if non-null, used in ascii protocol to adjust with f<str>num<cr>
    char ui_type;           // only UI_NONE or UI_SHORT
    void *ptr;              // pointer to value
    int len;               // length of value
    char rw;                // PARAM_R or PARAM_RW

    PARAMSTAT_FN fn;        // function to handle events
};

code

this is the code to send to REAVAL or WRITEVAL to access this entry

description

if non null, used to display a description in the ascii protocol help listings for 'f'.

uistr

if non-null, used in ascii protocol to adjust with fnum

ui_type

UI_NONE or UI_SHORT - determines interpretation of 'num' in fnum

ptr

this is be a pointer to the data to be read/written

len

this is the length of data which can be read/written.

Note that it is valid to read/write LESS than this value.

rw

This defines if data is PARAM_R (1), or PARAM_RW (3)

fn - helper function

is of the form:

void fn( PROTOCOL_STAT *s, PARAMSTAT *param, uint8_t fn_type, int len ) {
    switch (fn_type) {
        case FN_TYPE_PRE_READ:
        case FN_TYPE_POST_READ:
        case FN_TYPE_PRE_READRESPONSE:
        case FN_TYPE_POST_READRESPONSE:
            break;

        case FN_TYPE_PRE_WRITE:
        case FN_TYPE_POST_WRITE:
        case FN_TYPE_PRE_WRITERESPONSE:
        case FN_TYPE_POST_WRITERESPONSE:
            break;
    }
}

this is an optional helper function which is called:

  • before the data is read, (fn_type = FN_TYPE_PRE_READ, FN_TYPE_PRE_READRESPONSE)
  • after data is read, (fn_type = FN_TYPE_POST_READ, FN_TYPE_POST_READRESPONSE)
  • before data is written, (fn_type = FN_TYPE_PRE_WRITE, FN_TYPE_PRE_WRITERESPONSE)
  • after data is written, (fn_type = FN_TYPE_POST_WRITE, FN_TYPE_POST_WRITERESPONSE)

of the 8 current fn_types, four are used with PROTOCOL_CMD_READVAL and PROTOCOL_CMD_WRITEVAL, and four are user with PROTOCOL_CMD_READVALRESPONSE and PROTOCOL_CMD_WRITEVALRESPONSE.

PROTOCOL_CMD_READVALRESPONSE and PROTOCOL_CMD_WRITEVALRESPONSE are intended for use when this repo is used in a controlling application.

  • examples of use of the helper function *

PRE_READ - e.g. maybe volatile data must be copied with amutex to a safe reading memory location. POST_READ - e.g. maybe you are reading a counter, and want it reset to zero after reading. PRE_WRITE - e.g. maybe the whole structure should be zeroed before a short write. POST_WRITE - e.g. maybe writing to this 'subcommand' actually does a lot more than write an area of memory - e.g. write to PID values may require a reset of PID routines.

Adding functionality

Depending upon your requirements, the above structure should allow:

1/ easy adding of direct access to variables in memory, for readonly or read/write. This is the simplest form of enhancement.

2/ ability to perform more complex functions upon reading or writing a 'subcommand'

real example:

the function:

void fn_BuzzerData ( PROTOCOL_STAT *s, PARAMSTAT *param, uint8_t fn_type, int len ) {
    switch (fn_type) {
        case FN_TYPE_POST_WRITE:
            buzzerFreq      = ((BUZZER_DATA*) (param->ptr))->buzzerFreq;
            buzzerLen       = ((BUZZER_DATA*) (param->ptr))->buzzerLen;
            buzzerPattern   = ((BUZZER_DATA*) (param->ptr))->buzzerPattern;
            break;

        case FN_TYPE_PRE_READ:
            ((BUZZER_DATA*) (param->ptr))->buzzerFreq       = buzzerFreq;
            ((BUZZER_DATA*) (param->ptr))->buzzerLen        = buzzerLen;
            ((BUZZER_DATA*) (param->ptr))->buzzerPattern    = buzzerPattern;
            break;
    }
}

enables setting of buzzer values. Since these values are separate global variables, we must copy them from the structure we use to read/write them to/from the global variables.