aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-11-01 17:36:26 -0400
committerSam Anthony <sam@samanthony.xyz>2025-11-01 17:36:26 -0400
commit0dbbdd9b594269fdb66c834146011df48678a901 (patch)
tree91e3969691926868ad8a41d7d907720e4d4ab276
parentd0ceeb4e2ad98c2f5698d78513143a39c6f36b95 (diff)
downloadcan-gauge-interface-0dbbdd9b594269fdb66c834146011df48678a901.zip
extract big-endian signals from frames
-rw-r--r--fw/Makefile2
-rw-r--r--fw/signal.c93
-rw-r--r--fw/signal.h33
-rw-r--r--fw/signal_utestable.h2
-rw-r--r--fw/tests/unit/signal_utests.c51
-rw-r--r--fw/tests/unit/types_utests.c63
-rw-r--r--fw/tests/unit/types_utests.h5
7 files changed, 180 insertions, 69 deletions
diff --git a/fw/Makefile b/fw/Makefile
index 1c0fb95..4d88b3a 100644
--- a/fw/Makefile
+++ b/fw/Makefile
@@ -38,7 +38,7 @@ UTEST_INCLUDES = -I. -I $(UNITY_DIR)
UTEST_CFLAGS = -std=c99 -Wall $(UTEST_INCLUDES)
UTEST_LDFLAGS =
UTEST_BIN = $(basename $(wildcard $(UTEST_DIR)/*.c))
-UTEST_SRC = $(wildcard $(UTEST_DIR)/*.c) $(UNITY_DIR)/unity.c
+UTEST_SRC = $(wildcard $(UTEST_DIR)/*.c) $(UNITY_DIR)/unity.c signal.c
UTEST_OBJ = $(UTEST_SRC:.c=.o)
UTEST_HDR = $(wildcard $(UTEST_DIR)/*.h) $(UNITY_DIR)/unity.h
diff --git a/fw/signal.c b/fw/signal.c
new file mode 100644
index 0000000..30916e0
--- /dev/null
+++ b/fw/signal.c
@@ -0,0 +1,93 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "types.h"
+#include "can.h"
+
+#include "signal.h"
+#include "signal_utestable.h"
+
+// Extract a little-endian value from a frame.
+// Assumes signal is within the frame's DATA FIELD.
+Status
+pluckLE(const SigFmt *sig, const CanFrame *frame, U32 *raw) {
+ // TODO
+}
+
+// Extract a big-endian value from a frame.
+// Assumes signal is within the frame's DATA FIELD.
+void
+pluckBE(const SigFmt *sig, const CanFrame *frame, U32 *raw) {
+ U8 i, end, mask;
+
+ *raw = 0ul;
+ end = sig->start+sig->size;
+
+ // First iteration starts at arbitrary bit: namely the (i%8)'th bit.
+ // Subsequent iterations start at bit 0 of each byte.
+
+ for (i = sig->start; i < end; i += 8u-(i%8u)) {
+ mask = 0xFF << (i%8u);
+ if (i/8u == end/8u) { // if end in this byte
+ mask >>= (8u - (end%8u)); // ignore top bits
+ *raw <<= (end%8u) - (i%8u); // include bits between i and end
+ } else {
+ *raw <<= 8u - (i%8u); // include bits between i and end of byte
+ }
+ *raw |= (frame->data[i/8u] & mask) >> (i%8u);
+ }
+}
+
+Status
+sigPluck(const SigFmt *sig, const CanFrame *frame, Number *raw) {
+ // Preconditions
+ if (
+ (sig->start >= (8u * frame->dlc)) // signal starts outside DATA FIELD
+ || (sig->size > (8u * frame->dlc - sig->start)) // signal extends outside DATA FIELD
+ || (sig->size < 1u) // signal is empty
+ ) {
+ return FAIL;
+ }
+
+ // Read signal into U32
+ switch (sig->order) {
+ case LITTLE_ENDIAN:
+ pluckLE(sig, frame, &raw->u32);
+ break;
+ case BIG_ENDIAN:
+ pluckBE(sig, frame, &raw->u32);
+ break;
+ default:
+ return FAIL; // invalid byte order
+ }
+
+ // Shrink signal to appropriate size and set +/- sign
+ if (sig->size <= 8u) {
+ raw->u8 = raw->u32 & 0xFF;
+ if (sig->isSigned) {
+ raw->type = NUM_I8;
+ raw->i8 = *(I8 *)&raw->u8;
+ } else {
+ raw->type = NUM_U8;
+ }
+ } else if (sig->size <= 16u) {
+ raw->u16 = raw->u32 & 0xFFFF;
+ if (sig->isSigned) {
+ raw->type = NUM_I16;
+ raw->i16 = *(I16 *)&raw->u16;
+ } else {
+ raw->type = NUM_U16;
+ }
+ } else if (sig->size <= 32u) {
+ if (sig->isSigned) {
+ raw->type = NUM_I32;
+ raw->i32 = *(I32 *)&raw->u32;
+ } else {
+ raw->type = NUM_U32;
+ }
+ } else {
+ return FAIL; // signal too big
+ }
+
+ return OK;
+}
diff --git a/fw/signal.h b/fw/signal.h
new file mode 100644
index 0000000..8bbc120
--- /dev/null
+++ b/fw/signal.h
@@ -0,0 +1,33 @@
+/** DBC Signals.
+ * See "DBC File Format Documentation" v.01/2007
+ *
+ * Device PIC16F1459
+ * Compiler: XC8 v3.00
+ *
+ * Usage:
+ *
+ * #include <stdbool.h>
+ * #include <stdint.h>
+ * #include "types.h"
+ * #include "can.h"
+ * #include "signal.h"
+ */
+
+// Byte order
+typedef enum {
+ LITTLE_ENDIAN = 0,
+ BIG_ENDIAN,
+} ByteOrder;
+
+// A Signal Format defines how a DBC signal is encoded in a CAN frame.
+typedef struct {
+ CanId id; // ID of message containing the signal
+ U8 start; // start bit -- position of signal within DATA FIELD
+ U8 size; // size of the signal in bits
+ ByteOrder order; // little-endian/big-endian
+ bool isSigned;
+} SigFmt;
+
+// Extract the raw signal value out of a CAN frame's DATA FIELD.
+// Assumes the frame's ID matches that of the signal.
+Status sigPluck(const SigFmt *sig, const CanFrame *frame, Number *raw);
diff --git a/fw/signal_utestable.h b/fw/signal_utestable.h
new file mode 100644
index 0000000..6ab802b
--- /dev/null
+++ b/fw/signal_utestable.h
@@ -0,0 +1,2 @@
+Status pluckLE(const SigFmt *sig, const CanFrame *frame, U32 *raw);
+void pluckBE(const SigFmt *sig, const CanFrame *frame, U32 *raw);
diff --git a/fw/tests/unit/signal_utests.c b/fw/tests/unit/signal_utests.c
new file mode 100644
index 0000000..ebce8f6
--- /dev/null
+++ b/fw/tests/unit/signal_utests.c
@@ -0,0 +1,51 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <unity.h>
+
+#include <types.h>
+#include <can.h>
+#include <signal.h>
+#include <signal_utestable.h>
+
+void setUp(void) {}
+void tearDown(void) {}
+
+static void
+testPluckLE(void) {
+ setUp();
+
+ // TODO
+ TEST_ASSERT(0);
+
+ tearDown();
+}
+
+static void
+testPluckBE(void) {
+ setUp();
+
+ // 1111 1111 (1110 11)10 (1111 0010) 1111 1(101)
+ // 7 0 15 8 23 16 31 24
+ CanFrame frame = {.data = {0xFF, 0xEE, 0xF2, 0xFD}};
+ SigFmt sig = {
+ .start = 10u,
+ .size = 17u,
+ };
+ U32 want = 0x1DF95;
+ U32 got;
+ pluckBE(&sig, &frame, &got);
+ TEST_ASSERT_EQUAL_UINT32(want, got);
+
+ tearDown();
+}
+
+int
+main(void) {
+ UnityBegin(__FILE__);
+
+ RUN_TEST(testPluckLE);
+ RUN_TEST(testPluckBE);
+
+ return UnityEnd();
+}
diff --git a/fw/tests/unit/types_utests.c b/fw/tests/unit/types_utests.c
deleted file mode 100644
index 578a100..0000000
--- a/fw/tests/unit/types_utests.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <unity.h>
-
-#include <types.h>
-
-void setUp(void) {}
-void tearDown(void) {}
-
-void
-testAddU16(void) {
- setUp();
- // TODO
- TEST_ASSERT(false);
- tearDown();
-}
-
-void
-testAddU16U8(void) {
- setUp();
- // TODO
- TEST_ASSERT(false);
- tearDown();
-}
-
-void
-testLshiftU16(void) {
- setUp();
- // TODO
- TEST_ASSERT(false);
- tearDown();
-}
-
-void
-testRshiftU16(void) {
- setUp();
- // TODO
- TEST_ASSERT(false);
- tearDown();
-}
-
-void
-testCmpU16(void) {
- setUp();
- // TODO
- TEST_ASSERT(false);
- tearDown();
-}
-
-int
-main(void) {
- UnityBegin(__FILE__);
-
- // Types
- RUN_TEST(testAddU16);
- RUN_TEST(testAddU16U8);
- RUN_TEST(testLshiftU16);
- RUN_TEST(testRshiftU16);
- RUN_TEST(testCmpU16);
-
- return UnityEnd();
-}
diff --git a/fw/tests/unit/types_utests.h b/fw/tests/unit/types_utests.h
deleted file mode 100644
index 1923727..0000000
--- a/fw/tests/unit/types_utests.h
+++ /dev/null
@@ -1,5 +0,0 @@
-testAddU16(void);
-testAddU16U8(void);
-testLshiftU16(void);
-testRshiftU16(void);
-testCmpU16(void);