You need to sign in or sign up before continuing.
Commit dabc790f authored by Oleg Nikulin's avatar Oleg Nikulin

Контрольная сумма crc16 modbus

parent 5812907a
import serial import serial
import time import time
from crc import Calculator, Crc16
def open_serial(port, baudrate): def open_serial(port, baudrate):
try: #пытаемся открыть serial порт try: #пытаемся открыть serial порт
...@@ -20,14 +21,23 @@ def open_serial(port, baudrate): ...@@ -20,14 +21,23 @@ def open_serial(port, baudrate):
return serial_port return serial_port
#если всё ок, возвращает полученный массив байт
def serial_exchange(serial_port, transmit_bytes, required_response_length, timeout = 1): #если required_response_length == 0, возвращает пустой массив
#если таймаут или не сходится crc, возвращает None
def serial_exchange(serial_port, transmit_array, required_response_length, timeout = 1):
if serial_port is None: if serial_port is None:
raise OSError raise OSError
transmit_bytes = bytearray(transmit_array)
crc_calculator = Calculator(Crc16.MODBUS)
crc16 = crc_calculator.checksum(transmit_bytes)
crc16_bytes = crc16.to_bytes(length=2, byteorder='big')
transmit_bytes += crc16_bytes
serial_port.reset_input_buffer() serial_port.reset_input_buffer()
serial_port.reset_output_buffer() serial_port.reset_output_buffer()
serial_port.write(bytearray(transmit_bytes)) serial_port.write(transmit_bytes)
if required_response_length == 0: if required_response_length == 0:
return bytes([]) return bytes([])
...@@ -42,4 +52,11 @@ def serial_exchange(serial_port, transmit_bytes, required_response_length, timeo ...@@ -42,4 +52,11 @@ def serial_exchange(serial_port, transmit_bytes, required_response_length, timeo
return None return None
response = serial_port.read(required_response_length) response = serial_port.read(required_response_length)
#минимум 1 байт данных + 2 байта crc
if len(response) >= 3:
response_crc16 = int.from_bytes([response[-2], response[-1]], byteorder='big', signed=False)
if not crc_calculator.verify(response[:-2], response_crc16):
return None
return response return response
...@@ -75,18 +75,18 @@ def initialize(serial_port): ...@@ -75,18 +75,18 @@ def initialize(serial_port):
config['controlGroups'][1]['copyFromGroupIndex'], config['controlGroups'][1]['copyFromGroupIndex'],
config['controlGroups'][2]['copyFromGroupIndex'] config['controlGroups'][2]['copyFromGroupIndex']
] ]
response_length = 1 response_length = 3
response = serial_exchange(serial_port, transmit_bytes, response_length, config['arduinoTimeoutSec']) response = serial_exchange(serial_port, transmit_bytes, response_length, config['arduinoTimeoutSec'])
if response is None: if response is None:
print('Initialize failed') print('Initialize no valid response')
else: else:
if response[0] == arduino_response_codes.initialize_ok: if response[0] == arduino_response_codes.initialize_ok:
initialized = True initialized = True
print('Initialize ok') print('Initialize ok')
else: else:
print('Initialize not ok') print('Initialize bad response')
def poll(serial_port): def poll(serial_port):
...@@ -102,12 +102,12 @@ def poll(serial_port): ...@@ -102,12 +102,12 @@ def poll(serial_port):
(temperatures[2] >> 8) & 0xff, (temperatures[2] >> 8) & 0xff,
temperatures[2] & 0xff, temperatures[2] & 0xff,
] ]
response_length = 16 response_length = 18
response = serial_exchange(serial_port, transmit_bytes, response_length, config['arduinoTimeoutSec']) response = serial_exchange(serial_port, transmit_bytes, response_length, config['arduinoTimeoutSec'])
if response is None: if response is None:
initialized = False initialized = False
print('Poll failed') print('Poll no valid response')
else: else:
if response[0] == arduino_response_codes.poll_noinit: if response[0] == arduino_response_codes.poll_noinit:
initialized = False initialized = False
...@@ -128,7 +128,7 @@ def poll(serial_port): ...@@ -128,7 +128,7 @@ def poll(serial_port):
return True return True
else: else:
initialized = False initialized = False
print('Poll not ok') print('Poll bad response')
return False return False
...@@ -164,11 +164,8 @@ if __name__ == "__main__": ...@@ -164,11 +164,8 @@ if __name__ == "__main__":
if baudrate is None: if baudrate is None:
print('Baudrate is not specified (neither in config nor in command line)') print('Baudrate is not specified (neither in config nor in command line)')
exit() exit()
serial_port = open_serial(port, baudrate)
if serial_port is None:
print('Failed to open serial port')
exit()
serial_port = open_serial(port, baudrate)
try: try:
......
//#include <Wire.h>
#define FAN_COUNT 6 //Количество вентиляторов #define FAN_COUNT 6 //Количество вентиляторов
#define CONTROL_COUNT 3 //Количество групп управления #define CONTROL_COUNT 3 //Количество групп управления
#define BAUDRATE 19200 //Скорость serial порта #define BAUDRATE 19200 //Скорость serial порта
...@@ -161,6 +159,71 @@ bool initialized = false; ...@@ -161,6 +159,71 @@ bool initialized = false;
const unsigned short crc16table[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
uint16_t crc16_calc(uint8_t *data, uint16_t len)
{
uint16_t crc = 0xFFFF;
uint8_t nTemp;
while (len--)
{
nTemp = *data++ ^ crc;
crc >>= 8;
crc ^= crc16table[nTemp];
}
return crc;
}
uint8_t add_crc(uint8_t *buf, uint8_t len) {
uint16_t crc16 = crc16_calc(buf, len);
buf[len] = crc16 >> 8;
buf[len+1] = crc16 & 0xff;
len += 2;
return len;
}
uint16_t get_avg_rpm(fan* fan_ptr) { uint16_t get_avg_rpm(fan* fan_ptr) {
uint32_t avg_rpm = 0; uint32_t avg_rpm = 0;
...@@ -174,7 +237,6 @@ uint16_t get_avg_rpm(fan* fan_ptr) { ...@@ -174,7 +237,6 @@ uint16_t get_avg_rpm(fan* fan_ptr) {
void process_command() { void process_command() {
uint8_t cmd_code = 0;
uint8_t cmd_buffer[32] = {}; uint8_t cmd_buffer[32] = {};
uint8_t cmd_length = 0; uint8_t cmd_length = 0;
...@@ -183,16 +245,18 @@ void process_command() { ...@@ -183,16 +245,18 @@ void process_command() {
uint8_t response_length = 1; uint8_t response_length = 1;
//читаем первый байт (код команды) //читаем первый байт (код команды)
if (Serial.readBytes(&cmd_code, 1) == 0) if (Serial.readBytes(cmd_buffer, 1) == 0)
return; return;
//по коду команды понимаем сколько еще байтов надо принять uint8_t cmd_code = cmd_buffer[0];
//по коду команды понимаем длину команды (с учетом байта кода команды и двух байт crc)
switch(cmd_code) { switch(cmd_code) {
case pc_command_codes::initialize: case pc_command_codes::initialize:
cmd_length = 7; cmd_length = 10;
break; break;
case pc_command_codes::poll: case pc_command_codes::poll:
cmd_length = 6; cmd_length = 9;
break; break;
default: default:
break; break;
...@@ -200,38 +264,42 @@ void process_command() { ...@@ -200,38 +264,42 @@ void process_command() {
//читаем команду //читаем команду
if (cmd_length > 0) { if (cmd_length > 0) {
uint8_t bytes_read = Serial.readBytes(cmd_buffer, cmd_length); //принимаем оставшиемся байты
uint8_t bytes_read = Serial.readBytes(&cmd_buffer[1], cmd_length-1);
if (bytes_read == cmd_length-1) {
uint16_t cmd_crc16 = cmd_buffer[cmd_length-2] << 8 | cmd_buffer[cmd_length-1];
uint16_t check_crc16 = crc16_calc(cmd_buffer, cmd_length-2);
if (cmd_crc16 == check_crc16) {
//выполняем команду //выполняем команду
if (bytes_read == cmd_length) {
switch(cmd_code) { switch(cmd_code) {
case pc_command_codes::initialize: case pc_command_codes::initialize:
pc_poll_interval_sec = cmd_buffer[0]; pc_poll_interval_sec = cmd_buffer[1];
control_a.target_temperature = cmd_buffer[1];
control_b.target_temperature = cmd_buffer[2];
control_c.target_temperature = cmd_buffer[3];
control_a.copy_from = cmd_buffer[4]; control_a.target_temperature = cmd_buffer[2];
control_b.copy_from = cmd_buffer[5]; control_b.target_temperature = cmd_buffer[3];
control_c.copy_from = cmd_buffer[6]; control_c.target_temperature = cmd_buffer[4];
control_a.copy_from = cmd_buffer[5];
control_b.copy_from = cmd_buffer[6];
control_c.copy_from = cmd_buffer[7];
initialized = true; initialized = true;
response_buffer[0] = arduino_response_codes::initialize_ok; response_buffer[0] = arduino_response_codes::initialize_ok;
response_length = 1; response_length = 1;
break; break;
case pc_command_codes::poll: case pc_command_codes::poll:
control_a.temperature = cmd_buffer[0] << 8 | cmd_buffer[1]; control_a.temperature = cmd_buffer[1] << 8 | cmd_buffer[2];
control_b.temperature = cmd_buffer[2] << 8 | cmd_buffer[3]; control_b.temperature = cmd_buffer[3] << 8 | cmd_buffer[4];
control_c.temperature = cmd_buffer[4] << 8 | cmd_buffer[5]; control_c.temperature = cmd_buffer[5] << 8 | cmd_buffer[6];
if (initialized) if (initialized)
response_buffer[0] = arduino_response_codes::poll_ok; response_buffer[0] = arduino_response_codes::poll_ok;
else else
response_buffer[0] = arduino_response_codes::poll_noinit; response_buffer[0] = arduino_response_codes::poll_noinit;
for (int i = 0; i < FAN_COUNT; i++){ for (int i = 0; i < FAN_COUNT; i++){
uint16_t rpm = get_avg_rpm(&fans[i]); uint16_t rpm = get_avg_rpm(&fans[i]);
response_buffer[i*2+1] = rpm >> 8; response_buffer[i*2+1] = rpm >> 8;
...@@ -240,23 +308,26 @@ void process_command() { ...@@ -240,23 +308,26 @@ void process_command() {
response_buffer[13] = OCR1A; response_buffer[13] = OCR1A;
response_buffer[14] = OCR2A; response_buffer[14] = OCR2A;
response_buffer[15] = OCR2B; response_buffer[15] = OCR2B;
response_length = 16; response_length = 16;
response_length = add_crc(response_buffer, response_length);
break; break;
default: default:
break; break;
} }
}
last_poll_time = millis(); last_poll_time = millis();
pc_respond = true; pc_respond = true;
} }
}
}
while (Serial.available()) // очистка буфера while (Serial.available()) // очистка буфера
Serial.read(); Serial.read();
//ответ response_length = add_crc(response_buffer, response_length);
Serial.write(response_buffer, response_length); Serial.write(response_buffer, response_length); //посылаем ответ
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment