Files
Balsam_167/Source/Internal/gas167.c
Andrey 5d9818291b feat: add M95M02-only GAS and EEPROM profiles
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.
2026-10-09 16:17:37 +03:00

64 lines
2.2 KiB
C

#include "gas167.h"
#if EEPROM_M95M02
#include "package.h"
extern int modbus[];
extern int Desk;
extern void ump_log_rs(void);
static const uint16_t gas167_info[GAS167_INFO_WORDS] = {
0x4741U, 0x5331U, GAS167_PROFILE_VERSION, 167U,
GAS167_REG_BASE, GAS167_REG_COUNT, GAS167_CAPABILITIES, 1U
};
int gas167_contains(uint16_t address)
{
return (uint16_t)(address - GAS167_REG_BASE) < GAS167_REG_COUNT ||
(uint16_t)(address - GAS167_INFO_BASE) < GAS167_INFO_WORDS;
}
static unsigned gas167_write(uint16_t offset, uint16_t value)
{
/* Match the existing native Modbus write policy. These status words
* cannot be overwritten and an invalid timeout cannot bypass protection. */
if (Desk == dsk_LOAD && (offset == 0x7CU || offset == 0x7DU)) return 2;
if (Desk == dsk_LOAD && offset == 0x52U &&
(value == 0U || value > 60000U)) return 3;
/* C28x int is one register word; reads always expose the raw uint16_t. */
modbus[offset] = (int)value;
if (offset == 127U) ump_log_rs();
return 0;
}
unsigned gas167_prepare(unsigned function, uint16_t address, uint16_t value,
int can, uint16_t *reply, unsigned *error)
{
uint16_t offset;
unsigned i, available;
int info;
if (!reply || !error) return 0;
*error = 0;
info = (uint16_t)(address - GAS167_INFO_BASE) < GAS167_INFO_WORDS;
offset = (uint16_t)(address - (info ? GAS167_INFO_BASE : GAS167_REG_BASE));
available = info ? GAS167_INFO_WORDS : GAS167_REG_COUNT;
if (function != 3U && function != 6U) *error = 1;
else if (offset >= available) *error = 2;
else if (function == 6U) {
*error = info ? 2U : gas167_write(offset, value);
} else if (!value || value > GAS167_MAX_WORDS || (can && (value & 1U))) {
*error = 3;
} else if (value > available - offset) {
*error = 2;
} else {
/* Validate the entire block before reading. A block cannot cross a
* region boundary, wrap at 0xFFFF, or leak the hidden parameter word. */
for (i = 0; i < value; ++i)
reply[i] = info ? gas167_info[offset+i] : (uint16_t)modbus[offset+i];
return value;
}
reply[0] = address;
reply[1] = value;
return 2;
}
#endif