kopia lustrzana https://github.com/SP8EBC/ParaTNC
rodzic
cadde74d9d
commit
3c96eb2e01
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue