#include #include #include #include #include #include "gas167.h" #include "ump_protocol.h" #include "ump_tms28335.h" #include "include/balsam167_eeprom_block.h" #define ANSWER_LEN 128U #define MAX_SEND_LENGTH 400U #define CNTRL_ADDR 16U #define CMD_MODBUS_3 3U #define CMD_MODBUS_6 6U #define dsk_LOAD 6 #define LOBYTE(v) ((v) & 255U) #define HIBYTE(v) (((v) >> 8) & 255U) #define UMP_CAN_MAX_WORDS UMP_MAX_WORDS #define ump_can_prepare ump_tms28335_prepare typedef struct { int all; } WORDE; #define Modbus ((WORDE *)modbus) typedef struct { uint16_t RS_Header[8], buffer[MAX_SEND_LENGTH]; unsigned flag_TIMEOUT_to_Send; } RS_DATA; int modbus[129], Desk = dsk_LOAD; static unsigned captures, spi_reads, sent, irq_depth, legacy_reads; static unsigned __disable_interrupts(void) { unsigned saved = irq_depth; ++irq_depth; return saved; } static void __restore_interrupts(unsigned saved) { irq_depth = saved; } void ump_log_rs(void) { ++captures; } unsigned int ump_log_read(unsigned int address) { ++legacy_reads; return address; } int ump_log_write(unsigned int address, unsigned int value) { return 1; } static unsigned get_crc_16(unsigned seed, const uint16_t *data, unsigned size) { assert(seed == 0xFFFFU); return ump_crc(data, size); } static void RS_Send(RS_DATA *rs, uint16_t *data, unsigned size) { assert(irq_depth == 0); sent = size; } static void Seeprom_read(unsigned long word, uint16_t *data, unsigned bytes) { unsigned i; assert(irq_depth == 0); /* The Timer2 SPI driver must retain interrupts. */ ++spi_reads; for (i = 0; i < bytes/2; ++i) data[i] = (uint16_t)(0xBEEFU+i); } static unsigned Load_protection_prepare(unsigned fn, unsigned a, unsigned n, uint16_t *out, unsigned *error) { out[0] = (uint16_t)a; out[1] = (uint16_t)n; *error = 0; return 2; } struct mock_reg { uint32_t all; }; static struct { struct mock_reg CANTA, CANAA, CANTRR, CANTRS; } ECanaRegs; static struct { struct { struct mock_reg MDH, MDL; } MBOX2; } ECanaMboxes; static struct { unsigned long InterruptCount; } CpuTimer1; #include "production_routes.inc" static void request(RS_DATA *rs, unsigned fn, unsigned a, unsigned n) { unsigned crc; memset(rs, 0, sizeof(*rs)); rs->RS_Header[0] = CNTRL_ADDR; rs->RS_Header[1] = fn; rs->RS_Header[2] = a >> 8; rs->RS_Header[3] = a & 255U; rs->RS_Header[4] = n >> 8; rs->RS_Header[5] = n & 255U; crc = ump_crc(rs->RS_Header, 6); rs->RS_Header[6] = crc & 255U; rs->RS_Header[7] = crc >> 8; sent = 0; if (fn == 3) ReceiveCommandModbus3(rs); else ReceiveCommandModbus6(rs); assert(irq_depth == 0 && rs->flag_TIMEOUT_to_Send); assert(ump_crc(rs->buffer, rs->buffer[1] & 128U ? 5 : (fn == 6 ? 8 : 5+rs->buffer[2])) == 0); } static void can_request(unsigned fn, unsigned a, unsigned n) { memset(&ECanaRegs, 0, sizeof(ECanaRegs)); memset(&ECanaMboxes, 0, sizeof(ECanaMboxes)); ump_can_waiting = 0; ump_can_length = 0; ump_can_index = 0; ump_can_pending = 1; ump_can_tag = 0x0100U | fn; ump_can_address = a; ump_can_value = n; UMP_CAN_service(); assert(irq_depth == 0 && !ump_can_pending); assert(ECanaRegs.CANTRS.all == 4U); } int main(void) { RS_DATA rs; unsigned i; for (i = 0; i < 129; ++i) modbus[i] = (int)i; modbus[128] = 0xD00D; /* Exercise the real native handlers in both builds. */ request(&rs, 6, 1, 0xFEDC); assert(modbus[1] == 0xFEDC && sent == 10); request(&rs, 3, 0, 2); assert(rs.buffer[2] == 4 && rs.buffer[5] == 0xFE && rs.buffer[6] == 0xDC); request(&rs, 6, 0x52, 0); assert(rs.buffer[1] == 0x86 && rs.buffer[2] == 3 && modbus[0x52] == 0x52); request(&rs, 6, 0x7C, 9); assert(rs.buffer[2] == 2 && modbus[0x7C] == 0x7C); /* Existing UMP and protection routing must still work. */ request(&rs, 3, 0x1000, 2); assert(rs.buffer[1] == 3 && rs.buffer[3] == 0x10 && legacy_reads == 2); request(&rs, 3, 0x1300, 2); assert(rs.buffer[1] == 3 && rs.buffer[3] == 0x13); #if EEPROM_M95M02 { uint16_t out[124]; unsigned error, count; for (i = 0; i < 65536U; ++i) assert(gas167_contains((uint16_t)i) == ((i >= 0x5000U && i <= 0x507FU) || (i >= 0x5F00U && i <= 0x5F07U))); assert(gas167_prepare(3, 0x5000, 124, 0, out, &error) == 124 && !error); assert(out[1] == 0xFEDC && out[123] == 123); count = gas167_prepare(3, 0x507F, 2, 0, out, &error); assert(count == 2 && error == 2 && modbus[128] == 0xD00D); assert(gas167_prepare(3, 0x5000, 0, 0, out, &error) == 2 && error == 3); assert(gas167_prepare(3, 0x5000, 125, 0, out, &error) == 2 && error == 3); assert(gas167_prepare(3, 0x5000, 1, 1, out, &error) == 2 && error == 3); assert(gas167_prepare(3, 0xFFFF, 2, 0, out, &error) == 2 && error == 2); assert(gas167_prepare(16, 0x5000, 1, 0, out, &error) == 2 && error == 1); assert(gas167_prepare(6, 0x5080, 7, 0, out, &error) == 2 && error == 2); assert(gas167_prepare(6, 0x5052, 60001, 0, out, &error) == 2 && error == 3); assert(gas167_prepare(6, 0x5052, 60000, 0, out, &error) == 2 && !error); assert(modbus[0x52] == 60000); assert(gas167_prepare(3, 0x5000, 1, 0, 0, &error) == 0); assert(gas167_prepare(6, 0x5000, 1, 0, out, 0) == 0 && modbus[0] == 0); } request(&rs, 3, 0x5000, 2); assert(sent == 9 && rs.buffer[5] == 0xFE && rs.buffer[6] == 0xDC); request(&rs, 3, 0x5000, 124); assert(sent == 253 && rs.buffer[2] == 248); request(&rs, 3, 0x5F00, 8); assert(sent == 21 && rs.buffer[3] == 0x47 && rs.buffer[4] == 0x41); assert(rs.buffer[5] == 0x53 && rs.buffer[6] == 0x31); assert(rs.buffer[10] == 167 && rs.buffer[18] == 1); request(&rs, 6, 0x5F00, 0); assert(sent == 5 && rs.buffer[2] == 2); request(&rs, 3, 0x5F07, 2); assert(rs.buffer[2] == 2); request(&rs, 6, 0x5052, 0); assert(rs.buffer[2] == 3 && modbus[0x52] == 60000); request(&rs, 6, 0x507D, 9); assert(rs.buffer[2] == 2 && modbus[0x7D] == 0x7D); request(&rs, 6, 0x507F, 0x80); assert(sent == 8 && rs.buffer[2] == 0x50 && rs.buffer[3] == 0x7F); assert(captures == 1 && modbus[127] == 0x80); can_request(6, 0x5001, 0xFEDC); assert(modbus[1] == 0xFEDC && ECanaMboxes.MBOX2.MDL.all == 0x5001FEDCUL); assert(ECanaMboxes.MBOX2.MDH.all == 0x1F000100UL); can_request(3, 0x5001, 2); assert(ECanaMboxes.MBOX2.MDL.all == 0xFEDC0002UL); can_request(3, 0x5000, 124); assert(ump_can_length == 124 && ump_can_index == 2); modbus[2] = 777; /* All fragments must retain the original snapshot. */ for (i = 1; i < 62; ++i) { ECanaRegs.CANTA.all = 4; UMP_CAN_service(); assert(ump_can_index == 2*(i+1)); if (i == 1) assert(ECanaMboxes.MBOX2.MDL.all == 0x00020003UL); } modbus[2] = 2; can_request(3, 0x5000, 3); assert(ECanaMboxes.MBOX2.MDH.all == 0x1F000103UL); can_request(6, 0x507C, 9); assert((ECanaMboxes.MBOX2.MDH.all & 255U) == 2 && modbus[0x7C] == 0x7C); can_request(6, 0x507F, 0x40); assert(captures == 2 && modbus[127] == 0x40); can_request(6, 0x5F00, 9); assert((ECanaMboxes.MBOX2.MDH.all & 255U) == 2); request(&rs, 3, 0x8000, 0x8001); #else request(&rs, 3, 0x5000, 2); assert(sent == 5 && rs.buffer[2] == 2); request(&rs, 6, 0x5001, 9); assert(rs.buffer[2] == 2 && modbus[1] == 0xFEDC); request(&rs, 3, 0x5000, 124); assert(sent == 5 && rs.buffer[2] == 2); request(&rs, 3, 0x5F00, 8); assert(rs.buffer[2] == 2); can_request(6, 0x5001, 9); assert((ECanaMboxes.MBOX2.MDH.all & 255U) == 2 && modbus[1] == 0xFEDC); assert(captures == 0); request(&rs, 3, 0x8000, 1); #endif assert(spi_reads == 1 && rs.buffer[3] == 0xBE && rs.buffer[4] == 0xEF); assert(modbus[128] == 0xD00D); printf("PASS GAS167 profile %d: production RTU/CAN routes, guards, CRC and legacy services\n", EEPROM_M95M02); return 0; }