Repository: canboat/canboat
Pull request #527: WIP, POC allow the camel name to be specified
Author: login: sbender9
Created: 2025-05-01T14:15:41Z | Merged: 2025-05-26T18:37:31Z

POC to see the best way to allow the camel name to be specified

See #526

Need to deal with -upper-camel properly


Diff:
diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c
index 7083cf3a..74a24072 100644
--- a/analyzer/analyzer.c
+++ b/analyzer/analyzer.c
@@ -86,6 +86,7 @@ bool       showJsonEmpty = false;
 bool       showJsonValue = false;
 bool       showVersion   = true;
 bool       showSI        = false; // Output everything in strict SI units
+bool       showCamel     = false;
 GeoFormats showGeo       = GEO_DD;
 
 char *sep = " ";
@@ -181,6 +182,7 @@ int main(int argc, char **argv)
     }
     else if (strcasecmp(av[1], "-camel") == 0)
     {
+      showCamel = true;
       camelCase(false);
     }
     else if (strcasecmp(av[1], "-upper-camel") == 0)
@@ -1241,7 +1243,16 @@ extern bool printFields(const Pgn *pgn, const uint8_t *data, int length, bool sh
       break;
     }
 
-    strcpy(fieldName, field->camelName ? field->camelName : field->name);
+    if ( showCamel )
+    {
+      strcpy(fieldName, field->camelName ? field->camelName : field->name);
+    }
+    else
+    {
+      strcpy(fieldName, field->name);
+    }
+
+    
     if (repetition >= 1 && !showJson)
     {
       strcat(fieldName, field->camelName ? "_" : " ");
diff --git a/analyzer/pgn.c b/analyzer/pgn.c
index 3802c7a6..7e6f72c0 100644
--- a/analyzer/pgn.c
+++ b/analyzer/pgn.c
@@ -311,7 +311,16 @@ void camelCase(bool upperCamelCase)
     {
       const char *name = pgnList[i].fieldList[j].name;
 
-      pgnList[i].fieldList[j].camelName = camelize(name, upperCamelCase, haveEarlierSpareOrReserved ? j + 1 : 0);
+      if (pgnList[i].fieldList[j].camelName == NULL)
+      {
+        pgnList[i].fieldList[j].camelName = camelize(name, upperCamelCase, haveEarlierSpareOrReserved ? j + 1 : 0);
+      }
+      else if (upperCamelCase)
+      {
+        pgnList[i].fieldList[j].camelName
+            = camelize(pgnList[i].fieldList[j].camelName, upperCamelCase, haveEarlierSpareOrReserved ? j + 1 : 0);
+      }
+
       if (strcmp(name, "Reserved") == 0 || strcmp(name, "Spare") == 0)
       {
         haveEarlierSpareOrReserved = true;
diff --git a/analyzer/pgn.h b/analyzer/pgn.h
index fafcd0c1..6f7d0fd0 100644
--- a/analyzer/pgn.h
+++ b/analyzer/pgn.h
@@ -119,6 +119,12 @@ typedef struct
 
 #define END_OF_FIELDS {0}
 
+#define PRIMARY_KEY(nam) nam, .partOfPrimaryKey = true
+#define PK(nam) DEFER(PRIMARY_KEY)(nam)
+
+#define CAMEL_NAME(camel, nam) nam, .camelName = camel
+#define CAMEL(camel, nam) DEFER(CAMEL_NAME)(camel, nam)
+
 #define LOOKUP_FIELD(nam, len, typ)       \
   {.name              = nam,              \
    .size              = len,              \
@@ -129,17 +135,6 @@ typedef struct
    .lookup.name       = xstr(typ),        \
    .fieldType         = "LOOKUP"}
 
-#define LOOKUP_PRIMARY_KEY_FIELD(nam, len, typ) \
-  {.name              = nam,                    \
-   .size              = len,                    \
-   .resolution        = 1,                      \
-   .hasSign           = false,                  \
-   .partOfPrimaryKey  = true,                   \
-   .lookup.type       = LOOKUP_TYPE_PAIR,       \
-   LOOKUP_PAIR_MEMBER = lookup##typ,            \
-   .lookup.name       = xstr(typ),              \
-   .fieldType         = "LOOKUP"}
-
 #define LOOKUP_DYNAMIC_FIELD_KEY(nam, len, typ)     \
   {.name                   = nam,                   \
    .size                   = len,                   \
@@ -570,24 +565,14 @@ typedef struct
 
 #define UINT8_DESC_FIELD(nam, desc) {.name = nam, .size = BYTES(1), .resolution = 1, .fieldType = "UINT8", .description = desc}
 
-#define UINT8_DESC_PRIMARY_KEY_FIELD(nam, desc) \
-  {.name = nam, .size = BYTES(1), .resolution = 1, .fieldType = "UINT8", .description = desc, .partOfPrimaryKey = true}
-
 #define FIELD_INDEX(nam, desc) {.name = nam, .size = BYTES(1), .resolution = 1, .fieldType = "FIELD_INDEX", .description = desc}
 
 #define UINT8_FIELD(nam) UINT8_DESC_FIELD(nam, NULL)
 
-#define UINT8_PRIMARY_KEY_FIELD(nam) UINT8_DESC_PRIMARY_KEY_FIELD(nam, NULL)
-
 #define UINT16_DESC_FIELD(nam, desc) {.name = nam, .size = BYTES(2), .resolution = 1, .fieldType = "UINT16", .description = desc}
 
-#define UINT16_PRIMARY_KEY_DESC_FIELD(nam, desc) \
-  {.name = nam, .size = BYTES(2), .resolution = 1, .fieldType = "UINT16", .description = desc, .partOfPrimaryKey = true}
-
 #define UINT16_FIELD(nam) UINT16_DESC_FIELD(nam, NULL)
 
-#define UINT16_PRIMARY_KEY_FIELD(nam) UINT16_PRIMARY_KEY_DESC_FIELD(nam, NULL)
-
 #define UINT32_DESC_FIELD(nam, desc) {.name = nam, .size = BYTES(4), .resolution = 1, .fieldType = "UINT32", .description = desc}
 
 #define UINT32_FIELD(nam) UINT32_DESC_FIELD(nam, NULL)
@@ -605,43 +590,14 @@ typedef struct
       .unit              = "=" xstr(id),      \
   }
 
-#define MATCH_LOOKUP_PRIMARY_KEY_FIELD(nam, len, id, typ) \
-  {                                                       \
-      .name              = nam,                           \
-      .size              = len,                           \
-      .resolution        = 1,                             \
-      .hasSign           = false,                         \
-      .partOfPrimaryKey  = true,                          \
-      .lookup.type       = LOOKUP_TYPE_PAIR,              \
-      LOOKUP_PAIR_MEMBER = lookup##typ,                   \
-      .lookup.name       = xstr(typ),                     \
-      .fieldType         = "LOOKUP",                      \
-      .unit              = "=" xstr(id),                  \
-  }
-
 #define MATCH_FIELD(nam, len, id, desc) \
   {.name = nam, .size = len, .resolution = 1, .unit = "=" xstr(id), .description = desc, .fieldType = "UNSIGNED_INTEGER"}
 
-#define MATCH_PRIMARY_KEY_FIELD(nam, len, id, desc) \
-  {.name             = nam,                         \
-   .size             = len,                         \
-   .resolution       = 1,                           \
-   .unit             = "=" xstr(id),                \
-   .description      = desc,                        \
-   .partOfPrimaryKey = true,                        \
-   .fieldType        = "UNSIGNED_INTEGER"}
-
 #define SIMPLE_DESC_FIELD(nam, len, desc) \
   {.name = nam, .size = len, .resolution = 1, .description = desc, .fieldType = "UNSIGNED_INTEGER"}
 
-#define SIMPLE_DESC_PRIMARY_KEY_FIELD(nam, len, desc) \
-  {.name = nam, .size = len, .resolution = 1, .description = desc, .partOfPrimaryKey = true, .fieldType = "UNSIGNED_INTEGER"}
-
 #define SIMPLE_FIELD(nam, len) {.name = nam, .size = len, .resolution = 1, .fieldType = "UNSIGNED_INTEGER"}
 
-#define SIMPLE_PRIMARY_KEY_FIELD(nam, len) \
-  {.name = nam, .size = len, .resolution = 1, .partOfPrimaryKey = true, .fieldType = "UNSIGNED_INTEGER"}
-
 #define SIMPLE_SIGNED_FIELD(nam, len) {.name = nam, .size = len, .resolution = 1, .hasSign = true, .fieldType = "INTEGER"}
 
 #define MMSI_FIELD(nam)           \
@@ -662,17 +618,12 @@ typedef struct
 #define STRING_FIX_DESC_FIELD(nam, len, desc) \
   {.name = nam, .size = len, .resolution = 0, .description = desc, .fieldType = "STRING_FIX"}
 
-#define STRING_FIX_DESC_PRIMARY_KEY_FIELD(nam, len, desc) \
-  {.name = nam, .size = len, .resolution = 0, .description = desc, .partOfPrimaryKey = true, .fieldType = "STRING_FIX"}
-
 #define STRINGVAR_FIELD(nam) {.name = nam, .size = LEN_VARIABLE, .resolution = 0, .fieldType = "STRING_LZ"}
 
 #define STRINGLAU_FIELD(nam) {.name = nam, .size = LEN_VARIABLE, .resolution = 0, .fieldType = "STRING_LAU"}
 
 #define STRING_FIX_FIELD(nam, len) STRING_FIX_DESC_FIELD(nam, len, NULL)
 
-#define STRING_FIX_PRIMARY_KEY_FIELD(nam, len) STRING_FIX_DESC_PRIMARY_KEY_FIELD(nam, len, NULL)
-
 #define TEMPERATURE_HIGH_FIELD(nam) {.name = nam, .size = BYTES(2), .resolution = 0.1, .unit = "K", .fieldType = "TEMPERATURE_HIGH"}
 
 #define TEMPERATURE_FIELD(nam) {.name = nam, .size = BYTES(2), .resolution = 0.01, .unit = "K", .fieldType = "TEMPERATURE"}
@@ -1050,7 +1001,7 @@ Pgn pgnList[] = {
      0xe800,
      PACKET_INCOMPLETE,
      PACKET_SINGLE,
-     {BINARY_FIELD("Data", BYTES(8), NULL), END_OF_FIELDS},
+     {BINARY_FIELD(CAMEL("data", "Data"), BYTES(8), NULL), END_OF_FIELDS},
      .fallback    = true,
      .explanation = "Standardized PGNs in PDU1 (addressed) single-frame PGN range 0xE800 to "
                     "0xEE00 (59392 - 60928). "
@@ -1216,12 +1167,12 @@ Pgn pgnList[] = {
      PACKET_SINGLE,
      {SIMPLE_DESC_FIELD("Unique Number", 21, "ISO Identity Number"),
       MANUFACTURER_FIELD(NULL, NULL, false),
-      SIMPLE_DESC_PRIMARY_KEY_FIELD("Device Instance Lower", 3, "ISO ECU Instance"),
-      SIMPLE_DESC_PRIMARY_KEY_FIELD("Device Instance Upper", 5, "ISO Function Instance"),
+      SIMPLE_DESC_FIELD(PK("Device Instance Lower"), 3, "ISO ECU Instance"),
+      SIMPLE_DESC_FIELD(PK("Device Instance Upper"), 5, "ISO Function Instance"),
       LOOKUP_TRIPLET_FIELD("Device Function", BYTES(1), DEVICE_FUNCTION, "ISO Function", 7 /*Device Class*/),
       SPARE_FIELD(1),
       LOOKUP_FIELD("Device Class", 7, DEVICE_CLASS),
-      SIMPLE_DESC_PRIMARY_KEY_FIELD("System Instance", 4, "ISO Device Class Instance"),
+      SIMPLE_DESC_FIELD(PK("System Instance"), 4, "ISO Device Class Instance"),
       LOOKUP_FIELD("Industry Group", 3, INDUSTRY_CODE),
       // "Arbitrary address capable" is explained at
       // https://embeddedflakes.com/network-management-in-sae-j1939/#Arbitrary_Address_Capable
@@ -1260,7 +1211,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_SINGLE,
      {COMPANY(1851),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 1, "Wireless Keypad Light Control"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(1), 1, "Wireless Keypad Light Control"),
       UINT8_FIELD("Variant"),
       UINT8_FIELD("Wireless Setting"),
       UINT8_FIELD("Wired Setting"),
@@ -1273,7 +1224,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_SINGLE,
      {COMPANY(1851),
-      UINT8_PRIMARY_KEY_FIELD("PID"),
+      UINT8_FIELD(PK("PID")),
       UINT8_FIELD("Variant"),
       UINT8_FIELD("Beep Control"),
       RESERVED_FIELD(BYTES(3)),
@@ -1628,12 +1579,12 @@ Pgn pgnList[] = {
      PACKET_ISO_TP,
      {BINARY_FIELD("Unique Number", 21, "ISO Identity Number"),
       MANUFACTURER_FIELD("Manufacturer Code", NULL, false),
-      SIMPLE_DESC_PRIMARY_KEY_FIELD("Device Instance Lower", 3, "ISO ECU Instance"),
-      SIMPLE_DESC_PRIMARY_KEY_FIELD("Device Instance Upper", 5, "ISO Function Instance"),
+      SIMPLE_DESC_FIELD(PK("Device Instance Lower"), 3, "ISO ECU Instance"),
+      SIMPLE_DESC_FIELD(PK("Device Instance Upper"), 5, "ISO Function Instance"),
       LOOKUP_TRIPLET_FIELD("Device Function", BYTES(1), DEVICE_FUNCTION, "ISO Function", 7 /*Device Class*/),
       RESERVED_FIELD(1),
       LOOKUP_FIELD("Device Class", 7, DEVICE_CLASS),
-      SIMPLE_DESC_PRIMARY_KEY_FIELD("System Instance", 4, "ISO Device Class Instance"),
+      SIMPLE_DESC_FIELD(PK("System Instance"), 4, "ISO Device Class Instance"),
       LOOKUP_FIELD("Industry Code", 3, INDUSTRY_CODE),
       RESERVED_FIELD(1),
       UINT8_FIELD("New Source Address"),
@@ -1670,7 +1621,7 @@ Pgn pgnList[] = {
      PACKET_COMPLETE,
      PACKET_SINGLE,
      {COMPANY(137),
-      UINT8_PRIMARY_KEY_FIELD("Bank Instance"),
+      UINT8_FIELD(PK("Bank Instance")),
       UINT8_FIELD("Indicator Number"),
       CURRENT_UFIX16_DA_FIELD("Breaker Current"),
       RESERVED_FIELD(BYTES(2)),
@@ -1992,7 +1943,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_SINGLE,
      {COMPANY(1851),
-      UINT8_PRIMARY_KEY_FIELD("Proprietary ID"),
+      UINT8_FIELD(PK("Proprietary ID")),
       UINT8_FIELD("First key"),
       UINT8_FIELD("Second key"),
       SIMPLE_FIELD("First key state", 2),
@@ -2008,7 +1959,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_SINGLE,
      {COMPANY(1851),
-      UINT8_PRIMARY_KEY_FIELD("Proprietary ID"),
+      UINT8_FIELD(PK("Proprietary ID")),
       UINT8_FIELD("Variant"),
       UINT8_FIELD("Status"),
       RESERVED_FIELD(BYTES(3)),
@@ -2322,7 +2273,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(1851),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(2), 33264, "0x81f0"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(2), 33264, "0x81f0"),
       MATCH_FIELD("command", BYTES(1), 132, "0x84"),
       BINARY_FIELD("Unknown 1", BYTES(3), NULL),
       LOOKUP_FIELD("Pilot Mode", BYTES(1), SEATALK_PILOT_MODE),
@@ -2337,7 +2288,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(419),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 3, "Media Control"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(1), 3, "Media Control"),
       UINT8_FIELD("Unknown"),
       UINT8_FIELD("Source ID"),
       LOOKUP_FIELD("Command", BYTES(1), FUSION_COMMAND),
@@ -2349,7 +2300,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(419),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 30, "Sirius Control"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(1), 30, "Sirius Control"),
       UINT8_FIELD("Unknown"),
       UINT8_FIELD("Source ID"),
       LOOKUP_FIELD("Command", BYTES(1), FUSION_SIRIUS_COMMAND),
@@ -2416,7 +2367,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(1851),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(2), 33264, "0x81f0"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(2), 33264, "0x81f0"),
       MATCH_FIELD("command", BYTES(1), 134, "0x86"),
       UINT8_FIELD("device"),
       LOOKUP_FIELD("key", BYTES(1), SEATALK_KEYSTROKE),
@@ -2432,7 +2383,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(1851),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(2), 33264, "0x81f0"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(2), 33264, "0x81f0"),
       MATCH_FIELD("command", BYTES(1), 144, "0x90"),
       RESERVED_FIELD(BYTES(1)),
       LOOKUP_FIELD("device", BYTES(1), SEATALK_DEVICE_ID),
@@ -2444,7 +2395,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(1851),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(2), 3212, "0x0c8c"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(2), 3212, "0x0c8c"),
       LOOKUP_FIELD("Group", BYTES(1), SEATALK_NETWORK_GROUP),
       BINARY_FIELD("Unknown 1", BYTES(1), NULL),
       MATCH_FIELD("Command", BYTES(1), 0, "Brightness"),
@@ -2458,7 +2409,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(1851),
-      MATCH_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(2), 3212, "0x0c8c"),
+      MATCH_FIELD(PK("Proprietary ID"), BYTES(2), 3212, "0x0c8c"),
       LOOKUP_FIELD("Group", BYTES(1), SEATALK_NETWORK_GROUP),
       BINARY_FIELD("Unknown 1", BYTES(1), NULL),
       MATCH_FIELD("Command", BYTES(1), 1, "Color"),
@@ -2568,7 +2519,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(135),
       MATCH_LOOKUP_FIELD("Proprietary ID", BYTES(1), 42, AIRMAR_COMMAND),
-      LOOKUP_PRIMARY_KEY_FIELD("Temperature instance", 2, AIRMAR_TEMPERATURE_INSTANCE),
+      LOOKUP_FIELD(PK("Temperature instance"), 2, AIRMAR_TEMPERATURE_INSTANCE),
       RESERVED_FIELD(6),
       TEMPERATURE_DELTA_FIX16_FIELD("Temperature offset", "actual range is -9.999 to +9.999 K"),
       END_OF_FIELDS},
@@ -2655,7 +2606,7 @@ Pgn pgnList[] = {
      126720,
      PACKET_INCOMPLETE,
      PACKET_FAST,
-     {COMPANY(135), UINT8_PRIMARY_KEY_FIELD("Proprietary ID"), END_OF_FIELDS}}
+     {COMPANY(135), UINT8_FIELD(PK("Proprietary ID")), END_OF_FIELDS}}
 
     ,
     {"Maretron: Slave Response",
@@ -2740,7 +2691,7 @@ Pgn pgnList[] = {
       UINT8_FIELD("Alert Sub-System"),
       UINT16_FIELD("Alert ID"),
       ISO_NAME_FIELD("Data Source Network ID NAME"),
-      UINT8_PRIMARY_KEY_FIELD("Data Source Instance"),
+      UINT8_FIELD(PK("Data Source Instance")),
       UINT8_FIELD("Data Source Index-Source"),
       UINT8_FIELD("Alert Occurrence Number"),
       LOOKUP_FIELD("Temporary Silence Status", 1, YES_NO),
@@ -2768,7 +2719,7 @@ Pgn pgnList[] = {
       UINT8_FIELD("Alert Sub-System"),
       UINT16_FIELD("Alert ID"),
       ISO_NAME_FIELD("Data Source Network ID NAME"),
-      UINT8_PRIMARY_KEY_FIELD("Data Source Instance"),
+      UINT8_FIELD(PK("Data Source Instance")),
       UINT8_FIELD("Data Source Index-Source"),
       UINT8_FIELD("Alert Occurrence Number"),
       ISO_NAME_FIELD("Acknowledge Source Network ID NAME"),
@@ -2787,7 +2738,7 @@ Pgn pgnList[] = {
       UINT8_FIELD("Alert Sub-System"),
       UINT16_FIELD("Alert ID"),
       ISO_NAME_FIELD("Data Source Network ID NAME"),
-      UINT8_PRIMARY_KEY_FIELD("Data Source Instance"),
+      UINT8_FIELD(PK("Data Source Instance")),
       UINT8_FIELD("Data Source Index-Source"),
       UINT8_FIELD("Alert Occurrence Number"),
       LOOKUP_FIELD("Language ID", BYTES(1), ALERT_LANGUAGE_ID),
@@ -2806,7 +2757,7 @@ Pgn pgnList[] = {
       UINT8_FIELD("Alert Sub-System"),
       UINT16_FIELD("Alert ID"),
       ISO_NAME_FIELD("Data Source Network ID NAME"),
-      UINT8_PRIMARY_KEY_FIELD("Data Source Instance"),
+      UINT8_FIELD(PK("Data Source Instance")),
       UINT8_FIELD("Data Source Index-Source"),
       UINT8_FIELD("Alert Occurrence Number"),
       /* Unknown field lengths past this point, except Alert Control is likely 2 bits */
@@ -2829,7 +2780,7 @@ Pgn pgnList[] = {
       UINT8_FIELD("Alert Sub-System"),
       UINT16_FIELD("Alert ID"),
       ISO_NAME_FIELD("Data Source Network ID NAME"),
-      UINT8_PRIMARY_KEY_FIELD("Data Source Instance"),
+      UINT8_FIELD(PK("Data Source Instance")),
       UINT8_FIELD("Data Source Index-Source"),
       UINT8_FIELD("Alert Occurrence Number"),
       UINT8_DESC_FIELD("Number of Parameters", "Total Number of Threshold Parameters"),
@@ -2853,7 +2804,7 @@ Pgn pgnList[] = {
       UINT8_FIELD("Alert Sub-System"),
       UINT16_FIELD("Alert ID"),
       ISO_NAME_FIELD("Data Source Network ID NAME"),
-      UINT8_PRIMARY_KEY_FIELD("Data Source Instance"),
+      UINT8_FIELD(PK("Data Source Instance")),
       UINT8_FIELD("Data Source Index-Source"),
       UINT8_FIELD("Alert Occurrence Number"),
       UINT8_DESC_FIELD("Number of Parameters", "Total Number of Value Parameters"),
@@ -2875,7 +2826,7 @@ Pgn pgnList[] = {
                         BYTES(1),
                         "An upward counting number used to tie releated information together between different PGNs. For example "
                         "the SID would be used to tie together the COG, SOG and RAIM values to a given position."),
-      LOOKUP_PRIMARY_KEY_FIELD("Source", 4, SYSTEM_TIME),
+      LOOKUP_FIELD(PK("Source"), 4, SYSTEM_TIME),
       RESERVED_FIELD(4),
       DATE_FIELD("Date"),
       TIME_FIELD("Time"),
@@ -2928,11 +2879,11 @@ Pgn pgnList[] = {
      {VERSION_FIELD_DESC("NMEA 2000 Version",
                          "Binary number containing a decimal number of format AABBB, where AA is the major and BBB is the minor "
                          "release. The decimal point position is assumed."),
-      UINT16_PRIMARY_KEY_FIELD("Product Code"),
-      STRING_FIX_PRIMARY_KEY_FIELD("Model ID", BYTES(32)),
-      STRING_FIX_PRIMARY_KEY_FIELD("Software Version Code", BYTES(32)),
-      STRING_FIX_PRIMARY_KEY_FIELD("Model Version", BYTES(32)),
-      STRING_FIX_PRIMARY_KEY_FIELD("Model Serial Code", BYTES(32)),
+      UINT16_FIELD(PK("Product Code")),
+      STRING_FIX_FIELD(PK("Model ID"), BYTES(32)),
+      STRING_FIX_FIELD(PK("Software Version Code"), BYTES(32)),
+      STRING_FIX_FIELD(PK("Model Version"), BYTES(32)),
+      STRING_FIX_FIELD(PK("Model Serial Code"), BYTES(32)),
       LOOKUP_FIELD("Certification Level", BYTES(1), CERTIFICATION_LEVEL),
       SIMPLE_DESC_FIELD("Load Equivalency", BYTES(1), "Garantueed maximum power consumption, 50 mA per LEN"),
       END_OF_FIELDS},
@@ -3081,7 +3032,7 @@ Pgn pgnList[] = {
      127251,
      PACKET_COMPLETE,
      PACKET_SINGLE,
-     {UINT8_FIELD("SID"), ROTATION_FIX32_FIELD("Rate"), RESERVED_FIELD(BYTES(3)), END_OF_FIELDS},
+     {UINT8_FIELD(CAMEL("sid", "SID")), ROTATION_FIX32_FIELD(CAMEL("rate", "Rate")), RESERVED_FIELD(BYTES(3)), END_OF_FIELDS},
      .interval = 100,
      .priority = 2}
 
@@ -3133,7 +3084,7 @@ Pgn pgnList[] = {
      127488,
      PACKET_COMPLETE,
      PACKET_SINGLE,
-     {LOOKUP_PRIMARY_KEY_FIELD("Instance", BYTES(1), ENGINE_INSTANCE),
+     {LOOKUP_FIELD(PK("Instance"), BYTES(1), ENGINE_INSTANCE),
       ROTATION_UFIX16_RPM_FIELD("Speed", NULL),
       PRESSURE_UFIX16_HPA_FIELD("Boost Pressure"),
       PERCENTAGE_I8_FIELD("Tilt/Trim"),
@@ -3150,7 +3101,7 @@ Pgn pgnList[] = {
      127489,
      PACKET_COMPLETE,
      PACKET_FAST,
-     {LOOKUP_PRIMARY_KEY_FIELD("Instance", BYTES(1), ENGINE_INSTANCE),
+     {LOOKUP_FIELD(PK("Instance"), BYTES(1), ENGINE_INSTANCE),
       PRESSURE_UFIX16_HPA_FIELD("Oil pressure"),
       TEMPERATURE_HIGH_FIELD("Oil temperature"),
       TEMPERATURE_FIELD("Temperature"),
@@ -3173,7 +3124,7 @@ Pgn pgnList[] = {
      127490,
      PACKET_PDF_ONLY,
      PACKET_FAST,
-     {UINT8_PRIMARY_KEY_FIELD("Inverter/Motor Identifier"),
+     {UINT8_FIELD(PK("Inverter/Motor Identifier")),
       SIMPLE_FIELD("Operating Mode", 4),
       RESERVED_FIELD(4),
       TEMPERATURE_FIELD("Motor Temperature"),
@@ -3190,7 +3141,7 @@ Pgn pgnList[] = {
      127491,
      PACKET_PDF_ONLY,
      PACKET_FAST,
-     {UINT8_PRIMARY_KEY_FIELD("Energy Storage Identifier"),
+     {UINT8_FIELD(PK("Energy Storage Identifier")),
       PERCENTAGE_U8_FIELD("State of Charge"),
       DURATION_UFIX16_MIN_FIELD("Time Remaining", "Time remaining at current rate of discharge"),
       TEMPERATURE_FIELD("Highest Cell Temperature"),
@@ -3208,7 +3159,7 @@ Pgn pgnList[] = {
      127493,
      PACKET_COMPLETE,
      PACKET_SINGLE,
-     {LOOKUP_PRIMARY_KEY_FIELD("Instance", 8, ENGINE_INSTANCE),
+     {LOOKUP_FIELD(PK("Instance"), 8, ENGINE_INSTANCE),
       LOOKUP_FIELD("Transmission Gear", 2, GEAR_STATUS),
       RESERVED_FIELD(6),
       PRESSURE_UFIX16_HPA_FIELD("Oil pressure"),
@@ -3224,7 +3175,7 @@ Pgn pgnList[] = {
      127494,
      PACKET_PDF_ONLY,
      PACKET_FAST,
-     {UINT8_PRIMARY_KEY_FIELD("Inverter/Motor Identifier"),
+     {UINT8_FIELD(PK("Inverter/Motor Identifier")),
       SIMPLE_FIELD("Motor Type", 4),
       RESERVED_FIELD(4),
       VOLTAGE_U16_100MV_FIELD("Motor Voltage Rating"),
@@ -3245,7 +3196,7 @@ Pgn pgnList[] = {
      127495,
      PACKET_PDF_ONLY,
      PACKET_FAST,
-     {UINT8_PRIMARY_KEY_FIELD("Energy Storage Identifier"),
+     {UINT8_FIELD(PK("Energy Storage Identifier")),
       SIMPLE_FIELD("Motor Type", 4),
       RESERVED_FIELD(4),
       SIMPLE_FIELD("Storage Chemistry/Conversion", 8),
@@ -3283,7 +3234,7 @@ Pgn pgnList[] = {
      127497,
      PACKET_COMPLETE,
      PACKET_FAST,
-     {LOOKUP_PRIMARY_KEY_FIELD("Instance", BYTES(1), ENGINE_INSTANCE),
+     {LOOKUP_FIELD(PK("Instance"), BYTES(1), ENGINE_INSTANCE),
       VOLUME_UFIX16_L_FIELD("Trip Fuel Used"),
       VOLUMETRIC_FLOW_FIELD("Fuel Rate, Average"),
       VOLUMETRIC_FLOW_FIELD("Fuel Rate, Economy"),
@@ -3297,7 +3248,7 @@ Pgn pgnList[] = {
      127498,
      PACKET_COMPLETE,
      PACKET_FAST,
-     {LOOKUP_PRIMARY_KEY_FIELD("Instance", BYTES(1), ENGINE_INSTANCE),
+     {LOOKUP_FIELD(PK("Instance"), BYTES(1), ENGINE_INSTANCE),
       ROTATION_UFIX16_RPM_FIELD("Rated Engine Speed", NULL),
       STRINGLAU_FIELD("VIN"),
       STRINGLAU_FIELD("Software ID"),
@@ -3450,7 +3401,7 @@ Pgn pgnList[] = {
      127505,
      PACKET_COMPLETE,
      PACKET_SINGLE,
-     {SIMPLE_PRIMARY_KEY_FIELD("Instance", 4),
+     {SIMPLE_FIELD(PK("Instance"), 4),
       LOOKUP_FIELD("Type", 4, TANK_TYPE),
       PERCENTAGE_I16_FIELD("Level"),
       VOLUME_UFIX32_DL_FIELD("Capacity"),
@@ -3484,7 +3435,7 @@ Pgn pgnList[] = {
      PACKET_COMPLETE,
      PACKET_FAST,
      {INSTANCE_FIELD,
-      UINT8_PRIMARY_KEY_FIELD("Battery Instance"),
+      UINT8_FIELD(PK("Battery Instance")),
       LOOKUP_FIELD("Operating State", 4, CHARGER_STATE),
       LOOKUP_FIELD("Charge Mode", 4, CHARGER_MODE),
       LOOKUP_FIELD("Enabled", 2, OFF_ON),
@@ -3515,8 +3466,8 @@ Pgn pgnList[] = {
      PACKET_COMPLETE,
      PACKET_FAST,
      {INSTANCE_FIELD,
-      UINT8_PRIMARY_KEY_FIELD("AC Instance"),
-      UINT8_PRIMARY_KEY_FIELD("DC Instance"),
+      UINT8_FIELD(PK("AC Instance")),
+      UINT8_FIELD(PK("DC Instance")),
       LOOKUP_FIELD("Operating State", 4, INVERTER_STATE),
       LOOKUP_FIELD("Inverter Enable", 2, OFF_ON),
       RESERVED_FIELD(2),
@@ -3537,7 +3488,7 @@ Pgn pgnList[] = {
      PACKET_NOT_SEEN,
      PACKET_FAST,
      {INSTANCE_FIELD,
-      UINT8_PRIMARY_KEY_FIELD("Battery Instance"),
+      UINT8_FIELD(PK("Battery Instance")),
       LOOKUP_FIELD("Charger Enable/Disable", 2, OFF_ON),
       RESERVED_FIELD(6),
       PERCENTAGE_U8_FIELD("Charge Current Limit"),
@@ -3561,8 +3512,8 @@ Pgn pgnList[] = {
      PACKET_NOT_SEEN,
      PACKET_FAST,
      {INSTANCE_FIELD,
-      UINT8_PRIMARY_KEY_FIELD("AC Instance"),
-      UINT8_PRIMARY_KEY_FIELD("DC Instance"),
+      UINT8_FIELD(PK("AC Instance")),
+      UINT8_FIELD(PK("DC Instance")),
       LOOKUP_FIELD("Inverter Enable/Disable", 2, OFF_ON),
       LOOKUP_FIELD("Inverter Mode", 4, INVERTER_MODE),
       LOOKUP_FIELD("Load Sense Enable/Disable", 2, OFF_ON),
@@ -3578,7 +3529,7 @@ Pgn pgnList[] = {
      PACKET_NOT_SEEN,
      PACKET_FAST,
      {INSTANCE_FIELD,
-      UINT8_PRIMARY_KEY_FIELD("Generator Instance"),
+      UINT8_FIELD(PK("Generator Instance")),
       LOOKUP_FIELD("AGS Mode", BITS(4), AGS_MODE),
       RESERVED_FIELD(BITS(4)),
       END_OF_FIELDS},
@@ -3621,7 +3572,7 @@ Pgn pgnList[] = {
      PACKET_NOT_SEEN,
      PACKET_FAST,
      {INSTANCE_FIELD,
-      UINT8_PRIMARY_KEY_FIELD("Generator Instance"),
+      UINT8_FIELD(PK("Generator Instance")),
       LOOKUP_FIELD("AGS Operating State", BITS(4), AGS_OPERATING_STATE),
       LOOKUP_FIELD("Generator State", BITS(4), AGS_GENERATING_STATE),
       LOOKUP_FIELD("Generator On Reason", BITS(8), AGS_ON_REASON),
@@ -5548,7 +5499,7 @@ Pgn pgnList[] = {
      {UINT8_FIELD("SID"),
       SPEED_U16_CM_FIELD("Wind Speed"),
       ANGLE_U16_FIELD("Wind Angle", NULL),
-      LOOKUP_PRIMARY_KEY_FIELD("Reference", 3, WIND_REFERENCE),
+      LOOKUP_FIELD(PK("Reference"), 3, WIND_REFERENCE),
       RESERVED_FIELD(5 + BYTES(2)),
       END_OF_FIELDS},
      .priority = 2,
@@ -6286,7 +6237,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 1, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 1, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT16_FIELD("A"),
       UINT16_FIELD("B"),
@@ -6300,7 +6251,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 4, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 4, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       LOOKUP_FIELD("Item", BYTES(1), SONICHUB_TUNING),
       RADIO_FREQUENCY_FIELD("Frequency", 1),
@@ -6318,7 +6269,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 5, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 5, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT8_FIELD("Zone"),
       END_OF_FIELDS},
@@ -6331,7 +6282,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 6, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 6, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       LOOKUP_FIELD("Source", BYTES(1), SONICHUB_SOURCE),
       END_OF_FIELDS},
@@ -6344,7 +6295,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 8, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 8, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT8_FIELD("Source ID"),
       UINT8_FIELD("A"),
@@ -6359,7 +6310,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 9, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 9, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       LOOKUP_FIELD("Item", BYTES(1), FUSION_MUTE_COMMAND),
       END_OF_FIELDS},
@@ -6372,7 +6323,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 12, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 12, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       LOOKUP_FIELD("Item", BYTES(1), SONICHUB_TUNING),
       RADIO_FREQUENCY_FIELD("Frequency", 1),
@@ -6392,7 +6343,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 13, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 13, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       LOOKUP_FIELD("Item", BYTES(1), SONICHUB_PLAYLIST),
       UINT8_FIELD("A"),
@@ -6410,7 +6361,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 14, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 14, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT32_FIELD("Item"),
       STRINGLZ_FIELD("Text", BYTES(32)),
@@ -6424,7 +6375,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 15, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 15, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT32_FIELD("Item"),
       STRINGLZ_FIELD("Text", BYTES(32)),
@@ -6438,7 +6389,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 16, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 16, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT32_FIELD("Item"),
       STRINGLZ_FIELD("Text", BYTES(32)),
@@ -6452,7 +6403,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 19, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 19, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT32_FIELD("Item"),
       UINT8_FIELD("C"),
@@ -6469,7 +6420,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 20, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 20, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT8_FIELD("Zones"),
       END_OF_FIELDS},
@@ -6482,7 +6433,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 23, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 23, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT8_FIELD("Zone"),
       UINT8_FIELD("Level"),
@@ -6496,7 +6447,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 24, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 24, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT8_FIELD("Zone"),
       UINT8_FIELD("Level"),
@@ -6510,7 +6461,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 25, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 25, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       END_OF_FIELDS},
      .priority = 7}
@@ -6522,7 +6473,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 48, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 48, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       DURATION_UFIX32_MS_FIELD("Position", NULL),
       END_OF_FIELDS},
@@ -6535,7 +6486,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(275),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 50, SONICHUB_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 50, SONICHUB_COMMAND),
       LOOKUP_FIELD("Control", BYTES(1), SONICHUB_CONTROL),
       UINT8_FIELD("A"),
       UINT8_FIELD("B"),
@@ -6549,7 +6500,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(1857),
       RESERVED_FIELD(BYTES(1)),
-      MATCH_LOOKUP_PRIMARY_KEY_FIELD("Proprietary ID", BYTES(1), 50, SIMNET_COMMAND),
+      MATCH_LOOKUP_FIELD(PK("Proprietary ID"), BYTES(1), 50, SIMNET_COMMAND),
       UINT8_FIELD("A"),
       UINT8_FIELD("B"),
       UINT8_FIELD("C"),
@@ -6573,7 +6524,7 @@ Pgn pgnList[] = {
      PACKET_INCOMPLETE,
      PACKET_FAST,
      {COMPANY(140),
-      UINT16_PRIMARY_KEY_FIELD("Product Code"),
+      UINT16_FIELD(PK("Product Code")),
       STRING_FIX_FIELD("Model", BYTES(32)),
       UINT8_FIELD("A"),
       UINT8_FIELD("B"),
@@ -6662,7 +6613,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32772, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       LOOKUP_FIELD("Flags", BYTES(2), FUSION_PLAY_STATUS),
       UINT32_FIELD("Track #"),
       UINT32_FIELD("Track Count"),
@@ -6678,7 +6629,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32773, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT32_FIELD("Index"),
       STRINGVAR_FIELD("Track"),
       END_OF_FIELDS},
@@ -6691,7 +6642,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32774, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT32_FIELD("Index"),
       STRINGVAR_FIELD("Artist"),
       END_OF_FIELDS},
@@ -6704,7 +6655,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32775, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT32_FIELD("Index"),
       STRINGVAR_FIELD("Album"),
       END_OF_FIELDS},
@@ -6728,7 +6679,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32813, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Number"),
+      UINT8_FIELD(PK("Number")),
       STRINGVAR_FIELD("Name"),
       END_OF_FIELDS},
      .priority = 7}
@@ -6740,7 +6691,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32777, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       DURATION_UFIX24_MS_FIELD("Progress", NULL),
       END_OF_FIELDS},
      .priority = 7}
@@ -6752,7 +6703,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32779, FUSION_STATUS_MESSAGE_ID),
-      LOOKUP_PRIMARY_KEY_FIELD("Source ID", BYTES(1), FUSION_RADIO_SOURCE),
+      LOOKUP_FIELD(PK("Source ID"), BYTES(1), FUSION_RADIO_SOURCE),
       UINT8_FIELD("Scanning"),
       RADIO_FREQUENCY_FIELD("Frequency", 1),
       UINT8_FIELD("Signal Strength"),
@@ -6767,7 +6718,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32780, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT8_FIELD("Channel"),
       UINT8_FIELD("Signal Strength"),
       STRINGVAR_FIELD("Name"),
@@ -6781,7 +6732,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32781, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT8_FIELD("Squelch"),
       END_OF_FIELDS},
      .priority = 7}
@@ -6793,7 +6744,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32782, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       LOOKUP_FIELD("Scan", BYTES(1), YES_NO),
       END_OF_FIELDS},
      .priority = 7}
@@ -6805,7 +6756,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32785, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT32_FIELD("Item Index"),
       UINT8_FIELD("Flags"),
       UINT8_FIELD("Lock ID"),
@@ -6820,7 +6771,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32787, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT8_FIELD("Gain"),
       END_OF_FIELDS},
      .priority = 7}
@@ -6883,7 +6834,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32792, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Zone"),
+      UINT8_FIELD(PK("Zone")),
       UINT8_FIELD("VALUE"),
       END_OF_FIELDS},
      .priority = 7}
@@ -6895,7 +6846,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32793, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Zone"),
+      UINT8_FIELD(PK("Zone")),
       UINT8_FIELD("Filter"),
       END_OF_FIELDS},
      .priority = 7}
@@ -6923,7 +6874,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32795, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Zone"),
+      UINT8_FIELD(PK("Zone")),
       SIMPLE_SIGNED_FIELD("Bass", BYTES(1)),
       SIMPLE_SIGNED_FIELD("Mid", BYTES(1)),
       SIMPLE_SIGNED_FIELD("Treble", BYTES(1)),
@@ -6980,7 +6931,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32799, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Zone"),
+      UINT8_FIELD(PK("Zone")),
       UINT8_FIELD("Control"),
       END_OF_FIELDS},
      .priority = 7}
@@ -7003,7 +6954,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32802, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       LOOKUP_FIELD("Com State", BYTES(1), FUSION_SIRIUS_COM_STATE),
       LOOKUP_FIELD("Alert", BYTES(1), FUSION_SIRIUS_COM_STATE),
       UINT16_FIELD("Advisory Channel"),
@@ -7018,7 +6969,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32804, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT16_FIELD("Channel Number"),
       STRINGVAR_FIELD("Channel"),
       END_OF_FIELDS},
@@ -7031,7 +6982,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32805, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT16_FIELD("Channel"),
       STRINGVAR_FIELD("Title"),
       END_OF_FIELDS},
@@ -7044,7 +6995,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32806, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT16_FIELD("Channel"),
       STRINGVAR_FIELD("Artist"),
       END_OF_FIELDS},
@@ -7057,7 +7008,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32807, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT16_FIELD("Channel"),
       STRINGVAR_FIELD("Genre"),
       END_OF_FIELDS},
@@ -7070,7 +7021,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32808, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT16_FIELD("Channel"),
       STRINGVAR_FIELD("Name"),
       END_OF_FIELDS},
@@ -7083,7 +7034,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32809, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT8_FIELD("Signal"),
       END_OF_FIELDS},
      .priority = 7}
@@ -7095,7 +7046,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(419),
       MATCH_LOOKUP_FIELD("Message ID", BYTES(2), 32812, FUSION_STATUS_MESSAGE_ID),
-      UINT8_PRIMARY_KEY_FIELD("Source ID"),
+      UINT8_FIELD(PK("Source ID")),
       UINT8_FIELD("Count"),
       BINARY_FIELD("Values", 0, "Preset Values. There will be Count / 4 presets stored"),
       END_OF_FIELDS},
@@ -7260,7 +7211,7 @@ Pgn pgnList[] = {
      PACKET_FAST,
      {COMPANY(1857),
       UINT8_FIELD("C"),
-      UINT8_PRIMARY_KEY_FIELD("Device"),
+      UINT8_FIELD(PK("Device")),
       INSTANCE_FIELD,
       SIMPLE_FIELD("F", 1 * 4),
       LOOKUP_FIELD("Tank type", 1 * 4, TANK_TYPE),
diff --git a/common/common.h b/common/common.h
index 7789842d..f529c600 100644
--- a/common/common.h
+++ b/common/common.h
@@ -77,6 +77,10 @@ typedef int SOCKET;
 #define STDOUT (1)
 #define STDERR (2)
 
+// Macro expansion trickery
+#define EMPTY()
+#define DEFER(x) x EMPTY()
+
 typedef enum LogLevel
 {
   LOGLEVEL_FATAL,


Reviews:
user: login: meaning-matters
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-02T08:12:18Z
user: login: meaning-matters
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-02T08:18:21Z
user: login: sbender9
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T12:56:04Z
user: login: keesverruijt
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-02T13:38:11Z

Review comments:
diff_hunk: @@ -1241,7 +1243,16 @@ extern bool printFields(const Pgn *pgn, const uint8_t *data, int length, bool sh
       break;
     }
 
-    strcpy(fieldName, field->camelName ? field->camelName : field->name);
+    if ( showCamel )
path: analyzer/analyzer.c
user: login: meaning-matters
body: `if (showCamel)` is consistent with existing code.
created_at: 2025-05-02T08:12:18Z
author_association: NONE
diff_hunk: @@ -181,6 +182,7 @@ int main(int argc, char **argv)
     }
     else if (strcasecmp(av[1], "-camel") == 0)
     {
+      showCamel = true;
       camelCase(false);
path: analyzer/analyzer.c
user: login: meaning-matters
body: Assuming 'camel' stands for 'camel case': Since the term 'camel case' is already used (and it being the proper term), it should be used everywhere. Introducing a second term 'camel' for the same aspect/thing/... is bad. Also 'show camel' sounds weird.
created_at: 2025-05-02T08:18:21Z
author_association: NONE
diff_hunk: @@ -181,6 +182,7 @@ int main(int argc, char **argv)
     }
     else if (strcasecmp(av[1], "-camel") == 0)
     {
+      showCamel = true;
       camelCase(false);
path: analyzer/analyzer.c
user: login: sbender9
body: This is actually derived from the argument name, which is `-camel`
created_at: 2025-05-02T12:56:04Z
author_association: MEMBER
diff_hunk: @@ -1241,7 +1243,16 @@ extern bool printFields(const Pgn *pgn, const uint8_t *data, int length, bool sh
       break;
     }
 
-    strcpy(fieldName, field->camelName ? field->camelName : field->name);
+    if ( showCamel )
path: analyzer/analyzer.c
user: login: keesverruijt
body: there is a .clang-format file in the repo, just run `make format` with clang-format installed to fix whitespace and other formatting.
created_at: 2025-05-02T13:38:11Z
author_association: COLLABORATOR

PR comments:
user: login: sbender9
created_at: 2025-05-01T14:32:20Z
body: The macro definitions will start getting pretty disgusting, now with _DESC and _CAMEL versions.

wondering if it is better to bite the bullet and add the param to the existing macros and pass NULL unless it is needed?
author_association: MEMBER
user: login: keesverruijt
created_at: 2025-05-02T07:25:47Z
body: Let me brood a little on this — there may be some preprocessor Fu we can use. 
author_association: COLLABORATOR
user: login: keesverruijt
created_at: 2025-05-02T07:45:21Z
body: How about using a nested macro call:

     #define ID(camel, nam) nam, .camelName = camel
     ...
     BINARY_FIELD(ID("someData', "Data"), BYTES(8), NULL)

so we only need to use the ID macro when we need to keep the old camelName.

I'm not married to the word ID as the macro name, CAMEL would do as well.

We should also add a `.git/hooks/pre-commit` or `.git/hooks/pre-push` hook that verifies that no ids have been changed since the last version tag.
author_association: COLLABORATOR
user: login: sbender9
created_at: 2025-05-02T13:10:08Z
body: > How about using a nested macro call:
> 
> ```
>  #define ID(camel, nam) nam, .camelName = camel
>  ...
>  BINARY_FIELD(ID("someData', "Data"), BYTES(8), NULL)
> ```
> 
> so we only need to use the ID macro when we need to keep the old camelName.
> 
> I'm not married to the word ID as the macro name, CAMEL would do as well.
> 
> We should also add a `.git/hooks/pre-commit` or `.git/hooks/pre-push` hook that verifies that no ids have been changed since the last version tag.

Works great for BINARY_FIELD, but not for UINT8_FIELD:

```{UINT8_FIELD(CAMEL("someSid", "SID")), DISTANCE_FIX16_CM_FIELD("Heave", NULL), RESERVED_FIELD(BYTES(5)), END_OF_FIELDS},```

```
In file included from ./analyzer.h:66:
./pgn.h:2984:7: error: too many arguments provided to function-like macro invocation
 2984 |      {UINT8_FIELD(CAMEL("someSid", "SID")), DISTANCE_FIX16_CM_FIELD("Heave", NULL), RESERVED_FIELD(BYTES(5)), END_OF_FIELDS},
      |       ^
./pgn.h:519:48: note: expanded from macro 'UINT8_FIELD'
  519 | #define UINT8_FIELD(nam) UINT8_DESC_FIELD(nam, NULL)
      |                                                ^
./pgn.h:512:9: note: macro 'UINT8_DESC_FIELD' defined here
  512 | #define UINT8_DESC_FIELD(nam, desc) {.name = nam, .size = BYTES(1), .resolution = 1, .fieldType = "UINT8", .description = desc}
      |         ^
./pgn.h:2984:7: error: use of undeclared identifier 'UINT8_DESC_FIELD'
 2984 |      {UINT8_FIELD(CAMEL("someSid", "SID")), DISTANCE_FIX16_CM_FIELD("Heave", NULL), RESERVED_FIELD(BYTES(5)), END_OF_FIELDS},
      |       ^
./pgn.h:519:26: note: expanded from macro 'UINT8_FIELD'
  519 | #define UINT8_FIELD(nam) UINT8_DESC_FIELD(nam, NULL)
      |                          ^
./pgn.h:7535:29: error: invalid application of 'sizeof' to an incomplete type 'Pgn[]' (aka 'struct Pgn[]')
 7535 | const size_t pgnListSize  = ARRAY_SIZE(pgnList);
      |                             ^~~~~~~~~~~~~~~~~~~
../common/common.h:188:30: note: expanded from macro 'ARRAY_SIZE'
  188 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
```
author_association: MEMBER
user: login: keesverruijt
created_at: 2025-05-04T11:27:46Z
body: Solution found, the problem with 

     UINT8_FIELD(CAMEL("camelCase", "name))
     
would be that CAMEL would be expanded first, so you get

    UINT8_FIELD("name", .camelName = "camelCase")

which obviously won't work. There is a C preprocessor trick to defer this one stage:

    #define EMPTY()
    #define DEFER(x) x EMPTY()

    #define CAMEL_NAME(camel, nam) nam, .camelName = camel
    #define CAMEL(camel, nam) DEFER(CAMEL_NAME)(camel, nam)

In the last push I've used a similar macro to define primary keys more naturally.

Unfortunately this only works for one level, so we will have to also define a `PK_CAMEL` as `PK(CAMEL(...))` or `CAMEL(PK(...))` won't work.


author_association: COLLABORATOR
user: login: sbender9
created_at: 2025-05-07T13:14:54Z
body: @keesverruijt how do you want to move forward on this?

I definitely don't think we need to wait on this for a 6.x release.
author_association: MEMBER
user: login: keesverruijt
created_at: 2025-05-08T10:04:52Z
body: No, we don't need this for 6.0 but we do need it for the next one as I am now stating in the changelog that from now on no changes to Id fields will be made.

author_association: COLLABORATOR
user: login: keesverruijt
created_at: 2025-05-26T18:03:01Z
body: This creates macros PK() and CAMEL() that can be used simultaneously, if necessary.
author_association: COLLABORATOR