aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-11-07 10:33:58 -0500
committerSam Anthony <sam@samanthony.xyz>2025-11-07 10:33:58 -0500
commit4158981e549db6c5cc626cfd6d244c85485f5612 (patch)
tree749addefa29e66514f9ed9597f0b2d482ca06981
parentf88c088264f17e681b938cb3542ba0846b791fca (diff)
downloadcan-gauge-interface-4158981e549db6c5cc626cfd6d244c85485f5612.zip
respond to Signal Control REMOTE FRAME
-rw-r--r--fw/main.c91
-rw-r--r--fw/serial.h6
-rw-r--r--fw/table.h12
3 files changed, 76 insertions, 33 deletions
diff --git a/fw/main.c b/fw/main.c
index 06451ef..80719f1 100644
--- a/fw/main.c
+++ b/fw/main.c
@@ -17,6 +17,12 @@
// TODO: auto baud detection
#define CAN_TIMING CAN_TIMING_10K
+// Control frame CAN IDs
+enum {
+ TAB_CTRL_CAN_ID = 0x1272000, // Table Control Frame ID
+ SIG_CTRL_CAN_ID = 0x1272100, // Signal Control Frame ID
+};
+
// Signals
typedef enum {
SIG_TACH = 0,
@@ -33,22 +39,20 @@ typedef enum {
// Used for writing/reading calibration tables.
static const CanId tblCtrlFilter = {
.isExt = true,
- .eid = 0x01272000, // 112720XXh
-};
+ .eid = TAB_CTRL_CAN_ID};
-// ID Control filter.
-// Used for writing/reading the CAN ID associated with each signal.
-// See `doc/datafmt.ps'.
-static const CanId idCtrlFilter = {
+// Signal Control filter.
+// Used for writing/reading the CAN ID and encoding format of each signal.
+// See `doc/datafmt.pdf'.
+static const CanId sigCtrlFilter = {
.isExt = true,
- .eid = 0x01272100, // 127210Xh
-};
+ .eid = SIG_CTRL_CAN_ID};
// Receive buffer 0 mask.
-// RXB0 receives Table and ID Control Frames.
+// RXB0 receives Table Control and Signal Control frames.
static const CanId rxb0Mask = {
.isExt = true,
- .eid = 0x1FFFFF00, // all buf LSB
+ .eid = 0x1FFFFF00, // all but LSB
};
// Receive buffer 1 mask.
@@ -146,7 +150,7 @@ main(void) {
canSetBitTiming(CAN_TIMING);
canSetMask0(&rxb0Mask); // RXB0 receives control messages
canSetFilter0(&tblCtrlFilter); // Table Control Frames
- canSetFilter1(&idCtrlFilter); // ID Control Frames
+ canSetFilter1(&sigCtrlFilter); // Signal Control Frames
canSetMask1(&rxb1Mask); // RXB1 receives signal values
// RXB1 messages are filtered in software
canIE(true); // enable interrupts on MCP2515's INT pin
@@ -171,32 +175,66 @@ handleTblCtrlFrame(const CanFrame *frame) {
// TODO
}
-// Transmit the response to an ID Control REMOTE FRAME.
-// The response is an ID Control DATA FRAME containing the CAN ID
-// of the requested signal.
+// Transmit the response to a Signal Control REMOTE FRAME.
+// The response is a Signal Control DATA FRAME containing the CAN ID
+// and encoding format of the requested signal.
static Status
-respondIdCtrl(Signal sig) {
- // TODO: "ID Control" will likely have to be renamed to "Signal Control" or "Encoding Control" or similar. It will carry a SigFmt structure instead of just a CAN ID. The datafmt doc will have to be updated too.
+respondSigCtrl(Signal sig) {
+ const volatile SigFmt *sigFmt;
+ CanFrame response;
+
+ if (sig >= NSIG) {
+ return FAIL;
+ }
+ sigFmt = &sigFmts[sig];
+
+ response.id = (CanId){
+ .isExt = true,
+ .eid = SIG_CTRL_CAN_ID | (sig & 0xF),
+ };
+ response.rtr = false;
+ response.dlc = 7u;
+
+ // SigId
+ if (sigFmt->id.isExt) { // extended
+ response.data[0u] = 0x80 | ((sigFmt->id.eid >> 24u) & 0x1F); // EXIDE=1
+ response.data[1u] = (sigFmt->id.eid >> 16u) & 0xFF;
+ response.data[2u] = (sigFmt->id.eid >> 8u) & 0xFF;
+ response.data[3u] = (sigFmt->id.eid >> 0u) & 0xFF;
+ } else { // standard
+ response.data[0u] = 0u; // EXIDE=0
+ response.data[1u] = 0u;
+ response.data[2u] = (sigFmt->id.sid >> 8u) & 0x07;
+ response.data[3u] = (sigFmt->id.sid >> 0u) & 0xFF;
+ }
+
+ // Encoding
+ response.data[4u] = sigFmt->start;
+ response.data[5u] = sigFmt->size;
+ response.data[6u] = (U8)((sigFmt->order & 0x1) << 7u)
+ | (U8)((sigFmt->isSigned) ? 0x40 : 0x00);
+
+ return canTx(&response);
}
-// Set the CAN ID associated with a signal in response to an ID Control DATA FRAME.
+// Set the CAN ID and encoding format of a signal in response
+// to a Signal Control DATA FRAME.
static Status
-setSigId(const CanFrame *frame) {
- // TODO: this will likely have to be renamed to setSigFmt or similar. See above comment on updating datafmt doc.
+setSigFmt(const CanFrame *frame) {
+ // TODO
}
-// Handle an ID Control Frame.
-// See `doc/datafmt.ps'
+// Handle a Signal Control Frame.
+// See `doc/datafmt.pdf'
static Status
-handleIdCtrlFrame(const CanFrame *frame) {
+handleSigCtrlFrame(const CanFrame *frame) {
Signal sig;
- // TODO: update datafmt doc to transceive entire signal encoding format instead of just the ID.
if (frame->rtr) { // REMOTE
sig = frame->id.eid & 0xF;
- return respondIdCtrl(sig); // respond with the signal's CAN ID
+ return respondSigCtrl(sig); // respond with the signal's CAN ID and encoding format
} else { // DATA
- return setSigId(frame);
+ return setSigFmt(frame);
}
}
@@ -281,9 +319,8 @@ __interrupt() isr(void) {
(void)handleTblCtrlFrame(&frame);
break;
case 1u: // RXF1: signal ID control
- // TODO: see above TODOs on updating datafmt doc
canReadRxb0(&frame);
- (void)handleIdCtrlFrame(&frame);
+ (void)handleSigCtrlFrame(&frame);
break;
default: // message in RXB1
canReadRxb1(&frame);
diff --git a/fw/serial.h b/fw/serial.h
index 5a6b495..b071038 100644
--- a/fw/serial.h
+++ b/fw/serial.h
@@ -34,9 +34,9 @@ Status serReadCanId(EepromAddr addr, CanId *id);
// SigFmts use 8 bytes of space.
// The ID is stored little-endian in the first 4 bytes: 0--3.
// Start and Size occupy bytes 4 and 5.
-// The Byte-order and Signedness flags are bits 0 and 1 of byte 6, respectively.
-// Byte order: [6][0] = {0=>LE, 1=>BE}.
-// Signedness: [6][1] = {0=>unsigned, 1=>signed}.
+// The Byte-order and Signedness flags are bits 7 and 6 of byte 6, respectively.
+// Byte order: [6][7] = {0=>LE, 1=>BE}.
+// Signedness: [6][6] = {0=>unsigned, 1=>signed}.
// Byte 7 is unused -- it's for alignment.
Status serWriteSigFmt(EepromAddr addr, const SigFmt *sig);
diff --git a/fw/table.h b/fw/table.h
index a5cfb7b..da9baa0 100644
--- a/fw/table.h
+++ b/fw/table.h
@@ -1,11 +1,17 @@
/* Table datastructure for storing calibrations in the EEPROM.
*
* A table has a fixed number of rows that define a key/value mapping.
- * Keys and values are each U32.
- * T: U32->U32
+ * Keys and values are 32-bit and 16-bit respectively.
+ *
+ * Keys may be signed or unsigned; whether they are interpreted as
+ * signed or unsigned when they are read depends on the context. They
+ * must be monotonically increasing down the table.
+ *
+ * Values are unsigned 16-bit integers.
+ *
* Numbers are stored little-endian.
*
- * Keys must be monotonically increasing.
+ * See also: doc/datafmt.pdf
*
* Device: PIC16F1459
* Compiler: XC8 v3.00