diff --git a/sufst-controller/buffer.cpp b/sufst-controller/buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9f37426c5d6fdadd7b2fc4fd96d831cb21b7924 --- /dev/null +++ b/sufst-controller/buffer.cpp @@ -0,0 +1,142 @@ +// +// Created by Sil on 7/19/2019. +// + +#include "buffer.h" + +uint8_t cirBufferBegin(cirBuffer_handle cirBuff, void *data, uint16_t len, uint8_t unitSize) +{ + + if (cirBuff == NULL) { + return 0; + } + + if (data == NULL) { + return 0; + } + + cirBuff->head = 0; + cirBuff->tail = 0; + cirBuff->capacity = len; + cirBuff->full = 0; + cirBuff->data = (uint8_t *) data; + cirBuff->unitSize = unitSize; + + return 1; +} + +uint16_t cirBufferAvailable(cirBuffer_handle cirBuff) +{ + uint16_t availableForWrite = 0; + + if (!cirBuff->full) { + if (cirBuff->head >= cirBuff->tail) { + availableForWrite = cirBuff->head - cirBuff->tail; + } + else { + availableForWrite = cirBuff->capacity - cirBuff->tail + cirBuff->head; + } + } + else { + availableForWrite = cirBuff->capacity; + } + + return availableForWrite; +} + +uint16_t cirBufferAvailableForWrite(cirBuffer_handle cirBuff) +{ + return cirBuff->capacity - cirBufferAvailable(cirBuff); +} + +void cirBufferWrite(cirBuffer_handle cirBuff, void *unit) +{ + memcpy(&(cirBuff->data[cirBuff->head * cirBuff->unitSize]), unit, cirBuff->unitSize); + + ++cirBuff->head &= (cirBuff->capacity - 1); + + if (cirBuff->head == cirBuff->tail) { + cirBuff->full = 1; + + ++cirBuff->tail &= (cirBuff->capacity - 1); + } +} + +void cirBufferWriteBytes(cirBuffer_handle cirBuff, void *src, uint16_t len) +{ + + uint16_t usedBytes = cirBufferAvailable(cirBuff); + + if ((usedBytes + len) > cirBuff->capacity) { + cirBuff->full = 1; + } + + for (uint16_t i = 0; i < len; i++) { + cirBuff->data[cirBuff->head] = ((uint8_t *) src)[i]; + + ++cirBuff->head &= cirBuff->capacity - 1; + } + + if (cirBuff->full) { + cirBuff->tail = (cirBuff->tail + (len - (cirBuff->capacity - usedBytes))) & (cirBuff->capacity - 1); + } +} + +void *cirBufferExternalWrite(cirBuffer_handle cirBuff) +{ + uint8_t *head = &(cirBuff->data[cirBuff->head]); + + ++cirBuff->head &= cirBuff->capacity - 1; + + if (cirBuff->head == cirBuff->tail) { + cirBuff->full = 1; + + ++cirBuff->tail &= (cirBuff->capacity - 1); + } + + return head; +} + +void *cirBufferExternalRead(cirBuffer_handle cirBuff) +{ + uint8_t *tail = &(cirBuff->data[cirBuff->tail]); + + ++cirBuff->tail &= (cirBuff->capacity - 1); + + return (void *) tail; +} + +void cirBufferRead(cirBuffer_handle cirBuff, void *loc) +{ + + memcpy(loc, &(cirBuff->data[cirBuff->tail * cirBuff->unitSize]), cirBuff->unitSize); + + ++cirBuff->tail &= (cirBuff->capacity - 1); + + cirBuff->full = 0; + +} + +void *cirBufferPeek(cirBuffer_handle cirBuff) +{ + return (void *) (cirBuff->data[cirBuff->tail]); +} + +void cirBufferReadBytes(cirBuffer_handle cirBuff, void *loc, uint16_t len) +{ + cirBuff->full = 0; + + for (uint16_t i = 0; i < len; i++) { + ((uint8_t *) loc)[i] = cirBuff->data[cirBuff->tail]; + + ++cirBuff->tail &= cirBuff->capacity - 1; + } + +} + +void cirBufferReset(cirBuffer_handle cirBuff) +{ + cirBuff->head = 0; + cirBuff->tail = 0; + cirBuff->full = 0; +} \ No newline at end of file diff --git a/sufst-controller/buffer.h b/sufst-controller/buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..d8f886dfb619dfe314927fcad7b24f44b1123307 --- /dev/null +++ b/sufst-controller/buffer.h @@ -0,0 +1,48 @@ +// +// Created by Sil on 7/19/2019. +// + +#ifndef BUFFER_H +#define BUFFER_H + +#include "Arduino.h" + +typedef struct CirBuffer +{ + uint16_t head; + uint16_t tail; + uint8_t full; + uint8_t *data; + uint16_t capacity; + uint8_t unitSize; +}; + +typedef CirBuffer *cirBuffer_handle; + +/* + * THE LEN OF THE BUFFER MUST BE A POWER OF 2 + */ + +uint8_t cirBufferBegin(cirBuffer_handle cirBuff, void *data, uint16_t len, uint8_t unitSize); + +uint16_t cirBufferAvailable(cirBuffer_handle cirBuff); + +uint16_t cirBufferAvailableForWrite(cirBuffer_handle cirBuff); + +void cirBufferWrite(cirBuffer_handle cirBuff, void *unit); + +void cirBufferWriteBytes(cirBuffer_handle cirBuff, void *src, uint16_t len); + +void *cirBufferExternalWrite(cirBuffer_handle cirBuff); + +void cirBufferRead(cirBuffer_handle cirBuff, void *loc); + +void cirBufferReadBytes(cirBuffer_handle cirBuff, void *loc, uint16_t len); + +void *cirBufferExternalRead(cirBuffer_handle cirBuff); + +void *cirBufferPeek(cirBuffer_handle cirBuff); + +void cirBufferReset(cirBuffer_handle cirBuff); + +#endif //BUFFER_H \ No newline at end of file diff --git a/sufst-controller/can.cpp b/sufst-controller/can.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cc3e65b3620dcfb528ed77e92740565586e339f --- /dev/null +++ b/sufst-controller/can.cpp @@ -0,0 +1,321 @@ +// +// Created by Sil on 15/07/2019. +// + +#include "can.h" +// Watchdog +#include <avr/wdt.h> +#include "buffer.h" +#include <mcp_can.h> +#include <mcp_can_dfs.h> + +#include "ecuCan.h" + +// Can instance +MCP_CAN can; + +volatile unsigned long lastCanMsgRecTimeMs = 0; + +static CanMsgTemplate canRxBuffer[CAN_RX_BUFFER_LEN]; + +volatile CirBuffer canRxCirBuffer; + +static CanMsgTemplate canTxBuffer[CAN_TX_BUFFER_LEN]; + +volatile CirBuffer canTxCirBuffer; + +extern void ecuCanMsg0x2000(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2001(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2002(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2003(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2004(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2005(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2006(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2007(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2008(CanMsgTemplate *canMsg); + +extern void ecuCanMsg0x2009(CanMsgTemplate *canMsg); + +// ECU can messages function pointers for calling the corresponding function when that msg is seen. +// Used in function canParseRxMsg. +void +(*ecuCanFuncPtrs[10])(CanMsgTemplate *) = {ecuCanMsg0x2000, ecuCanMsg0x2001, + ecuCanMsg0x2002, + ecuCanMsg0x2003, + ecuCanMsg0x2004, ecuCanMsg0x2005, + ecuCanMsg0x2006, + ecuCanMsg0x2007, ecuCanMsg0x2008, + ecuCanMsg0x2009}; + +uint8_t canBegin() +{ + if (!cirBufferBegin(&canRxCirBuffer, canRxBuffer, CAN_RX_BUFFER_LEN, sizeof(CanMsgTemplate))) { + return 0; + } + + if (!cirBufferBegin(&canTxCirBuffer, canTxBuffer, CAN_TX_BUFFER_LEN, sizeof(CanMsgTemplate))) { + return 0; + } + + pinMode(CAN_INT_PIN, INPUT_PULLUP); + + // Initialize the Arduino CAN class with slave select pin. + can.init_CS(CAN_CS_PIN); + + // Initialize the CAN bus with speed 1000kbps + if (can.begin(CAN_1000KBPS) == CAN_FAILINIT) { + return 0; + } + + + return 1; +} + +uint8_t canSaveMsg() +{ + if (digitalRead(CAN_INT_PIN)) { + return 0; + } + + union + { + uint8_t id[4]; + uint32_t id32; + } uid; + + if (can.checkReceive() != CAN_MSGAVAIL) { + return 0; + } + + CanMsgTemplate canReceivedMsg; + + if (can.readMsgBuf(&(canReceivedMsg.len), canReceivedMsg.data) != CAN_OK) { + return 0; + } + + uid.id32 = can.getCanId(); + + canReceivedMsg.timestamp = millis(); + + canReceivedMsg.id = (uid.id[1] << 8) | uid.id[0]; + + cirBufferWrite(&canRxCirBuffer, &canReceivedMsg); + +#if DEBUG_CAN_RX + Serial.print("CAN SV RX: "); + + Serial.print(canReceivedMsg.id, HEX); + Serial.print(" : "); + for(uint8_t i = 0; i < 7; i++) { + Serial.print(canReceivedMsg.data[i]); + Serial.print(", "); + } + Serial.println(canReceivedMsg.data[7]); +#endif // DEBUG_CAN_RX; + + return 1; +} + +void canAddTxRequest(CanMsgTemplate *canMsg) +{ + if (NULL == canMsg) { + return; + } + +#if DEBUG_CAN_TX_REQS + Serial.print("CAN TX ADD: "); + Serial.print(canMsg.id, HEX); + Serial.print(" : "); + for(uint8_t i = 0; i < 7; i++) { + Serial.print(canMsg.data[i], HEX); + Serial.print(", "); + } + Serial.println(canMsg.data[7], HEX); +#endif // DEBUG_CAN_TX_REQS + + cirBufferWrite(&canTxCirBuffer, canMsg); +} + +// External interrupt currently only designed to work with atmega 2560 +#if !defined(__AVR_ATmega2560__) +#error "PLATFORM NOT SUPPORTED CURRENTLY" +#endif // !defined(atmega2560) + +#if CAN_INT_PIN != 2 +#error "CAN_INT_PIN CHANGED FROM 2" +#endif //CAN_INT_PIN != 2 + +void canBeginExtInterrupt() +{ + noInterrupts(); + + // On the mega 2560 pin 2 is external interrupt 4 + EIMSK &= ~(1 << INT4); + + EICRB &= ~(1 << ISC41); + //EICRB &= ~(1 << ISC40); + + EIMSK |= (1 << INT4); + + interrupts(); +} + +ISR(INT4_vect) { + + noInterrupts(); + + lastCanMsgRecTimeMs = millis(); + + canSaveMsg(); + + interrupts(); +} + +void canParseRxMsg(CanMsgTemplate *canMsg) +{ + if ((canMsg->id >= 0x2000) && (canMsg->id <= 0x200A)) { + // canMsg->idByte[0] holds the 0x01 in 0x2001 received can msg + // We use the sub byte of the can ecu msg to determine the corresonding function + // This removes the need for a long if statement giving significant performance boosts + (*ecuCanFuncPtrs[canMsg->idByte[0]])(canMsg); + } +} + +void canProcessRx() +{ + uint8_t retVal = 0; + + noInterrupts(); + canSaveMsg(); + interrupts(); + + noInterrupts(); + while (cirBufferAvailable(&canRxCirBuffer) > 0) { + + CanMsgTemplate canMsg; + + cirBufferRead(&canRxCirBuffer, &canMsg); + +#if DEBUG_CAN_RX + Serial.print("CAN RX: "); + + Serial.print(canMsg.id, HEX); + Serial.print(" : "); + for(uint8_t i = 0; i < 7; i++) { + Serial.print(canMsg.data[i]); + Serial.print(", "); + } + Serial.println(canMsg.data[7]); +#endif // DEBUG_CAN_RX + +#if DEBUG_CAN_RX_MINIMAL + Serial.print("CAN RX : "); + Serial.println(canMsg.id, HEX); +#endif // DEBUG_CAN_RX_MINIMAL + + canParseRxMsg(&canMsg); + + // This may seem dumb but this allows any pending interrupts to be serviced safely + // just before we start another loop. Otherwise if we stay in this loop too long without + // servicing any interrupts we might miss one. + interrupts(); + noInterrupts(); + } + interrupts(); +} + +uint8_t canProcessTx() +{ + + uint8_t retVal = 1; + + noInterrupts(); + while (cirBufferAvailable(&canTxCirBuffer) > 0) { + + CanMsgTemplate canMsg; + + cirBufferRead(&canTxCirBuffer, &canMsg); + +#if DEBUG_CAN_TX + Serial.print("CAN TX: "); + Serial.print(canMsg.id, HEX); + Serial.print(" : "); + for(uint8_t i = 0; i < (canMsg.len - 1); i++) { + Serial.print(canMsg.data[i]); + Serial.print(", "); + } + Serial.println(canMsg.data[canMsg.len - 1]); +#endif // DEBUG_CAN_TX + +#if DEBUG_CAN_TX_MINIMAL + Serial.print("CAN TX : "); + Serial.println(canMsg.id, HEX); +#endif // DEBUG_CAN_TX_MINIMAL + + uint8_t canTxWasSuccessful = 0; + + for (uint8_t i = 0; i < CAN_TX_RETRY_LIMIT; i++) { + if (can.sendMsgBuf(canMsg.id, 1, canMsg.len, + canMsg.data, true) == CAN_OK) { + + canTxWasSuccessful = 1; + + retVal = 1; + + break; + } + else { + retVal = 0; + } + + } + + if (!canTxWasSuccessful) { + +#if DEBUG_CAN_TX || DEBUG_CAN_TX_MINIMAL + Serial.println("CAN TX: TX FAILED"); +#endif // DEBUG_CAN_TX || DEBUG_CAN_TX_MINIMAL + + } + + // This may seem dumb but this allows any pending interrupts to be serviced safely + // just before we start another loop. Otherwise if we stay in this loop too long without + // servicing any interrupts we might miss one. + interrupts(); + noInterrupts(); + } + + interrupts(); + + return retVal; +} + +void canNoActivityResetDevice() +{ + Serial.println("CAN ERROR : RESETTING DEVICE"); + Serial.flush(); + +#if SD_ENABLED + + uint8_t payload[10] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; + + sdAddToWriteBlocks(payload, 10); + + sdWriteBufferBlocks(); + +#endif //SD_ENABLED + + // Enabled watchdog timer to reset device as we will not pat it + wdt_enable(WDTO_15MS); + + while (true); + +} \ No newline at end of file diff --git a/sufst-controller/can.h b/sufst-controller/can.h new file mode 100644 index 0000000000000000000000000000000000000000..4fc862a7e2a9d8c0530414318d27bece992bd68d --- /dev/null +++ b/sufst-controller/can.h @@ -0,0 +1,69 @@ +// +// Created by Sil on 15/07/2019. +// + +#ifndef SUFST_OPENLOGGER_CONTROLLER_CAN_H +#define SUFST_OPENLOGGER_CONTROLLER_CAN_H + +#include "Arduino.h" + +// CAN_INT_PIN MUST BE 2 +#define CAN_INT_PIN 2 +#define CAN_CS_PIN 10 + +#define CAN_RX_BUFFER_LEN 32 +#define CAN_TX_BUFFER_LEN 32 + +#define CAN_RESET_DEVICE_ON_TIMEOUT 0 +#define CAN_NO_MSG_TIMEOUT_RESET_MS 10000 + +#define CAN_TX_RETRY_LIMIT 5 + +#define DEBUG_CAN_RX 0 +#define DEBUG_CAN_RX_MINIMAL 0 + +#define DEBUG_CAN_TX 0 +#define DEBUG_CAN_TX_MINIMAL 0 +#define DEBUG_CAN_TX_REQS 0 + +typedef struct CanMsgTemplate +{ + uint32_t timestamp; + + union + { + uint16_t id; + // if id is 0x2001 then idByte[0] is 0x01 and idByte[1] is 0x20 + // due to the endianness of the system + uint8_t idByte[2]; + }; + + uint8_t len; + + union + { + uint8_t data[8]; + uint16_t data16[4]; + uint32_t data32[2]; + float dataFl[2]; + }; + +}; + +uint8_t canBegin(); + +uint8_t canSaveMsg(); + +uint8_t canAddTxRequest(uint16_t id, void *data, uint8_t lenBytes); + +void canBeginExtInterrupt(); + +void canParseRxMsg(CanMsgTemplate *canMsg); + +void canProcessRx(); + +uint8_t canProcessTx(); + +void canNoActivityResetDevice(); + +#endif //SUFST_OPENLOGGER_CONTROLLER_CAN_H diff --git a/sufst-controller/dashController.cpp b/sufst-controller/dashController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6cff4489eb072f1da24600c5319b49b271f5037 --- /dev/null +++ b/sufst-controller/dashController.cpp @@ -0,0 +1,56 @@ +// +// Created by Sil on 23/07/2019. +// + +#include "dashController.h" + +#define DASH_SERIAL_START_BYTE 0x55 + +struct DashSerialFrame { + uint8_t startByte; + uint16_t waterTemp; + uint16_t rpm; + // uint8_t crc; +} __attribute__((packed)); + +uint16_t gRpm = 0; +uint16_t gWaterTemp = 0; + +void dashBegin() +{ + Serial2.begin(57600); +} + +void dashEcuSetRpm(uint16_t rpm) +{ + + Serial.println(rpm); + + gRpm = rpm; +} + +void dashEcuSetWaterTemp(uint16_t waterTemp) +{ + gWaterTemp = waterTemp; +} + +void dashControllerProcess() +{ + uint32_t currentMs = millis(); + + static uint32_t lastSerialMs = 0; + + if ((currentMs - lastSerialMs) >= DASH_REFRESH_MS) + { + + Serial.println(gRpm); + + DashSerialFrame dashSerialFrame; + dashSerialFrame.startByte = DASH_SERIAL_START_BYTE; + dashSerialFrame.rpm = gRpm; + dashSerialFrame.waterTemp = gWaterTemp; + + Serial2.write((uint8_t *)(&dashSerialFrame), sizeof(DashSerialFrame)); + Serial2.flush(); + } +} diff --git a/sufst-controller/dashController.h b/sufst-controller/dashController.h new file mode 100644 index 0000000000000000000000000000000000000000..9cf21a55c94e9eba5e4e42db396023e20ef8f28b --- /dev/null +++ b/sufst-controller/dashController.h @@ -0,0 +1,17 @@ +// +// Created by Sil on 23/07/2019. +// + +#ifndef DASHCONTROLLER_H +#define DASHCONTROLLER_H + +#include "Arduino.h" + +#define DASH_REFRESH_MS 20 + +void dashBegin(); +void dashEcuSetRpm(uint16_t rpm); +void dashEcuSetWaterTemp(uint16_t waterTemp); +void dashControllerProcess(); + +#endif //DASHCONTROLLER_H diff --git a/sufst-controller/ecuCan.cpp b/sufst-controller/ecuCan.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65e3bd34ec26523e467947275bd7e77150819135 --- /dev/null +++ b/sufst-controller/ecuCan.cpp @@ -0,0 +1,284 @@ +// +// Created by Sil on 7/21/2019. +// + +#include "ecuCan.h" +#include "openLoggerController.h" +#include "ecuOpenloggerTags.h" +#include "dashController.h" + +struct EcuDataOpenlogger +{ + uint8_t startTag; + uint32_t timestamp; + uint16_t data; + uint8_t endTag; +}; + +void ecuOpenloggerWrite(EcuDataOpenlogger *ecuDataOpenlogger); + +void ecuOpenloggerSave(CanMsgTemplate *canMsgTemplate, uint8_t index); + +void ecuOpenloggerWrite(EcuDataOpenlogger &ecuDataOpenlogger) +{ + static uint8_t openloggerPayload[8]; + + memcpy(openloggerPayload, &(ecuDataOpenlogger.startTag), 1); + + memcpy(&(openloggerPayload[1]), &(ecuDataOpenlogger.timestamp), 4); + + memcpy(&(openloggerPayload[5]), &(ecuDataOpenlogger.data), 2); + + memcpy(&(openloggerPayload[7]), &(ecuDataOpenlogger.endTag), 1); + + openloggerWrite(openloggerPayload, 8); +} + +void ecuOpenloggerSave(CanMsgTemplate *canMsg, uint8_t index) +{ + static EcuDataOpenlogger ecuDataOpenlogger; + + uint8_t ecuId = canMsg->idByte[0]; + + uint8_t ecuParamterTag = ecuMsgParameterToOpenloggerTag[ecuId][index]; + + ecuDataOpenlogger.startTag = ecuParamterTag; + + ecuDataOpenlogger.timestamp = canMsg->timestamp; + + ecuDataOpenlogger.data = canMsg->data16[index]; + + ecuDataOpenlogger.endTag = ecuParamterTag; + + ecuOpenloggerWrite(ecuDataOpenlogger); +} + +void ecuCanMsg0x2000(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2000 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2000"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t rpm = canMsg->data16[0]; + uint16_t tpsPerc = canMsg->data16[1]; + uint16_t waterTempC = canMsg->data16[2]; + uint16_t airTempC = canMsg->data16[3]; + +// ecuOpenloggerSave(canMsg, 0); +// ecuOpenloggerSave(canMsg, 1); +// ecuOpenloggerSave(canMsg, 2); + + dashEcuSetRpm(tpsPerc); + dashEcuSetWaterTemp(waterTempC); +} + +void ecuCanMsg0x2001(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2001 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2001"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t mainifoldPresKpa = canMsg->data16[0]; + uint16_t lambdax1000 = canMsg->data16[1]; + uint16_t speedKphx10 = canMsg->data16[2]; + uint16_t oilPressKpa = canMsg->data16[3]; + +// ecuOpenloggerSave(canMsg, 1); +} + +void ecuCanMsg0x2002(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2002 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2002"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t fuelPressKpa = canMsg->data16[0]; + uint16_t oilTempC = canMsg->data16[1]; + uint16_t batteryVx10 = canMsg->data16[2]; + uint16_t fuelComsumLpHrx10 = canMsg->data16[3]; + +// ecuOpenloggerSave(canMsg, 2); + + // Serial.println((float)(batteryVx10 / 10.0)); +} + +void ecuCanMsg0x2003(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2003 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2003"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t currentGear = canMsg->data16[0]; + uint16_t advanceDegx10 = canMsg->data16[1]; + uint16_t injectionTimeMsx100 = canMsg->data16[2]; + uint16_t fuelComsumLp100kMx10 = canMsg->data16[3]; + +// ecuOpenloggerSave(canMsg, 1); +} + +void ecuCanMsg0x2004(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2004 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2004"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t ana1mV = canMsg->data16[0]; + uint16_t ana2mV = canMsg->data16[1]; + uint16_t ana3mV = canMsg->data16[2]; + uint16_t camAdvanceDegx10 = canMsg->data16[3]; + +// ecuOpenloggerSave(canMsg, 3); +} + +void ecuCanMsg0x2005(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2005 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2005"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t camTargDegx10 = canMsg->data16[0]; + uint16_t camPwmPercx10 = canMsg->data16[1]; + uint16_t crankErrorsNr = canMsg->data16[2]; + uint16_t camErrorsNr = canMsg->data16[3]; + +// ecuOpenloggerSave(canMsg, 0); +} + +void ecuCanMsg0x2006(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2006 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2006"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t cam2AdvDegx10 = canMsg->data16[0]; + uint16_t cam2TargDegx10 = canMsg->data16[1]; + uint16_t cam2PwmPercx10 = canMsg->data16[2]; + uint16_t external5VmV = canMsg->data16[3]; +} + +void ecuCanMsg0x2007(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2007 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2007"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t injDutyCyclePerc = canMsg->data16[0]; + uint16_t lambdaPidTargPercx10 = canMsg->data16[1]; + uint16_t lambdaPidAdjPercx10 = canMsg->data16[2]; + uint16_t ecuSwitchesBitField = canMsg->data16[3]; +// +// ecuOpenloggerSave(canMsg, 0); +// ecuOpenloggerSave(canMsg, 1); +// ecuOpenloggerSave(canMsg, 2); +} + +void ecuCanMsg0x2008(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2008 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2008"); +#endif //DEBUG_ECU_CAN_MINIMAL + + uint16_t rdSpeedKphx10 = canMsg->data16[0]; + uint16_t rUdSpeedKphx10 = canMsg->data16[1]; + uint16_t ldSpeedKphx10 = canMsg->data16[2]; + uint16_t lUdSpeedKphx10 = canMsg->data16[3]; +} + +void ecuCanMsg0x2009(CanMsgTemplate *canMsg) +{ +#if DEBUG_ECU_CAN + Serial.print("ECU : 0x2009 : "); + for (uint8_t i = 0; i < 3; i++) { + Serial.print(canMsg->data16[i], HEX); + Serial.print(" , "); + } + Serial.println(canMsg->data16[3], HEX); +#endif //DEBUG_ECU_CAN + +#if DEBUG_ECU_CAN_MINIMAL + Serial.println("ECU : 0x2008"); +#endif //DEBUG_ECU_CAN_MINIMAL + + // uint16_t rightLambdax1000 = canMsg->data16[0]; +} diff --git a/sufst-controller/ecuCan.h b/sufst-controller/ecuCan.h new file mode 100644 index 0000000000000000000000000000000000000000..3e0f98577cbe551131f608da0cd846dffa8ffbb4 --- /dev/null +++ b/sufst-controller/ecuCan.h @@ -0,0 +1,38 @@ +// +// Created by Sil on 7/21/2019. +// + +#ifndef ECUCAN_H +#define ECUCAN_H + +#include "Arduino.h" +#include "can.h" + +/* + * These are called from can.cpp when their corresponding can msg id is seen. + * So functions name *must* ecuCanMsg0x200N. + * + */ + +void ecuCanMsg0x2000(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2001(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2002(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2003(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2004(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2005(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2006(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2007(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2008(CanMsgTemplate *canMsg); + +void ecuCanMsg0x2009(CanMsgTemplate *canMsg); + + +#endif //ECUCAN_H diff --git a/sufst-controller/ecuOpenloggerTags.h b/sufst-controller/ecuOpenloggerTags.h new file mode 100644 index 0000000000000000000000000000000000000000..c0bc6d3e3810f6e4963268e2c2af16033d2d2f84 --- /dev/null +++ b/sufst-controller/ecuOpenloggerTags.h @@ -0,0 +1,19 @@ +// +// Created by Sil on 7/21/2019. +// + +#ifndef ECUOPENLOGGERTAGS_H +#define ECUOPENLOGGERTAGS_H + +uint8_t ecuMsgParameterToOpenloggerTag[8][4] = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}, + {13, 14, 15, 16}, + {17, 18, 19, 20}, + {21, 22, 23, 24}, + {25, 26, 27, 28}, + {29, 30, 31, 32} +}; + +#endif //ECUOPENLOGGERTAGS_H diff --git a/sufst-controller/openLoggerController.cpp b/sufst-controller/openLoggerController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d530acb5318f4ff7451e7cebddbbcddf383edad4 --- /dev/null +++ b/sufst-controller/openLoggerController.cpp @@ -0,0 +1,296 @@ +// +// Created by Sil on 14/07/2019. +// + +#include "openLoggerController.h" +#include "buffer.h" + +enum +{ + uartStartByte = 's', + uartStopByte = 'f' +}; + +enum +{ + uartTypeData = 0, + uartTypeCommand, + uartTypeInfo +}; + +enum +{ + uartCommandStartWrites = 0, + uartCommandStopWrites +}; + +enum +{ + uartInfoAlreadyRunning = 0, + uartInfoAlreadyIdle, + uartInfoWritesStarted, + uartInfoWritesStartError, + uartInfoStopped, + uartInfoStopError, + uartInfoWriteError, + uartInfoWritesNotStarted +}; + +typedef enum +{ + idle = 0, + running, + failedToStart, + failedToStop, + failToWrite +} OpenloggerState; + +typedef enum +{ + checkingForStart = 0, + checkingForType, + checkingForInfo +} OpenloggerUartRxState; + +static uint8_t openloggerTxDataBuffer[OPENLOGGER_TX_BUFFER_LEN]; + +static CirBuffer openloggerTxDataCirBuffer; + +static uint8_t openloggerTxCommandBuffer[OPENLOGGER_TX_COMMAND_BUFFER_LEN]; + +static CirBuffer openloggerTxCommandCirBuffer; + +OpenloggerState openloggerState = idle; + +OpenloggerUartRxState openloggerUartRxState = checkingForStart; + +static bool uartCurrentlyTransmitting = false; + +void openloggerIdle(); + +void openloggerRunning(); + +void openloggerFailedToStart(); + +void openloggerFailedToStop(); + +void openloggerFailedToWrite(); + +void openloggerRxCheckingForStart(); + +void openloggerRxCheckingForType(); + +void openloggerRxCheckingForInfo(); + +/* + * openloggerState_ptrs correspond to INFO packets, so e.g if OPENLOGGER_INFO_WRITES_STARTED (0x02) is seen then + * [2] is called which is openloggerRunning. + */ + +OpenloggerState rxInfoTypeToStateLookup[8] = {running, idle, running, failedToStart, idle, failedToStop, + failToWrite, idle}; + +void (*openloggerState_ptrs[8])(void) = {openloggerIdle, openloggerRunning, + openloggerFailedToStart, openloggerFailedToStop, + openloggerFailedToWrite}; + +void (*openloggerUartRxState_ptrs[3])(void) = {openloggerRxCheckingForStart, openloggerRxCheckingForType, + openloggerRxCheckingForInfo}; + +void serialEvent1() +{ + openloggerUartRxState_ptrs[openloggerUartRxState](); +} + +void openloggerRxCheckingForStart() +{ + +#if DEBUG_OPENLOGGER + Serial.print("OPLOG: CHECKING START "); + Serial.println(Serial1.peek()); +#endif // DEBUG_OPENLOGGER + + if (Serial1.read() == uartStartByte) { + openloggerUartRxState = checkingForType; + } +} + +void openloggerRxCheckingForType() +{ +#if DEBUG_OPENLOGGER + Serial.print("OPLOG: CHECKING FOR TYPE "); + Serial.println(Serial1.peek()); +#endif // DEBUG_OPENLOGGER + + if (Serial1.read() == uartTypeInfo) { + openloggerUartRxState = checkingForInfo; + } + else { + openloggerUartRxState = checkingForStart; + } +} + +void openloggerRxCheckingForInfo() +{ +#if DEBUG_OPENLOGGER + Serial.print("OPLOG: CHECKING FOR INFO "); + Serial.println(Serial1.peek()); +#endif // DEBUG_OPENLOGGER + /* + * The value received from the openlogger dictates what state we are in. + */ + openloggerState = rxInfoTypeToStateLookup[Serial1.read()]; + + openloggerUartRxState = checkingForStart; + +} + +void openloggerIdle() +{ + +} + +void openloggerRunning() +{ + /* + * The uart Tx buffer has a capacity of 64 bytes, if we try to write more than this then Serial.write becomes + * blocking, so we want to avoid this at all costs. + * + */ + + static uint8_t uartTxPayload[64]; + + static uint16_t uartAmountToTransmit = 0; + + static uint32_t uartLastTransmissionMs = millis(); + + uint32_t uartCurrentMs = millis(); + + uint16_t uartTxDataAmount = cirBufferAvailable(&openloggerTxDataCirBuffer); + + if (uartTxDataAmount > 0) { + + if ((uartCurrentMs - uartLastTransmissionMs) >= 5) { + if (Serial1.availableForWrite() >= 35) { + + uint8_t uartTxBytes = (uartTxDataAmount >= 32) ? 32 : uartTxDataAmount; + + Serial1.write(uartStartByte); + Serial1.write(uartTypeData); + Serial1.write(uartTxBytes); + + cirBufferReadBytes(&openloggerTxDataCirBuffer, uartTxPayload, uartTxBytes); + + Serial1.write(uartTxPayload, uartTxBytes); + + uartLastTransmissionMs = millis(); + } + } + } +} + +void openloggerFailedToStart() +{ +#if DEBUG_OPENLOGGER + Serial.println("OPLOG: FAILED TO START"); +#endif // DEBUG_OPENLOGGER + + openloggerState = idle; +} + +void openloggerFailedToStop() +{ +#if DEBUG_OPENLOGGER + Serial.println("OPLOG: FAILED TO STOP"); +#endif // DEBUG_OPENLOGGER + + openloggerState = idle; +} + +void openloggerFailedToWrite() +{ +#if DEBUG_OPENLOGGER + Serial.println("OPLOG: FAILED TO WRITE"); +#endif // DEBUG_OPENLOGGER + + openloggerState = idle; +} + +void openloggerBegin(uint32_t serialBaud) +{ + + Serial1.begin(serialBaud); + + cirBufferBegin(&openloggerTxDataCirBuffer, + openloggerTxDataBuffer, + OPENLOGGER_TX_BUFFER_LEN, + sizeof(uint8_t)); + + cirBufferBegin(&openloggerTxCommandCirBuffer, + openloggerTxCommandBuffer, + OPENLOGGER_TX_COMMAND_BUFFER_LEN, + sizeof(uint8_t)); + +#if DEBUG_OPENLOGGER + Serial.println("OPLOG: BEGIN FINISHED"); +#endif // DEBUG_OPENLOGGER +} + +void openloggerBeginWrites() +{ + openloggerWriteCommand(uartCommandStartWrites); + +#if DEBUG_OPENLOGGER + Serial.println("OPLOG: OPLOG STARTING WRITES"); +#endif // DEBUG_OPENLOGGER +} + +void openloggerStopWrites() +{ + openloggerWriteCommand(uartCommandStopWrites); + +#if DEBUG_OPENLOGGER + Serial.println("OPLOG: OPLOG STOPPING WRITES"); +#endif // DEBUG_OPENLOGGER +} + +void openloggerProcess() +{ + if (!uartCurrentlyTransmitting) { + if (cirBufferAvailable(&openloggerTxCommandCirBuffer) > 0) { + +#if DEBUG_OPENLOGGER + Serial.print("OPLOG: COMMAND "); + Serial.println(*((uint8_t *)cirBufferPeek(&openloggerTxCommandCirBuffer)), HEX); +#endif // DEBUG_OPENLOGGER + + Serial1.write(uartStartByte); + Serial1.write(uartTypeCommand); + Serial1.write(*((uint8_t *) cirBufferExternalRead(&openloggerTxCommandCirBuffer))); + Serial1.flush(); + } + } + + openloggerState_ptrs[openloggerState](); +} + +void openloggerWrite(void *pPayload, uint8_t payloadLen) +{ + + if (openloggerState == running) { + cirBufferWriteBytes(&openloggerTxDataCirBuffer, pPayload, payloadLen); + } +} + +void openloggerWriteCommand(uint8_t command) +{ + +#if DEBUG_OPENLOGGER + Serial.print("OPLOG: APPENDING COMMAND "); + Serial.println(command, HEX); + Serial.flush(); +#endif // DEBUG_OPENLOGGER + + cirBufferWrite(&openloggerTxCommandCirBuffer, &command); + +} diff --git a/sufst-controller/openLoggerController.h b/sufst-controller/openLoggerController.h new file mode 100644 index 0000000000000000000000000000000000000000..fd48ca605dfe165b8f0d885d9a4f2f7005fef928 --- /dev/null +++ b/sufst-controller/openLoggerController.h @@ -0,0 +1,49 @@ +// +// Created by Sil on 14/07/2019. +// + +#ifndef SUFST_OPENLOGGER_INO_SDCARDMASTER_H +#define SUFST_OPENLOGGER_INO_SDCARDMASTER_H + +#include "Arduino.h" + +#define DEBUG_OPENLOGGER 0 + +#define OPENLOGGER_TX_BUFFER_LEN 1024 +#define OPENLOGGER_TX_COMMAND_BUFFER_LEN 8 + +/* + * The serial port is hard coded to serial1 so ensure openlogger is connected to serial1. + * + * There are three types of transactions: save this data, do this command or heres some info. + * + * STRUCTURE OF A VALID SD CARD UART SAVE THIS DATA TRANSACTION + * + * START BYTE | DATA TYPE | LENGTH BYTE | DATA BYTES | STOP BYTE + * + * STRUCTURE OF A VALID COMMAND TRANSACTION + * + * START BYTE | COMMAND TYPE | COMMAND BYTE | STOP BYTE + * + * STUCTURE OF VALID INFO TRANSACTION + * + * START BYTE | INFO TYPE | INFO BYTE | STOP BYTE + * + * If no rx has been received for more than 500ms the rx state is reset to checking for start byte + * This ensures the open logger does not get stuck in the middle of a transaction if the master stops sending data + * + */ +void openloggerBegin(uint32_t serialBaud); + +void openloggerBeginWrites(); + +void openloggerStopWrites(); + +void openloggerProcess(); + +void openloggerWrite(void *pPayload, uint8_t payloadLen); + +void openloggerWriteCommand(uint8_t command); + + +#endif //SUFST_OPENLOGGER_INO_SDCARDMASTER_H diff --git a/sufst-controller/sufst-controller.ino b/sufst-controller/sufst-controller.ino new file mode 100644 index 0000000000000000000000000000000000000000..53ba526bb1e25c95febe66fe3a8133bad34dc92e --- /dev/null +++ b/sufst-controller/sufst-controller.ino @@ -0,0 +1,68 @@ +#define DEBUG_ECU_CAN 0 +#define DEBUG_ECU_CAN_MINIMAL 0 + +#include "openLoggerController.h" +#include "ecuCan.h" +#include "can.h" +#include "dashController.h" + +// Watchdog +#include <avr/wdt.h> + +#define OPENLOGGER_SERIAL_BUAD_RATE 115200 + +uint8_t arduinoProcessSerial(); + +void setup() +{ + // put your setup code here, to run once: + + + // Serial port for host pc communications + Serial.begin(115200); + + Serial.println("BEGIN"); + + dashBegin(); + + // Openlogger runs on uart port TX1 RX1 (Serial1) + //openloggerBegin(OPENLOGGER_SERIAL_BUAD_RATE); + + canBegin(); +} + +void loop() +{ + // put your main code here, to run repeatedly: + + /* + * ALL PROCESSES *MUST* BE NON BLOCKING + */ + //wdt_reset(); + + //openloggerProcess(); + //arduinoProcessSerial(); + canProcessRx(); + dashControllerProcess(); + //canProcessTx(); +} + +uint8_t arduinoProcessSerial() +{ + if (Serial.available()) { + + uint8_t serialByte = Serial.read(); + + switch (serialByte) { + case 'g':openloggerBeginWrites(); + + break; + + case 's':openloggerStopWrites(); + + break; + } + } + + return 1; +} diff --git a/sufst-dash/sufst-dash.ino b/sufst-dash/sufst-dash.ino new file mode 100644 index 0000000000000000000000000000000000000000..c562714f111f9a9f6d2dc613c6b50a896835d981 --- /dev/null +++ b/sufst-dash/sufst-dash.ino @@ -0,0 +1,265 @@ +#define DASH_RPM_LED_RED_1_PIN 2 +#define DASH_RPM_LED_RED_2_PIN 4 +#define DASH_RPM_LED_GREEN_1_PIN 6 +#define DASH_RPM_LED_GREEN_2_PIN 8 +#define DASH_RPM_LED_GREEN_3_PIN 10 +#define DASH_RPM_LED_1_BLUE_PIN 3 +#define DASH_RPM_LED_2_BLUE_PIN 5 +#define DASH_RPM_LED_3_BLUE_PIN 7 +#define DASH_RPM_LED_4_BLUE_PIN 9 +#define DASH_RPM_LED_5_BLUE_PIN 11 + +#define DASH_RPM_SHIFT_FLASH_SWITCH_MS 100 + +#define DASH_RPM_LED_ACTIVE LOW +#define DASH_RPM_LED_NON_ACTIVE HIGH + +#define DASH_WATER_LED_PIN 12 +#define DASH_WATER_LED_ACTIVE LOW +#define DASH_WATER_LED_NON_ACTIVE HIGH + +#define DASH_SERIAL_START_BYTE 0x55 + +#define DASH_RPM_THRESHOLD_1 30 +#define DASH_RPM_THRESHOLD_2 40 +#define DASH_RPM_THRESHOLD_3 50 +#define DASH_RPM_THRESHOLD_4 60 +#define DASH_RPM_THRESHOLD_5 70 +#define DASH_RPM_THRESHOLD_SHIFT 80 + +#define DASH_WATER_C_THRESHOLD 100 + +void dashRpmLedsBegin(); +void dashRpmLedsProcess(); + +bool gShiftFlashState = true; + +struct DashSerialFrame { + uint8_t startByte; + uint16_t waterTemp; + uint16_t rpm; + // uint8_t crc; +} __attribute__((packed)); + +uint16_t gDashRpm = 0; +uint16_t gDashWaterTemp = 0; + +void setup() { + // put your setup code here, to run once: + + Serial.begin(57600); + + dashRpmLedsBegin(); + dashWaterLedBegin(); +} + +void loop() { + // put your main code here, to run repeatedly: + + serialProcess(); + dashRpmLedsProcess(); + dashWaterLedProcess(); +} + +void dashWaterLedBegin() +{ + pinMode(DASH_WATER_LED_PIN, OUTPUT); + + digitalWrite(DASH_WATER_LED_PIN, DASH_WATER_LED_NON_ACTIVE); +} + +void dashRpmLedsBegin() +{ + pinMode(DASH_RPM_LED_RED_1_PIN, OUTPUT); + pinMode(DASH_RPM_LED_RED_2_PIN, OUTPUT); + pinMode(DASH_RPM_LED_GREEN_1_PIN, OUTPUT); + pinMode(DASH_RPM_LED_GREEN_2_PIN, OUTPUT); + pinMode(DASH_RPM_LED_GREEN_3_PIN, OUTPUT); + pinMode(DASH_RPM_LED_1_BLUE_PIN, OUTPUT); + pinMode(DASH_RPM_LED_2_BLUE_PIN, OUTPUT); + pinMode(DASH_RPM_LED_3_BLUE_PIN, OUTPUT); + pinMode(DASH_RPM_LED_4_BLUE_PIN, OUTPUT); + pinMode(DASH_RPM_LED_5_BLUE_PIN, OUTPUT); + + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThreshold0() +{ + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThreshold1() +{ + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThreshold2() +{ + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThreshold3() +{ + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThreshold4() +{ + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThreshold5() +{ + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); +} + +void dashRpmLedsThresholdShift() +{ + uint32_t currentMs = millis(); + + static uint32_t dashShiftLastFlashMs = 0; + + if ((currentMs - dashShiftLastFlashMs) >= DASH_RPM_SHIFT_FLASH_SWITCH_MS) { + gShiftFlashState = !gShiftFlashState; + + dashShiftLastFlashMs = millis(); + } + + if (gShiftFlashState) { + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_ACTIVE); + } + else { + digitalWrite(DASH_RPM_LED_RED_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_RED_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_1_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_2_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_GREEN_3_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_1_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_2_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_3_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_4_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + digitalWrite(DASH_RPM_LED_5_BLUE_PIN, DASH_RPM_LED_NON_ACTIVE); + } +} + +void dashRpmLedsProcess() +{ + if (gDashRpm < DASH_RPM_THRESHOLD_1) { + dashRpmLedsThreshold0(); + } + else if (gDashRpm < DASH_RPM_THRESHOLD_2) { + dashRpmLedsThreshold1(); + } + else if (gDashRpm < DASH_RPM_THRESHOLD_3) { + dashRpmLedsThreshold2(); + } + else if (gDashRpm < DASH_RPM_THRESHOLD_4) { + dashRpmLedsThreshold3(); + } + else if (gDashRpm < DASH_RPM_THRESHOLD_5) { + dashRpmLedsThreshold4(); + } + else if (gDashRpm < DASH_RPM_THRESHOLD_SHIFT) { + dashRpmLedsThreshold5(); + } + else { + dashRpmLedsThresholdShift(); + } +} + +void dashWaterLedProcess() +{ + if (gDashWaterTemp >= DASH_WATER_C_THRESHOLD) { + digitalWrite(DASH_WATER_LED_PIN, DASH_WATER_LED_ACTIVE); + } + else { + digitalWrite(DASH_WATER_LED_PIN, DASH_WATER_LED_NON_ACTIVE); + } +} + +void serialProcess() +{ + DashSerialFrame dashSerialFrame; + + if (Serial.available() >= sizeof(DashSerialFrame)) { + Serial.readBytes((uint8_t *)(&dashSerialFrame), sizeof(DashSerialFrame)); + + if (dashSerialFrame.startByte == DASH_SERIAL_START_BYTE) { + gDashRpm = dashSerialFrame.rpm; + gDashWaterTemp = dashSerialFrame.waterTemp; + } + } +}