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,63 +264,70 @@ void process_command() { ...@@ -200,63 +264,70 @@ 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) { if (bytes_read == cmd_length-1) {
switch(cmd_code) { uint16_t cmd_crc16 = cmd_buffer[cmd_length-2] << 8 | cmd_buffer[cmd_length-1];
case pc_command_codes::initialize: uint16_t check_crc16 = crc16_calc(cmd_buffer, cmd_length-2);
pc_poll_interval_sec = cmd_buffer[0];
if (cmd_crc16 == check_crc16) {
control_a.target_temperature = cmd_buffer[1]; //выполняем команду
control_b.target_temperature = cmd_buffer[2]; switch(cmd_code) {
control_c.target_temperature = cmd_buffer[3]; case pc_command_codes::initialize:
pc_poll_interval_sec = cmd_buffer[1];
control_a.copy_from = cmd_buffer[4];
control_b.copy_from = cmd_buffer[5]; control_a.target_temperature = cmd_buffer[2];
control_c.copy_from = cmd_buffer[6]; control_b.target_temperature = cmd_buffer[3];
control_c.target_temperature = cmd_buffer[4];
initialized = true; control_a.copy_from = cmd_buffer[5];
control_b.copy_from = cmd_buffer[6];
response_buffer[0] = arduino_response_codes::initialize_ok; control_c.copy_from = cmd_buffer[7];
response_length = 1;
break; initialized = true;
case pc_command_codes::poll: response_buffer[0] = arduino_response_codes::initialize_ok;
control_a.temperature = cmd_buffer[0] << 8 | cmd_buffer[1];
control_b.temperature = cmd_buffer[2] << 8 | cmd_buffer[3]; response_length = 1;
control_c.temperature = cmd_buffer[4] << 8 | cmd_buffer[5]; break;
if (initialized) case pc_command_codes::poll:
response_buffer[0] = arduino_response_codes::poll_ok; control_a.temperature = cmd_buffer[1] << 8 | cmd_buffer[2];
else control_b.temperature = cmd_buffer[3] << 8 | cmd_buffer[4];
response_buffer[0] = arduino_response_codes::poll_noinit; control_c.temperature = cmd_buffer[5] << 8 | cmd_buffer[6];
for (int i = 0; i < FAN_COUNT; i++){ if (initialized)
uint16_t rpm = get_avg_rpm(&fans[i]); response_buffer[0] = arduino_response_codes::poll_ok;
response_buffer[i*2+1] = rpm >> 8; else
response_buffer[i*2+2] = rpm & 0xff; response_buffer[0] = arduino_response_codes::poll_noinit;
} for (int i = 0; i < FAN_COUNT; i++){
response_buffer[13] = OCR1A; uint16_t rpm = get_avg_rpm(&fans[i]);
response_buffer[14] = OCR2A; response_buffer[i*2+1] = rpm >> 8;
response_buffer[15] = OCR2B; response_buffer[i*2+2] = rpm & 0xff;
response_length = 16; }
break; response_buffer[13] = OCR1A;
response_buffer[14] = OCR2A;
default: response_buffer[15] = OCR2B;
break;
response_length = 16;
response_length = add_crc(response_buffer, response_length);
break;
default:
break;
}
last_poll_time = millis();
pc_respond = true;
} }
} }
last_poll_time = millis();
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