DDE CORE

Description

Automatically generates application code to simplify interchange of DDE containers between the backend's storage and DLO / BLO / POV.

  • Maps datastructures between transportation encoding and native DLO / BLO / POV programming language
  • Checks container validity

DDE WRITE QUEUE

record-queue:

The firmware can only process a limited number of requests to store records into flash memory (using DDE_XXX_write(), rM2M_RecData() or rM2M_WriteLog()) within a period of time.

The "Record Queue" integrated in the DDE library caches the records in RAM when the firmware cannot accept any further requests to store records in the internal flash memory.

If records have been cached in the buffer of the "record queue", cyclical checks are carried out to see if the firmware is ready to accept new requests and the data records are transferred to the firmware if possible.

The define rM2M_RecDataQ_BUFFER_BYTES can be used to adjust the size of the RAM buffer of the "Record Queue" or to deactivate the "Record Queue" (not recommended). The default size of the RAM buffer is 1kBytes (1024 bytes).

// dde/main.dde #define rM2M_RecDataQ_BUFFER_BYTES 0 // disables the queue

Record queue overflows can occur if the DLO is constantly delivering data at a higher rate than the firmware can process. In this case, the library keeps track of the lost data records as well as the lost syslog records. If the queue is able to fit one applog message, there will be an alarm applog entry generated:

// data_lost = lost historical data records (incl. lost applog data records) // logs_lost = lost syslogs records applog("dde.recordq", "lost;data=%d;logs=%d", data_lost, logs_lost)

Using the following defines is only required if you want to adapt the "Record Queue" to your needs:

rM2M_RecDataQ_BUFFER_BYTES
rM2M_RecDataQ_BUFFER_BYTES -

Used to adjust the size of the RAM buffer of the "Record Queue" or to deactivate the "Record Queue".

It is strongly recommended to use queueing.
>0 - Record Queue is active (default 1024 + 7 bytes)
=0 - Record Queue is disabled. If the flash is busy, records are lost.
record-queue

DDE CONVERSION UTILS

s64set(out v64, v32)

convert s32 value to DDE s64

v64 : s64
v32 : s32
f64set(out v64, v32)

convert f32 value to DDE f64

v64 : f64
v32 : f32
stamp40set(out stamp, seconds, sec256)
stamp : stamp40
seconds : s32
sec256 : s32 - 1/256second fraction
stamp40get(stamp)
stamp : stamp40
returns : s32 - seconds
stamp40get256(stamp)
stamp : stamp40
returns : s32 - 1/256second fraction

DDE READ

