aboutsummaryrefslogtreecommitdiffstats
path: root/fw/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/main.c')
-rw-r--r--fw/main.c167
1 files changed, 125 insertions, 42 deletions
diff --git a/fw/main.c b/fw/main.c
index 1f0308b..d5b1443 100644
--- a/fw/main.c
+++ b/fw/main.c
@@ -2,6 +2,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <string.h>
#include "system.h"
#include "types.h"
@@ -14,10 +15,22 @@
// TODO: auto baud detection
#define CAN_TIMING CAN_TIMING_10K
+// Parameters
+typedef enum {
+ TACH = 0,
+ SPEED,
+ AN1,
+ AN2,
+ AN3,
+ AN4,
+
+ NPARAM,
+} Param;
+
// Table Control filter.
// Used for writing/reading calibration tables.
static const CanId tblCtrlFilter = {
- .type = CAN_ID_EXT,
+ .isExt = true,
.eid = {0x00, 0x20, 0x27, 0x01}, // 12720XXh
};
@@ -25,7 +38,7 @@ static const CanId tblCtrlFilter = {
// Used for writing/reading the CAN ID associated with each parameter.
// See `doc/datafmt.ps'.
static const CanId idCtrlFilter = {
- .type = CAN_ID_EXT,
+ .isExt = true,
.eid = {0x00, 0x21, 0x27, 0x01}, // 127210Xh
};
@@ -34,7 +47,7 @@ static const CanId idCtrlFilter = {
// and CAN IDs for each parameter.
// This mask is the union of the two control message filters.
static const CanId rxb0Mask = {
- .type = CAN_ID_EXT,
+ .isExt = true,
.eid = {0x00, 0x21, 0x27, 0x01}, // 1272100h
};
@@ -42,7 +55,7 @@ static const CanId rxb0Mask = {
// RXB1 is used for receiving parameter values.
// The mask is permissive: all messages are accepted and filtered in software.
static const CanId rxb1Mask = {
- .type = CAN_ID_EXT,
+ .isExt = true,
.eid = {0u, 0u, 0u, 0u}, // accept all messages
};
@@ -58,53 +71,33 @@ static const Table an4Tbl = {{0x05, 0x00}};
// EEPROM address of CAN ID for each parameter.
// Each of these addresses holds a U32 CAN ID.
-static const EepromAddr tachIdAddr = {0x06, 0x00}; // tachometer
-static const EepromAddr speedIdAddr = {0x06, 0x04}; // speedometer
-static const EepromAddr an1IdAddr = {0x06, 0x08}; // analog channels...
-static const EepromAddr an2IdAddr = {0x06, 0x0C};
-static const EepromAddr an3IdAddr = {0x06, 0x10};
-static const EepromAddr an4IdAddr = {0x06, 0x14};
-
-static volatile CanId tachId; // tachometer
-static volatile CanId speedId; // speedometer
-static volatile CanId an1Id; // analog channels...
-static volatile CanId an2Id;
-static volatile CanId an3Id;
-static volatile CanId an4Id;
+static const EepromAddr paramIdAddrs[NPARAM] = {
+ [TACH] = {0x06, 0x00}, // tachometer
+ [SPEED] = {0x06, 0x04}, // speedometer
+ [AN1] = {0x06, 0x08}, // analog channels...
+ [AN2] = {0x06, 0x0C},
+ [AN3] = {0x06, 0x10},
+ [AN4] = {0x06, 0x14},
+};
+
+// CAN ID of each parameter
+static volatile CanId paramIds[NPARAM];
// Load parameters' CAN IDs from EEPROM
static Status
loadParamIds(void) {
- U8 oldGie;
+ U8 oldGie, k;
Status status;
// Disable interrupts so the volatile address pointers can be passed safely
oldGie = INTCONbits.GIE;
INTCONbits.GIE = 0;
- status = eepromReadCanId(tachIdAddr, (CanId*)&tachId);
- if (status != OK) {
- return FAIL;
- }
- status = eepromReadCanId(speedIdAddr, (CanId*)&speedId);
- if (status != OK) {
- return FAIL;
- }
- status = eepromReadCanId(an1IdAddr, (CanId*)&an1Id);
- if (status != OK) {
- return FAIL;
- }
- status = eepromReadCanId(an2IdAddr, (CanId*)&an2Id);
- if (status != OK) {
- return FAIL;
- }
- status = eepromReadCanId(an3IdAddr, (CanId*)&an3Id);
- if (status != OK) {
- return FAIL;
- }
- status = eepromReadCanId(an4IdAddr, (CanId*)&an4Id);
- if (status != OK) {
- return FAIL;
+ for (k = 0u; k < NPARAM; k++) {
+ status = eepromReadCanId(paramIdAddrs[k], (CanId*)&paramIds[k]);
+ if (status != OK) {
+ return FAIL;
+ }
}
// Restore previous interrupt setting
@@ -163,11 +156,101 @@ 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 parameter.
+static Status
+respondIdCtrl(Param param) {
+ CanFrame response;
+ CanId paramId;
+ Status status;
+
+ // Read parameter's CAN ID from EEPROM
+ if ((U8)param < NPARAM) {
+ status = eepromReadCanId(paramIdAddrs[param], &paramId);
+ if (status != OK) {
+ return FAIL; // read failed
+ }
+ } else {
+ return FAIL; // invalid parameter
+ }
+
+ // Pack param ID into response's DATA FIELD
+ response.id = (CanId) {
+ .isExt = true,
+ .eid = {param & 0xF, 0x21, 0x27, 0x01}, // 127210Xh
+ };
+ response.rtr = false;
+ if (paramId.isExt) { // extended
+ response.dlc = 4u; // U32
+ // BE <- LE
+ response.data[0u] = paramId.eid[3u] & 0x1F;
+ response.data[1u] = paramId.eid[2u];
+ response.data[2u] = paramId.eid[1u];
+ response.data[3u] = paramId.eid[0u];
+ } else { // standard
+ response.dlc = 2u; // U16
+ response.data[0u] = paramId.sid.hi & 0x7;
+ response.data[1u] = paramId.sid.lo;
+ }
+
+ // Transmit response
+ return canTx(&response);
+}
+
+// Set the CAN ID associated with a parameter in response to an ID Control DATA FRAME.
+static Status
+setParamId(const CanFrame *frame) {
+ CanId paramId;
+ Param param;
+ Status status;
+
+ // Extract param ID from DATA FIELD
+ if (frame->dlc == 4u) { // extended
+ paramId.isExt = true;
+ // LE <- BE
+ paramId.eid[0u] = frame->data[3u];
+ paramId.eid[1u] = frame->data[2u];
+ paramId.eid[2u] = frame->data[1u];
+ paramId.eid[3u] = frame->data[0u] & 0x1F;
+ } else if (frame->dlc == 2u) { // standard
+ paramId.isExt = false;
+ paramId.sid.lo = frame->data[1u];
+ paramId.sid.hi = frame->data[0u] & 0x7;
+ } else {
+ return FAIL; // invalid DLC
+ }
+
+ // Extract param # from Control Frame's ID
+ param = frame->id.eid[0u] & 0xF;
+ if ((U8)param >= NPARAM) {
+ return FAIL; // invalid parameter
+ }
+
+ // Update copy in EEPROM
+ status = eepromWriteCanId(paramIdAddrs[param], &paramId);
+ if (status != OK) {
+ return FAIL; // write failed
+ }
+
+ // Update copy in PIC's RAM
+ paramIds[param] = paramId;
+
+ return OK;
+}
+
// Handle an ID Control Frame.
// See `doc/datafmt.ps'
static Status
handleIdCtrlFrame(const CanFrame *frame) {
- // TODO
+ Param param;
+
+ if (frame->rtr) { // REMOTE
+ param = frame->id.eid[0u] & 0xF;
+ return respondIdCtrl(param); // respond with the parameter's CAN ID
+ } else { // DATA
+ return setParamId(frame);
+ }
}
// Handle a frame potentially holding a parameter value.