diff --git a/include/HUDL/HUDL.hpp b/include/HUDL/HUDL.hpp index 6ed20f3..bd36432 100644 --- a/include/HUDL/HUDL.hpp +++ b/include/HUDL/HUDL.hpp @@ -59,32 +59,122 @@ class HUDL { */ void updateLCD(); -private: /** * reg_select PA_3 * reset PB_3 * cs PB_12 */ DEV::LCD lcd; - uint32_t totalVoltage = 0; - uint32_t thermTemps[4] = {}; + static constexpr uintptr_t TMS_NODE_ID = 0x08; + static constexpr uintptr_t MC_NODE_ID = 0x01; + +private: + enum CurrentPage { + PAGE_1, + ERROR_PAGE + }; + + enum Corner { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT + }; + + CurrentPage currentHUDLScreen = PAGE_1; + bool setHeaders = false; + char* errorString; + + unsigned char evtBitMap[1024] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x18, 0x1F, + 0x1F, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x9F, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x01, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xF8, 0xFE, 0xFF, 0xFF, 0x3F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFB, 0xF8, 0xF8, 0x78, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xFF, 0xFF, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xF3, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFC, 0xFF, 0xFF, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x1F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x9F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, + 0x01, 0x01, 0x00, 0xC0, 0xE0, 0xE0, 0xF0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xF1, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + uint16_t dummyValue = 0; + + uint16_t totalVoltage = 0; + + uint16_t thermTemps[4] = {}; /** The status word provided by the MC node over CAN. Found in the first 16 bits of the 1st PDO coming from the MC. */ uint16_t statusWord = 0; - /** The position actual value provided by the MC node over CAN. Found in the middle 32 bits of the 1st PDO coming from the MC. */ - uint32_t positionActual = 0; - /** The torque actual value provided by the MC node over CAN. Found in the last 16 bits of the 1st PDO coming from the MC. */ + + /** The torque actual value provided by the MC node over CAN. Found in the first 16 bits of the 4th PDO coming from the MC. */ uint16_t torqueActual = 0; - uint16_t velocityActual = 0; + uint16_t actualPosition = 0; - uint32_t rpdo4First32BitsDummyData = 0; + static uint8_t columnForCorner(Corner corner); + static uint8_t pageForCorner(Corner corner); + static uint8_t wrapForCorner(HUDL::Corner corner); - static constexpr uint16_t OBJECT_DICTIONARY_SIZE = 47; - static constexpr uintptr_t TMS_NODE_ID = 0x08; - static constexpr uintptr_t BMS_NODE_ID = 0x05; - static constexpr uintptr_t MC_NODE_ID = 0x01; + void writeError(const char* text); + void headerForCorner(Corner corner, const char* text); + void dataForCorner(Corner corner, const char* text); + + static constexpr uint16_t OBJECT_DICTIONARY_SIZE = 37; CO_OBJ_T objectDictionary[OBJECT_DICTIONARY_SIZE + 1] = { // Sync ID, defaults to 0x80 @@ -139,7 +229,10 @@ class HUDL { }, /** - * RPDO0 settings + * *** START RPDO SETTINGS *** + */ + /** + * TMS RPDO 0 * 0: RPDO number in index and total number of sub indexes. * 1: The COB-ID to receive PDOs from. * 2: transmission trigger @@ -159,9 +252,8 @@ class HUDL { .Type = nullptr, .Data = (uintptr_t) 0xFE, }, - /** - * RPDO1 settings + * Motor Controller RPDO 0 * 0: RPDO number in index and total number of sub indexes. * 1: The COB-ID to receive PDOs from. * 2: transmission trigger @@ -174,16 +266,15 @@ class HUDL { { .Key = CO_KEY(0x1401, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_COBID_TPDO_DEFAULT(1) + TMS_NODE_ID, + .Data = (uintptr_t) CO_COBID_TPDO_DEFAULT(0) + MC_NODE_ID, }, { .Key = CO_KEY(0x1401, 2, CO_UNSIGNED8 | CO_OBJ_D__R_), .Type = nullptr, .Data = (uintptr_t) 0xFE, }, - /** - * RPDO2 settings + * Motor Controller RPDO 1 * 0: RPDO number in index and total number of sub indexes. * 1: The COB-ID to receive PDOs from. * 2: transmission trigger @@ -196,235 +287,154 @@ class HUDL { { .Key = CO_KEY(0x1402, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = (uintptr_t) CO_COBID_TPDO_DEFAULT(0) + BMS_NODE_ID, + .Data = (uintptr_t) CO_COBID_TPDO_DEFAULT(1) + MC_NODE_ID, }, { .Key = CO_KEY(0x1402, 2, CO_UNSIGNED8 | CO_OBJ_D__R_), .Type = nullptr, .Data = (uintptr_t) 0xFE, }, - - /** - * RPDO3 settings - * 0: RPDO number in index and total number of sub indexes. - * 1: The COB-ID to receive PDOs from. - * 2: transmission trigger - */ - { - .Key = CO_KEY(0x1403, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) 3, - }, - { - .Key = CO_KEY(0x1403, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) CO_COBID_TPDO_DEFAULT(0) + MC_NODE_ID, - }, - { - .Key = CO_KEY(0x1403, 2, CO_UNSIGNED8 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) 0xFE, - }, /** - * RPDO4 settings - * 0: RPDO number in index and total number of sub indexes. - * 1: The COB-ID to receive PDOs from. - * 2: transmission trigger - */ - { - .Key = CO_KEY(0x1404, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) 3, - }, - { - .Key = CO_KEY(0x1404, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) CO_COBID_TPDO_DEFAULT(3) + MC_NODE_ID, - }, - { - .Key = CO_KEY(0x1404, 2, CO_UNSIGNED8 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) 0xFE, - }, - - /** - * RPDO0 mapping, determines the PDO messages to receive when RPDO0 is triggered + * TMS RPDO 0 + * Determines the PDO messages to receive when RPDO0 is triggered * 0: The number of PDO message associated with the RPDO - * 1: Link to the first PDO message - tempOne - * 2: Link to the second PDO message - tempTwo + * 1: tempOne + * 2: tempTwo + * 3: tempThree + * 4: tempFour */ { .Key = CO_KEY(0x1600, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), .Type = nullptr, - .Data = (uintptr_t) 2, + .Data = (uintptr_t) 4, }, { .Key = CO_KEY(0x1600, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2100, 0, 32), + .Data = CO_LINK(0x2100, 0, 16),// Temperature One }, { .Key = CO_KEY(0x1600, 2, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2100, 1, 32), - }, - - /** - * RPDO1 mapping, determines the PDO messages to receive when RPDO1 is triggered - * 0: The number of PDO message associated with the RPDO - * 1: Link to the first PDO message - tempThree - * 2: Link to the second PDO message - tempFour - */ - { - .Key = CO_KEY(0x1601, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) 2, + .Data = CO_LINK(0x2100, 1, 16),// Temperature Two }, { - .Key = CO_KEY(0x1601, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1600, 3, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2100, 2, 32), + .Data = CO_LINK(0x2100, 2, 16),// Temperature Three }, { - .Key = CO_KEY(0x1601, 2, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1600, 4, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2100, 3, 32), + .Data = CO_LINK(0x2100, 3, 16),// Temperature Four }, - /** - * RPDO2 mapping, determines the PDO messages to receive when RPDO1 is triggered + * Motor Controller RPDO 1 + * Determines the PDO messages to receive when RPDO3 is triggered * 0: The number of PDO message associated with the RPDO - * 1: Link to the first PDO message - totalVoltage + * 1: statusWord + * 2: positionActual + * 3: torqueActual */ { - .Key = CO_KEY(0x1602, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = (uintptr_t) 1, - }, - { - .Key = CO_KEY(0x1602, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), - .Type = nullptr, - .Data = CO_LINK(0x2101, 0, 32), - }, - - /** - * RPDO3 mapping, determines the PDO messages to receive when RPDO3 is triggered - * 0: The number of PDO message associated with the RPDO - * 1: Link to the first PDO message - statusWord - * 2: Link to the second PD0 message - positionActual - * 3: Link to the third PD0 message - torqueActual - */ - { - .Key = CO_KEY(0x1603, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1601, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), .Type = nullptr, .Data = (uintptr_t) 3, }, { - .Key = CO_KEY(0x1603, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1601, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2103, 0, 16), + .Data = CO_LINK(0x2101, 0, 16), }, { - .Key = CO_KEY(0x1603, 2, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1601, 2, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2103, 1, 32), + .Data = CO_LINK(0x2101, 1, 16), }, { - .Key = CO_KEY(0x1603, 3, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1601, 3, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2103, 2, 16), + .Data = CO_LINK(0x2101, 2, 16), }, - /** - * RPDO4 mapping, determines the PDO messages to receive when RPDO4 is triggered + * Motor Controller RPDO 2 + * Determines the PDO messages to receive when RPDO4 is triggered * 0: The number of PDO message associated with the RPDO - * 1: Link to the first PDO message - empty value - * 2: Link to the second PDO message - velocityActual + * 1: Dummy Value + * 2: Battery Voltage */ { - .Key = CO_KEY(0x1604, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1602, 0, CO_UNSIGNED8 | CO_OBJ_D__R_), .Type = nullptr, .Data = (uintptr_t) 2, }, { - .Key = CO_KEY(0x1604, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1602, 1, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2104, 0, 32), + .Data = CO_LINK(0x2102, 0, 16), }, { - .Key = CO_KEY(0x1604, 2, CO_UNSIGNED32 | CO_OBJ_D__R_), + .Key = CO_KEY(0x1602, 2, CO_UNSIGNED32 | CO_OBJ_D__R_), .Type = nullptr, - .Data = CO_LINK(0x2104, 1, 32), + .Data = CO_LINK(0x2102, 1, 16), }, /** * User defined data. Put elements that can be accessed via SDO * and depending on the configuration PDO */ + /* These data values assign TMU RPDO 0 to the 4 thermal temperatures. */ { - .Key = CO_KEY(0x2100, 0, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2100, 0, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, .Data = (uintptr_t) &thermTemps[0], }, { - .Key = CO_KEY(0x2100, 1, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2100, 1, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, .Data = (uintptr_t) &thermTemps[1], }, { - .Key = CO_KEY(0x2100, 2, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2100, 2, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, .Data = (uintptr_t) &thermTemps[2], }, { - .Key = CO_KEY(0x2100, 3, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2100, 3, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, .Data = (uintptr_t) &thermTemps[3], }, + /* These data values assign Motor Controller RPDO 0 to Status Word, Actual Position, and Torque Actual. */ { - .Key = CO_KEY(0x2101, 0, CO_UNSIGNED32 | CO_OBJ___PRW), - .Type = nullptr, - .Data = (uintptr_t) &totalVoltage, - }, - { - .Key = CO_KEY(0x2103, 0, CO_UNSIGNED16 | CO_OBJ___PRW), + .Key = CO_KEY(0x2101, 0, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, .Data = (uintptr_t) &statusWord, }, { - .Key = CO_KEY(0x2103, 1, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2101, 1, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, - .Data = (uintptr_t) &positionActual, + .Data = (uintptr_t) &actualPosition, }, { - .Key = CO_KEY(0x2103, 2, CO_UNSIGNED16 | CO_OBJ___PRW), + .Key = CO_KEY(0x2101, 2, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, .Data = (uintptr_t) &torqueActual, }, + /* These data values assign Motor Controller RPDO 1 to the Total Voltage, and then a dummy value. */ { - .Key = CO_KEY(0x2104, 0, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2102, 0, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, - .Data = (uintptr_t) &rpdo4First32BitsDummyData, + .Data = (uintptr_t) &dummyValue, }, { - .Key = CO_KEY(0x2104, 1, CO_UNSIGNED32 | CO_OBJ___PRW), + .Key = CO_KEY(0x2102, 1, CO_UNSIGNED16 | CO_OBJ___PRW), .Type = nullptr, - .Data = (uintptr_t) &velocityActual, + .Data = (uintptr_t) &totalVoltage, }, + CO_OBJ_DIR_ENDMARK, }; - - static constexpr char* SECTION_TITLES[9]{ - "B Voltage", - "Velocity", - "RPM", - "Temp 1", - "Temp 2", - "Temp 3", - "MC Stat", - "Position", - "Torque"}; }; }// namespace HUDL -#endif +#endif \ No newline at end of file diff --git a/libs/EVT-core b/libs/EVT-core index 73d53c7..4ff082a 160000 --- a/libs/EVT-core +++ b/libs/EVT-core @@ -1 +1 @@ -Subproject commit 73d53c7d7a0e353aba265791e33bc10395baf0e3 +Subproject commit 4ff082a8665ed0a3bc1b53c5964bcbc9ff26b199 diff --git a/src/HUDL/HUDL.cpp b/src/HUDL/HUDL.cpp index e08dc71..7fd6021 100644 --- a/src/HUDL/HUDL.cpp +++ b/src/HUDL/HUDL.cpp @@ -1,8 +1,8 @@ /** - * This is a basic sample of using the UART module. The program provides a - * basic echo functionality where the uart will write back whatever the user - * enters. - */ +* This is a basic sample of using the UART module. The program provides a +* basic echo functionality where the uart will write back whatever the user +* enters. +*/ // clang-format off #include @@ -11,6 +11,8 @@ #include #include #include +#include +#include "EVT/dev/BitmapFonts.hpp" // clang-format on namespace IO = EVT::core::IO; @@ -23,8 +25,11 @@ HUDL::HUDL(IO::GPIO& reg_select, IO::GPIO& reset, IO::SPI& spi) : lcd(DEV::LCD(r void HUDL::initLCD() { lcd.initLCD(); lcd.clearLCD(); - lcd.setDefaultSections(SECTION_TITLES); - lcd.displaySectionHeaders(); + lcd.setEntireScreenBitMap(evtBitMap); + EVT::core::time::wait(2000); + lcd.clearLCD(); + // lcd.setDefaultSections(SECTION_TITLES); + // lcd.displaySectionHeaders(); } CO_OBJ_T* HUDL::getObjectDictionary() { @@ -36,46 +41,140 @@ uint16_t HUDL::getObjectDictionarySize() const { } void HUDL::updateLCD() { - char temps[32][4]; - for (int i = 0; i < sizeof(thermTemps) / sizeof(uint32_t); i++) { - std::sprintf(temps[i], "%d C", thermTemps[i]); + switch (currentHUDLScreen) { + case PAGE_1: {// Set a new scope for this case + if (!setHeaders) { + lcd.clearLCD(); + headerForCorner(TOP_LEFT, "Battery"); + headerForCorner(TOP_RIGHT, "HI Temp"); + headerForCorner(BOTTOM_LEFT, "RPM"); + headerForCorner(BOTTOM_RIGHT, "MC Stat"); + setHeaders = true; + } + + // Set the battery voltage + char voltage[9]; + std::sprintf(voltage, "%hu.%hu v", totalVoltage / 10, totalVoltage % 10); + dataForCorner(TOP_LEFT, voltage); + + // Set the highest temp + uint16_t highestTemp = thermTemps[0]; + for (uint16_t temp : thermTemps) { + if (temp > highestTemp) { + highestTemp = temp; + } + } + char temp[9]; + std::sprintf(temp, "%hu.%hu C", thermTemps[0] / 100, thermTemps[0] % 100); + + dataForCorner(TOP_RIGHT, temp); + + // Set the rpm + char rpm[8]; + std::sprintf(rpm, "%lu", actualPosition); + dataForCorner(BOTTOM_LEFT, rpm); + + // Set the status word + char status[8]; + + if (statusWord == 0x21) { + std::sprintf(status, "STOP"); + } else if (statusWord == 0x27) { + std::sprintf(status, "GO"); + } else { + std::sprintf(status, "UNKNOWN"); + // std::sprintf(errorString, "There was an error with the Motor Controller: Unknown Error %x", statusWord); + // currentHUDLScreen = ERROR_PAGE; + } + + dataForCorner(BOTTOM_RIGHT, status); + } break; + case ERROR_PAGE: {// Set a new scope for this page + if (!setHeaders) { + lcd.clearLCD(); + } + writeError(errorString); + break; + } } +} - char voltage[32]; - std::sprintf(voltage, "%d v", totalVoltage); +void HUDL::headerForCorner(HUDL::Corner corner, const char* text) { + // Clear the sections area so text is not written over old text. + uint8_t sectionColumn = columnForCorner(corner); + uint8_t sectionPage = pageForCorner(corner); - char status[32]; - std::sprintf(status, "0x%X", statusWord); + lcd.clearArea(64, 2, sectionPage, sectionColumn); - char position[32]; - std::sprintf(position, "0x%X", positionActual); + // Calculate the padding to center the text in the section + uint8_t length = strlen(text) * 8; + uint8_t padding = (64 - length) / 2; - char torque[32]; - std::sprintf(torque, "0x%X", torqueActual); + sectionColumn += padding; + + // Write the text to the screen under the section header. + lcd.writeLargeText(text, sectionPage, sectionColumn, false); +} - char velocity[32]; - std::sprintf(velocity, "0x%X", velocityActual); +void HUDL::dataForCorner(HUDL::Corner corner, const char* text) { + // Clear the sections area so text is not written over old text. + uint8_t sectionColumn = columnForCorner(corner); + uint8_t sectionPage = pageForCorner(corner) + 2; - lcd.setTextForSection(0, voltage); - lcd.setTextForSection(1, velocity); - lcd.setTextForSection(2, "3000"); - lcd.setTextForSection(3, temps[0]); - lcd.setTextForSection(4, temps[1]); - lcd.setTextForSection(5, temps[2]); - lcd.setTextForSection(6, status); - lcd.setTextForSection(7, position); - lcd.setTextForSection(8, torque); + lcd.clearArea(64, 2, sectionPage, sectionColumn); + + // Calculate the padding to center the text in the section + uint8_t length = strlen(text) * 8; + uint8_t padding = (64 - length) / 2; + + sectionColumn += padding; + + // Write the text to the screen under the section header. + lcd.writeLargeText(text, sectionPage, sectionColumn, false); +} - for (int i = 0; i < sizeof(thermTemps) / sizeof(uint32_t); i++) { - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Temp %d: %d\n\r", i, thermTemps[i]); +void HUDL::writeError(const char* text) { + // Calculate the padding to center the text in the section + uint8_t length = strlen("!!! Error !!!") * 8; + uint8_t padding = (128 - length) / 2; + + // Write the Error header + lcd.writeLargeText("!!! Error !!!", 0, padding, false); + + // Write the error message + lcd.writeSmallText(text, 2, 0, true); +} + +uint8_t HUDL::columnForCorner(HUDL::Corner corner) { + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + return 0; + case TOP_RIGHT: + case BOTTOM_RIGHT: + return 64; } - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Total Voltage: %d\n\r", totalVoltage); +} - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Status Word: 0x%X\n\r", statusWord); - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Position Actual: 0x%X\n\r", positionActual); - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Torque Actual: 0x%X\n\r", torqueActual); - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Velocity Value: 0x%X\n\r", velocityActual); - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Dummy Data: 0x%X\n\r", rpdo4First32BitsDummyData); +uint8_t HUDL::wrapForCorner(HUDL::Corner corner) { + switch (corner) { + case TOP_LEFT: + case BOTTOM_LEFT: + return 64; + case TOP_RIGHT: + case BOTTOM_RIGHT: + return 128; + } } +uint8_t HUDL::pageForCorner(HUDL::Corner corner) { + switch (corner) { + case TOP_LEFT: + case TOP_RIGHT: + return 0; + case BOTTOM_LEFT: + case BOTTOM_RIGHT: + return 4; + } +} }// namespace HUDL diff --git a/targets/HUDL/main.cpp b/targets/HUDL/main.cpp index 606f987..7d4e34f 100644 --- a/targets/HUDL/main.cpp +++ b/targets/HUDL/main.cpp @@ -2,20 +2,18 @@ * This is the main code running on the HUDL responsible for displaying * information that other boards that broadcast through the CAN network */ -#include - #include #include #include #include #include -#include #include +#include #include #include -#include #include +#include namespace IO = EVT::core::IO; namespace DEV = EVT::core::DEV; @@ -47,17 +45,17 @@ void canInterrupt(IO::CANMessage& message, void* priv) { EVT::core::types::FixedQueue* queue = (EVT::core::types::FixedQueue*) priv; - // Log raw received data - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Got RAW message from %X of length %d with data: ", message.getId(), message.getDataLength()); - - uint8_t* data = message.getPayload(); - for (int i = 0; i < message.getDataLength(); i++) { - log::LOGGER.log(log::Logger::LogLevel::DEBUG, "%X ", *data); - data++; - } - - if (queue != nullptr) + // // Log raw received data + // log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Got RAW message from %X of length %d with data: ", message.getId(), message.getDataLength()); + // + // uint8_t* data = message.getPayload(); + // for (int i = 0; i < message.getDataLength(); i++) { + // log::LOGGER.log(log::Logger::LogLevel::DEBUG, "%X ", *data); + // data++; + // } + if (queue != nullptr) { queue->append(message); + } } /////////////////////////////////////////////////////////////////////////////// @@ -89,32 +87,56 @@ extern "C" void COTmrLock(void) {} extern "C" void COTmrUnlock(void) {} +extern "C" void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef* hcan) { + log::LOGGER.log(log::Logger::LogLevel::DEBUG, "RX Full"); +} + int main() { // Initialize system - IO::init(); + EVT::core::platform::init(); // Will store CANopen messages that will be populated by the EVT-core CAN // interrupt - EVT::core::types::FixedQueue canOpenQueue; + auto canOpenQueue = EVT::core::types::FixedQueue(true); // Initialize CAN, add an IRQ which will add messages to the queue above IO::CAN& can = IO::getCAN(); can.addIRQHandler(canInterrupt, reinterpret_cast(&canOpenQueue)); // Initialize the timer - DEV::Timerf302x8 timer(TIM2, 100); - timer.stopTimer(); + DEV::Timerf3xx timer(TIM2, 160); //create the RPDO node IO::GPIO* devices[deviceCount]; IO::GPIO& regSelect = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); - IO::GPIO& reset = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + // HUDL 1.0 + // IO::GPIO& reset = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + // devices[0] = &IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + // HUDL 1.1 + // IO::GPIO& reset = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + // devices[0] = &IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + // HUDL 1.2 + IO::GPIO& reset = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); devices[0] = &IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + devices[0]->writePin(IO::GPIO::State::HIGH); + // auto& hudl_spi = IO::getSPI( + // devices, deviceCount); auto& hudl_spi = IO::getSPI( devices, deviceCount); + IO::PWM& brightness = IO::getPWM(); + brightness.setPeriod(1); + brightness.setDutyCycle(100); + + /* + IO::GPIO& regSelect = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + IO::GPIO& reset = IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + devices[0] = &IO::getGPIO(EVT::core::IO::GPIO::Direction::OUTPUT); + devices[0]->writePin(IO::GPIO::State::HIGH); + */ + hudl_spi.configureSPI(SPI_SPEED, SPI_MODE0, SPI_MSB_FIRST); HUDL::HUDL hudl(regSelect, reset, hudl_spi); @@ -126,10 +148,14 @@ int main() { // Attempt to join the CAN network IO::CAN::CANStatus result = can.connect(); + // Adds can filtering to only allow messages from IDs 1, 5, and 8. + can.addCANFilter(0x1, 0b00001111111, 0); + can.addCANFilter(0x8, 0b00001111111, 1); + can.addCANFilter(0x5, 0b00001111111, 2); + //test that the board is connected to the can network if (result != IO::CAN::CANStatus::OK) { log::LOGGER.log(log::Logger::LogLevel::ERROR, "Failed to connect to CAN network\r\n"); - return 1; } else { log::LOGGER.log(log::Logger::LogLevel::INFO, "Connected to CAN network\r\n"); @@ -168,7 +194,7 @@ int main() { .EmcyCode = NULL, .TmrMem = appTmrMem, .TmrNum = 16, - .TmrFreq = 100, + .TmrFreq = 1, .Drv = &canStackDriver, .SdoBuf = reinterpret_cast(&sdoBuffer[0]), }; @@ -185,9 +211,14 @@ int main() { log::LOGGER.log(log::Logger::LogLevel::DEBUG, "Error: %d\r\n", CONodeGetErr(&canNode)); hudl.initLCD(); - - while (1) { - hudl.updateLCD(); + uint8_t displayCounter = 0; + while (true) { + if (displayCounter >= 100) { + displayCounter = 0; + hudl.updateLCD(); + } else { + displayCounter++; + } CONodeProcess(&canNode); // Update the state of timer based events @@ -195,6 +226,6 @@ int main() { // Handle executing timer events that have elapsed COTmrProcess(&canNode.Tmr); // Wait for new data to come in - time::wait(100); + // time::wait(10); } }