Use these steps to read values from a downward container::
  • dde_rbegin(...) - prepare for reading
  • dde_rxxx(...) - read values /w optional default if container is shorter than expected
  • ...
  • dde_rend() - end reading
  • dde_rbegin(cid, version=0)

    begin reading a container

    Applicable to #configX containers only!
    cid : s32 - container id e.g. DDE_xxx_id
    version : s32 - optional;
    >0 = heck if loaded container has same version
    In = ase of version mismatch: sets _dde_buf to "empty" to force followingdde_rxxx() to reset whole container to it's defaults
    returns : s32
    <0 = .. error, sets _dde_buf to "empty"
    0 = .. OK
    dde_rend()

    end reading a container

    dde_ru8(out val, def=0)
    ival : u8
    def : u8 - optional fallback default value if container does not provide the requested field
    dde_ru16(out val, def=0)
    ival : u16
    def : u16
    dde_ru32(out val, def=0)
    Note that result is "pressed" into an s32 type - e.g. the MSB is used as sign bit!
    ival : u32
    def : u32
    dde_rs8(out ival, def=0)
    ival : s8
    def : s8
    dde_rs16(out ival, def=0)
    ival : s16
    def : s16
    dde_rs32(out ival, def=0)
    ival : s32
    def : s32
    dde_rs64(out ival, def=0)
    ival : s64
    def : s64 - optional fallback default value if container does not provide the requested field
    dde_rf16(out fval, def=0.0)
    fval : f16
    def : f16
    dde_rf32(out fval, def=0.0)
    fval : f32
    def : f32
    dde_rf64(out fval, def=0.0)
    fval : f64
    def : f64
    dde_rstamp32(out stamp, def=0)
    stamp : stamp32
    dde_wstamp40(stamp)
    stamp : stamp40
    dde_rbin(out val, len, def=0)
    val[] : u8 - output buffer with at least
    len bytes size
    len : s32 - number of bytes to read
    def[] : u8 - default value if container does not provide any data
    dde_rastr(out str, fsize, def="")

    read CP-1252 ANSI string from uplink buffer containing 8bit ANSI.

    The terminating zero is optional in the source (uplink) buffer, but granted in the output buffer.
    str : astr - output buffer, always with terminating zero; unused bytes remain unchanged.
    fsize : s32 - size [bytes] of source field - e.g. max. number of bytes to read.
    def : astr - optional fallback value used if uplink buffer does not supply any data.
    dde_rnstr(out str, fsize, def="")

    read CP-1252 ANSI string from uplink buffer containing Unicode utf-8.

    Same as dde_rastr(), but maps CP-1252 ANSI string from Unicode utf-8.
    Unicode characters which are not part of CP-1252, as well as invalid utf-8 codesare replaced with '?' and issue once a warning on the testBed console.
    str : astr
    fsize : s32
    dde_rwstr(out str, fsize, def='''')

    read unpacked Unicode utf-32 string from uplink buffer containing Unicode utf-8.

    The terminating zero is optional in the source (uplink) buffer, but granted in the output buffer.
    Invalid utf-8 codes are replaced with '?' and issue once a warning on the testBed console.
    str : wstr - output buffer, always with terminating zero; unused bytes remain unchanged.
    fsize : s32 - size [bytes] of source field - e.g. max. number of bytes to read.
    def : wstr - optional fallback value used if uplink buffer does not supply any data.
    dde_rustr(out str, fsize, def='''')

    copy Unicode utf-8 string from uplink buffer

    Similar to dde_rwstr(), but does a 1:1 copy (instead of utf-32 from utf-8 mapping).
    str : wstr
    fsize : s32
    dde_rcstr(out str, fsize, def="")

    read 8bit ANSI string of any custom codepage from uplink buffer

    Same as dde_rastr(), but not limited to glyphs of Unicode or any standard codepage anymore.
    str : cstr
    fsize : s32

    DDE WRITE

    Use these steps to write values into an upward container::
  • dde_wbegin(...) - prepare for writing
  • dde_wxxx(...) - write values
  • ...
  • dde_wend() - end writing, flag for transmission
  • dde_wbegin(cid)
    dde_wend(stamp=0)
    stamp : s32 - for histdata only; optional; seconds since 31.12.1999 0:00
    Defaults to "now" if not given (or set to 0)
    returns : s32
    0 = ok
    <0 = error
    >0 = ok, stamp assigned to recording (applies to histdata containers only)
    dde_wu8(ival)
    ival : u8
    dde_wu16(ival)
    ival : u16
    dde_wu32(ival)
    ival : u32
    dde_ws8(ival)
    ival : s8
    dde_ws16(ival)
    ival : s16
    dde_ws32(ival)
    ival : s32
    dde_ws64(ival)
    ival : s64
    dde_wstamp32(stamp)
    stamp : stamp32
    dde_wstamp40(stamp)
    stamp : stamp40
    dde_wf16(fval)
    fval : f16
    dde_wf32(fval)
    fval : f32
    dde_wf64(fval)
    fval : f64
    dde_wbin(val, len)
    val[] : u8 - input buffer with at least
    len bytes size
    len : s32 - number of bytes to write
    dde_wastr(str, fsize)

    write CP-1252 ANSI string to uplink buffer as 8bit ANSI.

    Considers optional terminating zero, remainig bytes are filled up with zero.
    Supports flexible length containers (up+, down+) if specified as last field.
    str : astr - source buffer /w optional terminating zero
    fsize : s32 - size [bytes] of target field - e.g. max. number of bytes to write
    dde_wnstr(str, fsize)

    write CP-1252 ANSI string to uplink buffer as Unicode utf-8.

    Same as dde_wastr(), but maps CP-1252 ANSI string to Unicode utf-8.
    str : nstr
    fsize : s32 onUplinkReady
    dde_wwstr(str, fsize)

    write unpacked Unicode utf-32 string to uplink buffer as Unicode utf-8.

    Considers optional terminating zero, remainig bytes are filled up with zero.
    Supports flexible length containers (up+, down+) if specified as last field.
    str : wstr - source buffer /w optional terminating zero
    fsize : s32 - size [bytes] of target field - e.g. max. number of bytes to write
    dde_wustr(str, fsize)

    copy Unicode utf-8 string to uplink buffer

    Similar to dde_wwstr(), but does a 1:1 copy (instead of utf-32 to utf-8 mapping).
    str : ustr
    fsize : s32
    dde_wcstr(str, fsize)

    write 8bit ANSI string of any custom codepage to uplink buffer

    Same as dde_wastr(), but not limited to glyphs of Unicode or any standard codepage anymore.
    str : cstr
    fsize : s32

    DDE ALERT

    see tutorial alerts:
    DDE_alerts_overflow(isAlarm, cid, field, fValue, fThreshold)

    shorthand for DDE_alerts_write( DDE_alerts_OVERFLOW_x,...)

    isAlarm : bool - true=alarm, false=warning
    cid : DDE_xxx_id - id of *histdata*-stream which raises this alert
    field : s32 - index of field which raises this alert, e.g. 0 = the first field in the given container, 1= the next field
    fValue : f32 - current value; float number or F32_SC/F32_UF/F32_OF/F32_OL
    fThreshold : f32 - threshold which raises this alert
    DDE_alerts_underflow(isAlarm, cid, field, fValue, fThreshold)

    shorthand for DDE_alerts_write( DDE_alerts_UNDERFLOW_x,...)

    See DDE_alerts_overflow for parameters.
    DDE_alerts_fault(isAlarm, cid, field)

    shorthand for DDE_alerts_write( DDE_alerts_FAULT_x,...)

    See DDE_alerts_overflow for parameters.
    DDE_alerts_clear(cid, field)

    shorthand for DDE_alerts_write( DDE_alerts_CLEAR,...)

    See DDE_alerts_overflow for parameters.
    DDE_alerts_write(signal, cid, field, Float:fValue, Float:fThreshold)
    Avoid to use this method directly - use DDE_alerts_overflow(), DDE_alerts_underflow() or DDE_alerts_fault() instead!
    signal : s32
    DDE_alerts_CLEAR = 0 - clear all alarm/warning conditions
    DDE_alerts_OVERFLOW_WARN = 0b00000001 - overflow warning
    DDE_alerts_OVERFLOW_ALARM = 0b00000010 - overflow alarm
    DDE_alerts_UNDERFLOW_WARN = 0b10000001 - underflow warning
    DDE_alerts_UNDERFLOW_ALARM = 0b10000010 - underflow alarm
    DDE_alerts_FAULT_WARN = 0b00000100 - technical fault warning
    DDE_alerts_FAULT_ALARM = 0b00001000 - technical fault alarm
    cid - see DDE_alerts_overflow
    field - see DDE_alerts_overflow
    fValue
  • DDE_alerts_SIGNAL_TFx - only F32_SC/F32_UF/F32_OF/F32_OL allowed
  • others - see DDE_alerts_overflow
  • fThreshold - see DDE_alerts_overflow
  • DDE_alerts_SIGNAL_TFx - only 0.0 allowed
  • others - see DDE_alerts_overflow
  • DDE APPLOG

    #applog:

    The #applog container provides a standardized mechanism to log major applicative events as a time series and represent them at the backend's administration portal without any further coding.

    Add these lines to dde/main.dde to enable the #applog container:

    #applog // enable the applog container #define APPLOG_TO_CONSOLE 1 // optionally activate automatic console output

    Trigger an applog from dlo/** like that:

    applog( "my.msg", "a=%d;b=%d", a, b); // regular log level applog_debug( "my.dbg", "a=%d;b=%d", a, b); // debug applog_ok( "my.okmsg", "a=%d;b=%d", a, b); // ok applog_warning( "my.warn", "a=%d;b=%d", a, b); // warning applog_alarm( "my.alarm", "a=%d;b=%d", a, b); // alarm

    In certain cases this alternative syntax may be usefull:

    applog( "~my.dbg", "a=%d;b=%d", a, b); // debug applog( "$my.okmsg", "a=%d;b=%d", a, b); // ok applog( "?my.warn", "a=%d;b=%d", a, b); // warning applog( "!my.alarm", "a=%d;b=%d", a, b); // alarm
    APPLOG_TO_CONSOLE -

    #log a copy of every applog() recording to the console

    This definition must be set in dde/main.dde:
    #define APPLOG_TO_CONSOLE 1
    #applog
    applog_ok(code, params, ?values...)
    Same as applog(), but sets priority to ok ("$").
    #applog
    applog_debug(code, params, ?values...)
    Same as applog(), but sets priority to debug ("~").
    #applog
    applog_warning(code, params, ?values...)
    Same as applog(), but sets priority to warning ("?").
    #applog
    applog_alarm(code, params, ?values...)
    Same as applog(), but sets priority to alarm ("!").
    #applog
    applog(prio_code, params, ?values...)
    prio_code : astr[16] - First character represents the priority (optional), followed by the event code.
    Priority values:
    default - (e.g.
    space or omitted) regular level, purely informative. The application passed some major point.
    '~' = debug - diagnostic information that may be needed for troubleshooting.
    '$' = ok - some important user/control action executed succcessfully
    '?' = warning - indicates unusual or noteable runtime conditions, which can be handled by the application without significant loss of functionality.
    '!' = alarm/error - some critical condition appeared that happens to halt a specific operation or part of the application's functionality, but not the overall application.
    '§' = fatal error - some real catastropy occured from which the application cannot recover anymore.
    Any fatal error will automatically halt the application and the runtime environment will try to reboot the device (similar to #log("§...").Therefore the applog() function will never return in case of a "§"!
    Event code
  • Limited to 15 characters.
  • It's recommended to apply some structure using '.' as delimiter; e.g. "my.fancy.code"
  • params : astr[100] - Semicolon (';') seperated params, classic printf formatting can be used (e.g. "myValue=%d", myValue)
    values - any value cited by the params string
    applog_debug(), applog_ok(), applog_warning(), applog_alarm()
    #applog

    DDE ALOHA

    DDE_ALOHA_DBG -

    set it to 1 to enable aloha debug output

    aloha:
    1. Aloha is enabled by declaring the #aloha container in the DDE
    2. The aloha container should not exceed 10 channels, not to overwhelm the portal view
    3. Aloha is triggered by calling alohaStart()
    4. Then the backend periodically requests aloha data (typ. every 3s, backend global setting)
    5. The application must provide aloha data upon request → onAlohaEvent( ALOHA_EV_CAPTURE), DDE_aloha_write();
    6. Aloha operation ends either
      • automatically after time chosen with alohaStart(), or
      • manually due to alohaStop()
    Each aloha operation cycles through certain states
    which are signalled by onAlohaEvent()
    1. alohaStart() triggered by application
      ALOHA_EV_STATE_STARTING
    2. connection with backend established
      ALOHA_EV_STATE_RUNNING
    3. hold time (given with alohaStart()) expired
      ALOHA_EV_STATE_STOPPING
    4. end of aloha confirmed by backend
      ALOHA_EV_STATE_OFF
    Basic example
    #aloha up temp f32.1 units="°C" ubat u16 units="mV"
    // trigger source may be a button press onAlohaTriggered() { alohaStart( 300); // start aloha and hold it for 300 seconds uplinkFlush(); // onAlohaEvent() has to take care about further handling } captureAloha() { new o[DDE_aloha]; // !!! replace constant values with capture function !!! o.temp= 17.1; o.ubat= 3600; DDE_aloha_write( o); // ignore any error } public onAlohaEvent( ev) { if (ev == ALOHA_EV_CAPTURE) captureAloha(); }
    Add aloha status and error signalling
    public onAlohaEvent( ev) { #log( "aloha %s", alohaEventStrings[ev]); switch( ev) { case ALOHA_EV_CAPTURE: captureAloha(); case ALOHA_EV_STATE_OFF: #watch( "alohaState=off %s", alohaErrorStrings[alohaLastError()]); case ALOHA_EV_STATE_STARTING: #watch( "alohaState=starting..."); case ALOHA_EV_STATE_RUNNING: #watch( "alohaState=BUSY"); case ALOHA_EV_STATE_STOPPING: #watch( "alohaState=stopping..."); } }
    User abort of aloha
    // trigger source may be another button press onAlohaStopTriggered() { alohaStop(); // onAlohaEvent() signals stopping process. // it may take up to approx. 30s until ALOHA_EV_STATE_OFF }
    alohaStart(runSecs)

    start aloha operation

    This prolongues any already active aloha operation.
    At least onAlohaEvent( ALOHA_EV_CAPTURE) must be declared by your application.
    alohaStart() should be followed by uplinkFlush() /w optional RM2M_TX_SUPPRESS_POSUPDATE flag for performance reasons.
    Or take rM2M_TxStart() instead if not using the ~uplink library.
    runSecs : s32 - seconds to hold the aloha mode in state ALOHA_EV_STATE_RUNNING
    onAlohaEvent(ev) - process notifications issued by the aloha engine
    At least ALOHA_EV_CAPTURE must be handled!
    ev : s32
    ALOHA_EV_CAPTURE - capture aloha data and hand it over to the backend using DDE_aloha_write().
    Alternatively use alohaWriteBuf() to handover binary raw data.
    State transision events
    ALOHA_EV_STATE_STARTING - alohaStart() has been called, device is waiting for backend to start aloha communication
    ALOHA_EV_STATE_RUNNING - backend has started aloha communication
    ALOHA_EV_STATE_STOPPING - device or backend asked to stop aloha
    ALOHA_EV_STATE_OFF - aloha just ended, see alohaLastError() if you are interessted in error signalling
    alohaStop()

    end the current aloha operation as soon as possible, instead of waiting for expiration of hold time set by alohaInit()

    This is silently ignored, if there is no aloha operation active.
    alohaEventStrings[]:string -

    translate onAlohaEvent() parameter into readable string

    alohaErrorStrings[]:string -

    translate alohaLastError() result into readable string

    alohaLastError()

    get error information of recent aloha operation

    Updates on every ALOHA_EV_STATE_OFF.
    returns : s32
    ALOHA_ERR_OK - no problems, regularly off after aloha runtime is over or user abort
    ALOHA_ERR_STARTTIMEOUT - uplink connection not established during starting phase
    ALOHA_ERR_SIMCOLD - uplink is cold, can not establish uplink connection
    ALOHA_ERR_UPLINK - any other permament uplink error exists - ask rM2M_TxGetStatus() for details
    alohaWriteBuf(buf, bytes, _bufCells=sizeof buf)

    handover aloha data for transmission to backend

    This is the bloody way which takes raw binary data. It's recommended to use DDE_aloha_write() instead as a smart alternative.
    buf[] : u8 - raw data to be sent
    bytes : s32 - number of bytes in buf to be sent
    alohaTimeRemaining(includeStopTime=true)

    get number of seconds the current aloha will last

    includeStopTime : bool
    true - result refers to next ALOHA_EV_STATE_OFF
    false - result refers to next ALOHA_EV_STATE_STOPPING
    returns : s32 - [seconds]
    0 = no aloha active
    >0 = seconds until aloha will reach state acc. to includeStopTime