cmacroscontikicoojaprotothread

Understanding Macro behavior and protothreads


Thanks in advance for the help.

First a preface. I have been looking at using the Contiki TSCH implementation given at https://github.com/contiki-os/contiki/tree/master/core/net/mac/tsch. While running a simple example in the Cooja simulator (with a few log messages that I have added to the base code so I can see what's going on) I noticed that the ASN counter was not incrementing its most significant byte.

Specifically, the ASN (absolute slot number for TSCH) is given by the struct

// data type of absolute slot number
struct tsch_asn_t {
  uint32_t ls4b; /* least significant 4 bytes */
  uint8_t  ms1b; /* most significant 1 byte */
};

and can essentially be thought of as an index value represented as two variables, the most significant byte and least significant 4 bytes. The following macro is used to increment an ASN by a set amount.

// Here is the macro
#define TSCH_ASN_INC(asn, inc) do { \
    printf("TSCH INC1: new UNDEF, old %u, inc %u\n", (asn).ls4b, inc);  \
\
    uint32_t new_ls4b = (asn).ls4b + (inc); \
\
    printf("TSCH INC2: new %u, old %u, inc %u\n",new_ls4b, (asn).ls4b, inc);  \
\
    if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \
\
    printf("TSCH INC3: new %u, old %u, inc %u\n",new_ls4b, (asn).ls4b, inc);  \
\
    (asn).ls4b = new_ls4b; \
\
    printf("TSCH INC4: new %u, old %u, inc %u\n",new_ls4b, (asn).ls4b, inc);  \
} while(0);

For the moment ignore the printf statements (I have added these to try to understand what is going on). As I understand this macro, what happens is the the least significant bytes are incremented first. Then, if the least significant bytes wrap around the most significant byte is then incremented. When looking at the log of what was happening though, I noticed that the most significant byte was not being incremented when the least significant bytes wrapped around.

Now to my actual question. To identify why the most significant byte was not being incremented I added the above print statements to the macro and added print statements above and below the actual macro call as seen below (note the ASN is given by tsch_current_asn, and timeslot_diff is the amount I want to increment the ASN by).

printf("TSCH INC BEFORE: ms1b %u, ls4b %u, inc %u\n",tsch_current_asn.ms1b, tsch_current_asn.ls4b, timeslot_diff);
TSCH_ASN_INC(tsch_current_asn, timeslot_diff);
printf("TSCH INC AFTER: ms1b %u, ls4b %u, inc %u\n",tsch_current_asn.ms1b, tsch_current_asn.ls4b, timeslot_diff);

Doing this produced the following log that is absolutely stumping me

// LOG
TIME        DEVID   LOG MSG
00:28.885   ID:1    TSCH INC BEFORE: ms1b 0, ls4b 1877, inc 0
00:28.888   ID:1    TSCH INC1: new UNDEF, old 1877, inc 0
00:28.891   ID:1    TSCH INC2: new 1878, old 0, inc 1877
00:28.895   ID:1    TSCH INC3: new 1878, old 0, inc 1877
00:28.898   ID:1    TSCH INC4: new 1878, old 0, inc 1878
00:28.901   ID:1    TSCH INC AFTER: ms1b 0, ls4b 1878, inc 0

Specifically, it appears that in between the first and second printf statement in the macro inc (the timeslot_diff) changed from 0 to 1877. In other words it appears to me that the statement

uint32_t new_ls4b = (asn).ls4b + (inc); \

changed the value of inc (the timeslot_diff). Moreover this statement appears to me to change ans.ls4b (tsch_current_asn.ls4b) from 1877 to 0.

Am I having a senior moment so to speak in regards to how macros work or is this an effect of Contiki's protothreads (i.e. being suspended and later resumed)?

For reference, the actual code for the macro call is given on line 1035 of https://github.com/contiki-os/contiki/blob/master/core/net/mac/tsch/tsch-slot-operation.c and the macro is given on line 67 of https://github.com/contiki-os/contiki/blob/master/core/net/mac/tsch/tsch-asn.h.


Solution

  • It looks like mismatch between printf specifiers and actual argument types happening on 16-bit architecture. It is recommended to use specifiers defined as format macro constants in inttypes.h for all integer types coming from stdint.h

    I.e. when x is of type uint32_t you shall use

    printf("x is %"PRIu32" \n", x);
    

    instead of

    printf("x is %u \n", x);