modbus rtu pooler

pull/2/head DF07
Mateusz Lubecki 2020-09-18 21:34:25 +02:00
rodzic cadde74d9d
commit 3c96eb2e01
11 zmienionych plików z 342 dodań i 33 usunięć

Wyświetl plik

@ -1,17 +0,0 @@
/*
* rtu_coil_data_t.h
*
* Created on: 28.08.2020
* Author: mateusz
*/
#ifndef INCLUDE_MODBUS_RTU_RTU_COIL_DATA_T_H_
#define INCLUDE_MODBUS_RTU_RTU_COIL_DATA_T_H_
typedef struct rtu_coil_data_t {
uint8_t number_of_coils;
}rtu_coil_data_t;
#endif /* INCLUDE_MODBUS_RTU_RTU_COIL_DATA_T_H_ */

Wyświetl plik

@ -0,0 +1,48 @@
/*
* rtu_crc.h
*
* Created on: 18.09.2020
* Author: mateusz
*/
#ifndef INCLUDE_MODBUS_RTU_RTU_CRC_H_
#define INCLUDE_MODBUS_RTU_RTU_CRC_H_
#include <stdint.h>
inline uint16_t rtu_crc_stream(uint16_t previous_crc, uint8_t current_data) {
int i;
previous_crc ^= (uint16_t)current_data;
for (i = 0; i < 8; ++i) {
if (previous_crc & 1)
previous_crc = (previous_crc) ^ 0xA001;
else
previous_crc = (previous_crc >> 1);
}
return previous_crc;
}
inline uint16_t rtu_crc_buffer(uint8_t* buffer_ptr, uint8_t buffer_ln) {
uint16_t crc = 0xFFFF;
// https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/
for (int pos = 0; pos < buffer_ln; pos++) {
crc ^= (uint16_t)buffer_ptr[pos]; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
}
else // Else LSB is not set
crc >>= 1; // Just shift right
}
}
// Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
return crc;
}
#endif /* INCLUDE_MODBUS_RTU_RTU_CRC_H_ */

Wyświetl plik

@ -8,20 +8,10 @@
#ifndef INCLUDE_MODBUS_RTU_RTU_PARSER_H_
#define INCLUDE_MODBUS_RTU_RTU_PARSER_H_
#include <modbus_rtu/rtu_register_data_t.h>
#include <stdint.h>
inline uint16_t rtu_parser_stream_crc(uint16_t previous_crc, uint8_t current_data) {
int i;
previous_crc ^= (uint16_t)current_data;
for (i = 0; i < 8; ++i) {
if (previous_crc & 1)
previous_crc = (previous_crc) ^ 0xA001;
else
previous_crc = (previous_crc >> 1);
}
return previous_crc;
}
int32_t rtu_parser_03_04_registers(uint8_t* input, uint16_t input_ln, rtu_register_data_t* output);
#endif /* INCLUDE_MODBUS_RTU_RTU_PARSER_H_ */

Wyświetl plik

@ -0,0 +1,30 @@
/*
* rtu_pool_queue_t.h
*
* Created on: 18.09.2020
* Author: mateusz
*/
#ifndef INCLUDE_MODBUS_RTU_RTU_POOL_QUEUE_T_H_
#define INCLUDE_MODBUS_RTU_RTU_POOL_QUEUE_T_H_
#include <stdint.h>
#define RTU_POOL_QUEUE_LENGHT 4
/**
* This type stores the queue of RTU functions to be queued
* with theirs parameters (if there is any)
*/
typedef struct __attribute__((packed)) rtu_pool_queue {
int8_t it;
uint8_t function_id[RTU_POOL_QUEUE_LENGHT];
void* function_parameter[RTU_POOL_QUEUE_LENGHT];
} rtu_pool_queue_t;
#endif /* INCLUDE_MODBUS_RTU_RTU_POOL_QUEUE_T_H_ */

Wyświetl plik

@ -0,0 +1,27 @@
/*
* rtu_coil_data_t.h
*
* Created on: 28.08.2020
* Author: mateusz
*/
#ifndef INCLUDE_MODBUS_RTU_RTU_REGISTER_DATA_T_H_
#define INCLUDE_MODBUS_RTU_RTU_REGISTER_DATA_T_H_
#include <stdint.h>
#define MODBUS_RTU_MAX_REGISTERS_AT_ONCE 16 // according to RTU standard 125
typedef struct __attribute__((packed)) rtu_register_data {
uint16_t slave_address;
uint8_t number_of_registers;
uint16_t base_address;
uint16_t registers_values[MODBUS_RTU_MAX_REGISTERS_AT_ONCE];
}rtu_register_data_t;
#endif /* INCLUDE_MODBUS_RTU_RTU_REGISTER_DATA_T_H_ */

