Исправить порядок слов BALZAM CAN и добавить поддержку пульта МПУ

This commit is contained in:
2026-10-02 16:41:25 +03:00
parent a63c1dd7d8
commit 025a3fde28
7 changed files with 74 additions and 21 deletions

View File

@@ -3,7 +3,10 @@
* @brief CAN_Bal_2812 extended-CAN register space.
*
* The wire layout is used by BALZAM Src/balzam_7/CanSetupBalzam7.c:
* one big-endian address/mask word followed by three big-endian register words.
* eCAN MDL precedes MDH on the wire: value2, value3, address/mask, value1.
* Each word is big-endian; address/mask is at bytes 4..5, not 0..1.
* BA000x routes PM -> node; BA001x routes node -> PM.
* The MPU panel uses 745009 / 745019 with the same register layout.
*/
#ifndef BALSAM_CAN_H
#define BALSAM_CAN_H

View File

@@ -104,7 +104,7 @@ object BalsamCanProtocol {
}
val padded = values + List(3 - values.size) { 0 }
val header = (mask shl 13) or startAddress
val data = listOf(header, padded[0], padded[1], padded[2])
val data = listOf(padded[1], padded[2], header, padded[0])
.flatMap { listOf((it ushr 8).toByte(), it.toByte()) }
.toByteArray()
val node = nodes[device - 1]
@@ -131,13 +131,13 @@ object BalsamCanProtocol {
private fun fallbackDecode(canId: Long, data: ByteArray): IntArray {
val relative = (canId and 0x1FFF_FFFFL) - BASE_ID
val header = u16be(data, 0)
val header = u16be(data, 4)
return intArrayOf(
((relative and 0x0F) + 1).toInt(),
if (relative >= 0x10) 1 else 0,
(header ushr 13) and 7,
header and 0x1FFF,
u16be(data, 2), u16be(data, 4), u16be(data, 6),
u16be(data, 6), u16be(data, 0), u16be(data, 2),
)
}

View File

@@ -9,7 +9,7 @@ class BalsamCanProtocolTest {
fun decodesThreeNamedSensorRegisters() {
val frame = requireNotNull(BalsamCanProtocol.decode(
0x00BA_0010L,
byteArrayOf(0xE0.toByte(), 0x18, 0x00, 0x29, 0xFF.toByte(), 0xFE.toByte(), 0x12, 0x34),
byteArrayOf(0xFF.toByte(), 0xFE.toByte(), 0x12, 0x34, 0xE0.toByte(), 0x18, 0x00, 0x29),
))
assertEquals(1, frame.device)
assertEquals(0x18, frame.startAddress)
@@ -28,7 +28,7 @@ class BalsamCanProtocolTest {
)
assertEquals(0x00BA_0002L, wire.canId)
assertEquals(
listOf(0xC0, 0x28, 0x12, 0x34, 0xFE, 0xDC, 0x00, 0x00),
listOf(0xFE, 0xDC, 0x00, 0x00, 0xC0, 0x28, 0x12, 0x34),
wire.data.map { it.toInt() and 0xFF },
)
val decoded = requireNotNull(BalsamCanProtocol.decode(wire.canId, wire.data))

View File

@@ -34,6 +34,8 @@ static size_t indexed_name(const char *prefix, unsigned index,
int balsam_can_is_id(uint32_t can_id)
{
can_id &= 0x1FFFFFFFUL;
if (can_id == 0x00745009UL || can_id == 0x00745019UL) return 1;
uint32_t relative = (can_id & 0x1FFFFFFFUL) - BALSAM_CAN_BASE_ID;
return relative < BALSAM_CAN_NODE_COUNT
|| (relative >= BALSAM_CAN_DATA_OFFSET
@@ -54,12 +56,18 @@ int balsam_can_decode(uint32_t can_id, const uint8_t *data, size_t size,
output->direction = relative >= BALSAM_CAN_DATA_OFFSET
? BALSAM_CAN_FROM_NODE : BALSAM_CAN_TO_NODE;
output->device = (uint8_t)((relative & 0x0FU) + 1U);
header = get_be16(data);
if (can_id == 0x00745009UL || can_id == 0x00745019UL) {
output->device = 10U;
output->direction = can_id == 0x00745019UL
? BALSAM_CAN_FROM_NODE : BALSAM_CAN_TO_NODE;
}
/* eCAN sends MDL before MDH: value2, value3, address/mask, value1. */
header = get_be16(&data[4]);
output->present_mask = (uint8_t)((header >> 13) & 0x07U);
output->start_address = (uint16_t)(header & 0x1FFFU);
output->values[0] = get_be16(&data[2]);
output->values[1] = get_be16(&data[4]);
output->values[2] = get_be16(&data[6]);
output->values[0] = get_be16(&data[6]);
output->values[1] = get_be16(&data[0]);
output->values[2] = get_be16(&data[2]);
return 1;
}
@@ -68,7 +76,7 @@ const char *balsam_can_device_name(uint8_t device)
static const char *const names[BALSAM_CAN_NODE_COUNT] = {
"Трансформатор 1", "Трансформатор 2", "Силовой блок 1",
"Силовой блок 2", "УМП 1", "УМП 2", "Двигатель", "ВЭП",
"Задатчик", "Узел 10", "Узел 11", "Узел 12", "Терминал"
"Задатчик", "Пульт (МПУ)", "Узел 11", "Узел 12", "Терминал"
};
return (device >= 1U && device <= BALSAM_CAN_NODE_COUNT)
? names[device - 1U] : "Неизвестный узел";

View File

@@ -9,7 +9,8 @@
int main(void)
{
const uint8_t packet[8] = { 0xE0, 0x18, 0x00, 0x29, 0xFF, 0xFE, 0x12, 0x34 };
const uint8_t packet[8] = { 0xFF, 0xFE, 0x12, 0x34, 0xE0, 0x18, 0x00, 0x29 };
const uint8_t command[8] = { 0, 0, 0, 0, 0x80, 0x7F, 0, 0x80 };
balsam_can_frame_t frame;
char name[64];
@@ -26,5 +27,13 @@ int main(void)
CHECK(balsam_can_register_name(1U, 0x18U, name, sizeof name) > 0U);
CHECK(strstr(name, "T° 1") != NULL);
CHECK(balsam_can_decode(0x00BA0010UL, packet, 7U, &frame) == -2);
CHECK(balsam_can_decode(0x00BA0004UL, command, 8U, &frame) == 1);
CHECK(frame.device == 5U && frame.direction == BALSAM_CAN_TO_NODE);
CHECK(frame.start_address == 127U && frame.present_mask == 4U);
CHECK(frame.values[0] == 0x80U);
CHECK(balsam_can_decode(0x00745009UL, command, 8U, &frame) == 1);
CHECK(frame.device == 10U && frame.direction == BALSAM_CAN_TO_NODE);
CHECK(balsam_can_decode(0x00745019UL, packet, 8U, &frame) == 1);
CHECK(frame.device == 10U && frame.direction == BALSAM_CAN_FROM_NODE);
return 0;
}