Expose the existing registers through Modbus and service CAN using one GAS provider only in M95M02 builds. Include the EEPROM layout/driver, LOAD protection and calibration, firmware identity and shared CCS build workflow. Add transport/profile and SCI8 validation tests, documentation and the checked M95M02 firmware image.
197 lines
7.9 KiB
C
197 lines
7.9 KiB
C
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#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;
|
|
}
|