Wyświetl plik

@ -0,0 +1,15 @@
/*
* rtu_request.h
*
* Created on: 18.09.2020
* Author: mateusz
*/
#ifndef INCLUDE_MODBUS_RTU_RTU_REQUEST_H_
#define INCLUDE_MODBUS_RTU_RTU_REQUEST_H_
#include <stdint.h>
int32_t rtu_request_03_04_registers(int8_t input_or_holding, uint8_t* output, uint8_t output_ln, uint8_t slave_address, uint16_t base_register, uint8_t number_of_registers);
#endif /* INCLUDE_MODBUS_RTU_RTU_REQUEST_H_ */

Wyświetl plik

@ -0,0 +1,16 @@
/*
* rtu_return_values.h
*
* Created on: 18.09.2020
* Author: mateusz
*/
#ifndef INCLUDE_MODBUS_RTU_RTU_RETURN_VALUES_H_
#define INCLUDE_MODBUS_RTU_RTU_RETURN_VALUES_H_
#define MODBUS_RET_UNINITIALIZED -1
#define MODBUS_RET_OK 0
#define MODBUS_RET_TOO_SHORT 1
#define MODBUS_RET_WRONG_FUNCTION 2
#endif /* INCLUDE_MODBUS_RTU_RTU_RETURN_VALUES_H_ */

Wyświetl plik

@ -10,12 +10,17 @@
#include <stdint.h>
extern uint16_t rtu_serial_previous_crc;
#include "./drivers/serial.h"
uint8_t rtu_serial_callback(uint8_t current_data, const uint8_t * const rx_buffer, uint16_t rx_bytes_counter);
#include "./modbus_rtu/rtu_pool_queue_t.h"
extern uint16_t rtu_serial_previous_crc;
inline void rtu_serial_reset_crc(void) {
rtu_serial_previous_crc = 0xFFFF;
}
uint8_t rtu_serial_callback(uint8_t current_data, const uint8_t * const rx_buffer, uint16_t rx_bytes_counter);
int32_t rtu_serial_pool(rtu_pool_queue_t* queue, srl_context_t* serial_context);
#endif /* INCLUDE_MODBUS_RTU_RTU_SERIAL_IO_H_ */

Wyświetl plik

@ -6,5 +6,57 @@
*/
#include "./modbus_rtu/rtu_parser.h"
#include "./modbus_rtu/rtu_return_values.h"
#define MODBUS_RTU_MIN_03_04_RESP_LN 7 // one register to read
int32_t rtu_parser_03_04_registers(uint8_t* input, uint16_t input_ln, rtu_register_data_t* output) {
uint32_t retval = MODBUS_RET_UNINITIALIZED;
uint16_t data = 0;
// iterator through input table and registers table
int i = 0, j = 6;
// 7 bytes is the shortest meaningful Modbus RTU frame
// with a value of single register
if (input_ln < MODBUS_RTU_MIN_03_04_RESP_LN) {
retval = MODBUS_RET_TOO_SHORT;
}
else {
// fetch slave address
data = *input << 8 | *(input + 1);
// store slave address
output->slave_address = data;
// fetch function code
data = *(input + 2) << 8 | *(input + 3);
// check if the function code is correct or not
if (data == 0x03 || data == 0x04) {
// fetch the function result lenght in bytes
data = *(input + 4) << 8 | *(input + 5);
// store amount of registers in this response
output->number_of_registers = data / 2;
// get all registers values
for (int i = 0; i < output->number_of_registers && i < MODBUS_RTU_MAX_REGISTERS_AT_ONCE; i++) {
output->registers_values[i] = *(input + j) << 8 | *(input + j + 1);
// moving to next 16bit word with next register
j += 2;
}
}
else {
// if not exit with an error as this isn't
// correct parser for this modbus function
retval = MODBUS_RET_WRONG_FUNCTION;
}
}
return retval;
}

Wyświetl plik

