Как согласовать ответ с запросом на связь RS485 на черном Биглебоне?

#javascript #node.js #beagleboneblack #rs485

Вопрос:

У меня есть Beaglebone black, работающий на Linux Debian с системой связи cape 2 с подключением RS485 (устройство последовательного порта Linux находится в /dev/ttyS1).

У меня нет проблем с тем, чтобы заставить thinks взаимодействовать с устройством BMS (система управления батареей), за исключением того, что его протокол выглядит настолько странно, что я не могу безопасно синхронизировать свои запросы с его ответами.

Позвольте мне погрузиться в протокол, который я разработал: рамка для запроса напряжения, тока и SoC (состояние заряда) 0x90 , и рамка выглядит следующим образом:

<Buffer a5 40 90 08 00 00 00 00 00 00 00 00 cs>

С cs контрольной суммой (совокупная сумма всех байтов, сохраняющая LSB).

13-байтовый ответ выглядит следующим образом:

<Buffer 69 40 86 00 84 00 00 75 30 03 e2 4c 00>

Чтобы декодировать кадр, пропуская 3 первых байта, мы делаем:

  • байт 3, 16-разрядный BE: напряжение, масштаб 0,1 В: 0x0084 = 132 * 0,1 = 13,2 В
  • байт 5, 16-разрядный BE: пропустить
  • байт 7, 16-разрядный BE: текущий, примените смещение 30000, затем масштаб 0.1 A 0x7530 = 30000 — 30000 = 0A
  • байт 8, 16-разрядный BE: SoC, примените масштаб 0,1%: 0x03e2 = 994 * 0,1 = 99,4%

Мой журнал кода выдает следующие значения, которые соответствуют ожидаемым.

Pepsr v2.2.236 4:08:15 PM 📈 [pepsr-olenlab2] -- ✅- 🚜 RS 485: voltageCurrentSoc: { voltage: 13.200000000000001, current: 0, soc: 99.4 }

Пока все хорошо.

Но теперь, поскольку мне нужно гораздо больше данных от BMS, я должен периодически запрашивать больше кадров. Я реализовал систему вопросов и ответов в setInterval() следующем:

 class Rs485 {

    // … blah blah …

    start() {
        
        // == Analyze the received frames
        serialport.on('data',  data => {
                
            // Append data
            this.readingBytes = this.readingBytes.concat(Array.from(data))
            //this.log('data received: ', data, 'as array', Array.from(data), 'length is', this.readingBytes.length)
        
            // Data is OK?
            if (this.readingBytes.length == 13) {
                this.parseMessage(new Buffer.from(this.readingBytes))
                this.readingBytes = []
            }
        })
        
        // == Prepare the next frame to be requested
        this.askFor = 0
        this.askForCount = Object.keys(Rs485.FRAME_TYPE).length
        
        
        const request = () => {
            const key = Object.keys(Rs485.FRAME_TYPE)[this.askFor]
            const type = Rs485.FRAME_TYPE[key]
            //this.log('Now asking for ', this.askFor, 'th type, aka', key, ', value:', type)
            this.request(type)
        }
        
        // == On open…
        this.serialport.on('open', () => {
            this.success('Successfully open')
        
            request()
        })
        
        // == Periodically ask for the next frame type (1Hz)
        setInterval(() => {
            if (!this.serialport.isOpen) {
                this.log("Port Open Status: "   this.serialport.isOpen)
                return
            }
            request()
        },1e3)
    }

}

 

parseMessage() просто делает то, что мы сделали выше, в зависимости от типа кадра.

Как вы можете видеть, я сохраняю текущий запрошенный тип кадра в переменной и предполагаю, что следующий полученный пакет будет ответом на запрос.

Одна вещь, которую, я думаю, я должен прояснить, заключается в том, что я не нашел крючка в заголовке ответа, который я мог бы связать с запросом.

Итак, мой вопрос в том, как я могу улучшить модель коммуникации, чтобы лучше согласовать ответ с запросом?

Комментарии:

1. Какой язык вы используете?

2. Это javascript на nodejs

Ответ №1:

Если вы когда-либо отправляете запросы только одного типа (например, запрос напряжения батареи, тока и SoC), то нет практической необходимости связывать запросы с ответами. Вам может сойти с рук просто отправлять новый запрос каждую секунду, даже не глядя на ответы. Если несколько кадров пропадут или будут повреждены во время передачи, вреда не будет — пока будут поступать последующие ответы, у вас будут свежие данные.

Если вы хотите обнаружить сбой связи в этом решении, запустите таймер при получении ответа (значение таймера зависит от вашей системы — может быть, 10-60 секунд?) и объявите сбой связи, если вы не получили никаких новых ответов до истечения времени ожидания.

Если вы отправляете запросы разных типов, то да, вам нужно запомнить, какой тип запроса был отправлен в последний раз, и дождаться правильного ответа. В этом решении вам нужно запускать таймер с каждым запросом, а затем ждать, пока текущий кадр запроса либо получит соответствующий кадр ответа, либо истечет время ожидания. Не отправляйте новый запрос до того, как это произойдет. Обработайте одну транзакцию запроса-ответа до ее успешного или неудачного завершения, прежде чем начинать новую. Таким образом, любые сбои передачи на линии связи будут пойманы таймаутом, и запросы и ответы не должны выходить из синхронизации. Опять же, значения времени ожидания зависят от вашей системы.