@ -0,0 +1,59 @@
/*
* rtu_request.c
*
* Created on: 18.09.2020
* Author: mateusz
*/
#include <stdarg.h>
#include <string.h>
#include "./modbus_rtu/rtu_request.h"
#include "./modbus_rtu/rtu_return_values.h"
#include "./modbus_rtu/rtu_crc.h"
int32_t rtu_request_03_04_registers(int8_t input_or_holding, uint8_t* output, uint8_t output_ln, uint8_t slave_address, uint16_t base_register, uint8_t number_of_registers) {
int32_t retval = MODBUS_RET_UNINITIALIZED;
uint16_t crc = 0;
// check if there is a room for a RTU frame
if (output == 0x00 || output_ln < 8) {
retval = MODBUS_RET_TOO_SHORT;
}
else {
// initialize the output buffer for RTU binary frame
memset(output, 0x00, output_ln);
// put the slave address
*output = slave_address;
// put the function code
if (input_or_holding == 0) {
*(output + 1) = 0x04;
}
else {
*(output + 1) = 0x03;
}
// put the base address to be read from the slave
*(output + 2) = (base_register & 0xFF00) >> 8;
*(output + 3) = base_register & 0xFF;
// put the numbers of register to be read from slave
*(output + 4) = 0x00; // all in all modbus RTU can transfer no more than 125 at once
*(output + 5) = number_of_registers;
// calculate the CRC from the content
crc = rtu_crc_buffer(output, 6);
// append the crc value
*(output + 6) = (crc & 0xFF00) >> 8;
*(output + 7) = crc & 0xFF;
retval = MODBUS_RET_OK;
}
return retval;
}

Wyświetl plik

@ -6,10 +6,26 @@
*/
#include "modbus_rtu/rtu_serial_io.h"
#include "modbus_rtu/rtu_parser.h"
#include "modbus_rtu/rtu_crc.h"
#include "modbus_rtu/rtu_return_values.h"
#include "modbus_rtu/rtu_register_data_t.h"
#include "modbus_rtu/rtu_request.h"
#include "drivers/serial.h"
#include "main.h"
typedef enum rtu_pool_state {
RTU_POOL_IDLE,
RTU_POOL_TRANSMITTING,
RTU_POOL_RECEIVING,
RTE_POOL_WAIT_AFTER_RECEIVE,
RTU_POOL_RECEIVE_ERROR,
RTU_POOL_STOP
} rtu_pool_state_t;
rtu_pool_state_t rtu_pool = RTU_POOL_STOP;
uint32_t rtu_time_of_last_receive = 0;
/**
* CRC value after the last call to rtu_serial_callback
@ -26,7 +42,7 @@ uint8_t rtu_serial_callback(uint8_t current_data, const uint8_t * const rx_buffe
uint16_t new_crc = 0;
// calculate new crc
new_crc = rtu_parser_stream_crc(rtu_serial_previous_crc, current_data);
new_crc = rtu_crc_stream(rtu_serial_previous_crc, current_data);
// if the new CRC value equals 0x0000 it means that this was MSB
// of CRC from correctly received Modbus-RTU frame
@ -41,4 +57,72 @@ uint8_t rtu_serial_callback(uint8_t current_data, const uint8_t * const rx_buffe
return retval;
}
int32_t rtu_serial_pool(rtu_pool_queue_t* queue, srl_context_t* serial_context) {
int32_t retval = MODBUS_RET_UNINITIALIZED;
int32_t result = MODBUS_RET_UNINITIALIZED;
if (queue->it >= RTU_POOL_QUEUE_LENGHT) {
queue->it = 0;
}
switch (rtu_pool) {
case RTU_POOL_IDLE: {
// check the function it at current queue position
if (queue->function_id[queue->it] == 0x03) {
// read holding registers
// generating request content
result = rtu_request_03_04_registers(
0,
serial_context->srl_tx_buf_pointer,
serial_context->srl_tx_buf_ln,
((rtu_register_data_t*)queue->function_parameter[queue->it])->slave_address,
((rtu_register_data_t*)queue->function_parameter[queue->it])->base_address,
((rtu_register_data_t*)queue->function_parameter[queue->it])->number_of_registers);
// if request has been generated correctly
if (result == MODBUS_RET_OK) {
;
}
else {
;
}
}
else if (queue->function_id[queue->it] == 0x04) {
// read input registers
;
}
else {
// any other unsupported or wrong function id
rtu_pool = RTU_POOL_STOP;
}
break;
}
case RTU_POOL_TRANSMITTING: {
break;
}
case RTU_POOL_RECEIVING: {
break;
}
case RTE_POOL_WAIT_AFTER_RECEIVE: {
break;
}
case RTU_POOL_RECEIVE_ERROR: {
break;
}
case RTU_POOL_STOP: {
break;
}
default: {
rtu_pool = RTU_POOL_STOP;
break;
}
}
return retval;
}