few more bugfixes in serial driver and serial crc callback for modbus rtu

pull/2/head
Mateusz Lubecki 2020-09-26 21:03:28 +02:00
rodzic 4756d9c341
commit 3a55ebadcb
8 zmienionych plików z 158 dodań i 50 usunięć

Wyświetl plik

@ -5,7 +5,7 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="-231650764009955027" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="-229988544573987027" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
@ -16,7 +16,7 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="-267504706212265789" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="-265842486776297789" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>

Wyświetl plik

@ -87,6 +87,8 @@ void SysTick_Handler(void) {
srl_keep_timeout(main_kiss_srl_ctx_ptr);
srl_keep_timeout(main_wx_srl_ctx_ptr);
srl_keep_tx_delay(main_wx_srl_ctx_ptr);
i2cKeepTimeout();
delay_decrement_counter();

Wyświetl plik

@ -349,6 +349,7 @@ int main(int argc, char* argv[]){
srl_init(main_kiss_srl_ctx_ptr, USART1, srl_usart1_rx_buffer, RX_BUFFER_1_LN, srl_usart1_tx_buffer, TX_BUFFER_1_LN, main_target_kiss_baudrate, 1);
srl_init(main_wx_srl_ctx_ptr, USART2, srl_usart2_rx_buffer, RX_BUFFER_2_LN, srl_usart2_tx_buffer, TX_BUFFER_2_LN, main_target_wx_baudrate, _RTU_SLAVE_STOP_BITS);
srl_switch_tx_delay(main_wx_srl_ctx_ptr, 1);
main_modbus_rtu_master_enabled = 1;

Wyświetl plik

@ -14,6 +14,7 @@
#define SEPARATE_RX_BUFF
#define SEPARATE_TX_BUFF
#define SRL_TX_DELAY_IN_MS 10
#define SRL_DEFAULT_RX_TIMEOUT_IN_MS 400
#define SRL_TIMEOUT_ENABLE 1
@ -33,10 +34,17 @@ typedef enum srlRxState {
typedef enum srlTxState {
SRL_TX_NOT_CONFIG,
SRL_TX_IDLE,
SRL_TX_WAITING,
SRL_TXING,
SRL_TX_ERROR
}srl_tx_state_t;
typedef enum srl_timeout_mode {
SRL_TIMEOUT_OFF,
SRL_TIMEOUT_INSTANT,
SRL_TIMEOUT_TRIGGERED
}srl_timeout_mode_t;
typedef struct srl_context_t {
USART_TypeDef *port;
@ -58,9 +66,11 @@ typedef struct srl_context_t {
uint8_t srl_triggered_start;
uint8_t srl_triggered_stop;
uint8_t srl_start_trigger; // znak oznaczaj<61>cy pocz<63>tek istotnych danych do odbebrania
uint8_t srl_stop_trigger; // znak oznaczaj<61>cy koniec istotnych danych do odebrania
uint8_t srl_start_trigger;
uint8_t srl_stop_trigger;
// temporary storage for reading the 'DR' register during waiting for the first byte
// of the protocol data to be received
volatile uint8_t srl_garbage_storage;
uint8_t srl_rx_timeout_enable;
@ -71,6 +81,15 @@ typedef struct srl_context_t {
uint32_t srl_rx_start_time;
uint32_t srl_rx_waiting_start_time;
// this is a time when srl_start_tx or srl_send_data initiated the transfer. If this is set to 0xFFFFFFFF
// the transmission will start immediately. If it is set to any other value the transmission
// (first and any consecutive byte) will be delayed by value defined by 'SRL_TX_DELAY_IN_MS'.
//
// This is a workaround of garbage occurring on RS485 bus when TE/RE pin of MAX485 is switched.
// A delay will separate this artificial 0xFF (when TE/RE are switched) from the rest of data
// what should make Modbus-RTU working again -> this 0xFF will be ignored.
uint32_t srl_tx_start_time;
srl_rx_state_t srl_rx_state;
srl_tx_state_t srl_tx_state;
@ -129,6 +148,8 @@ uint8_t srl_receive_data_with_instant_timeout(srl_context_t *ctx, int num, char
uint8_t srl_receive_data_with_callback(srl_context_t *ctx, srl_rx_termination_callback_t cbk);
uint16_t srl_get_num_bytes_rxed(srl_context_t *ctx);
uint8_t* srl_get_rx_buffer(srl_context_t *ctx);
void srl_keep_tx_delay(srl_context_t *ctx);
void srl_switch_tx_delay(srl_context_t *ctx, uint8_t disable_enable);
void srl_keep_timeout(srl_context_t *ctx);
void srl_switch_timeout(srl_context_t *ctx, uint8_t disable_enable, uint32_t value);
void srl_switch_timeout_for_waiting(srl_context_t *ctx, uint8_t disable_enable);

Wyświetl plik

@ -15,8 +15,10 @@ inline uint16_t rtu_crc_stream(uint16_t previous_crc, uint8_t current_data) {
previous_crc ^= (uint16_t)current_data;
for (i = 0; i < 8; ++i) {
if (previous_crc & 1)
if (previous_crc & 1) {
previous_crc = (previous_crc >> 1);
previous_crc = (previous_crc) ^ 0xA001;
}
else
previous_crc = (previous_crc >> 1);
}

Wyświetl plik

@ -8,23 +8,21 @@
#include <string.h>
int srlBRRegValue = 0x09C4 ; // dla symulacji ---- baudrate 9600bps
//int SrlBRRegValue = 0x0209; // dla realnego uk<75><6B>du
#ifdef SEPARATE_TX_BUFF
uint8_t srl_usart1_tx_buffer[TX_BUFFER_1_LN] = {'\0'}; // dane do wys<79>ania do zdalnego urz<72>dzenia
uint8_t srl_usart1_tx_buffer[TX_BUFFER_1_LN] = {'\0'};
#endif
#ifdef SEPARATE_RX_BUFF
uint8_t srl_usart1_rx_buffer[RX_BUFFER_1_LN] = {'\0'}; // dane odebrane od zdalnego urz<72>dzenia
uint8_t srl_usart1_rx_buffer[RX_BUFFER_1_LN] = {'\0'};
#endif
#ifdef SEPARATE_TX_BUFF
uint8_t srl_usart2_tx_buffer[TX_BUFFER_2_LN] = {'\0'}; // dane do wys<79>ania do zdalnego urz<72>dzenia
uint8_t srl_usart2_tx_buffer[TX_BUFFER_2_LN] = {'\0'};
#endif
#ifdef SEPARATE_RX_BUFF
uint8_t srl_usart2_rx_buffer[RX_BUFFER_2_LN] = {'\0'}; // dane odebrane od zdalnego urz<72>dzenia
uint8_t srl_usart2_rx_buffer[RX_BUFFER_2_LN] = {'\0'};
#endif
@ -56,6 +54,8 @@ void srl_init(
ctx->te_port = 0;
ctx->te_pin = 0;
ctx->srl_tx_start_time = 0xFFFFFFFFu;
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = baudrate;
@ -219,20 +219,27 @@ uint8_t srl_start_tx(srl_context_t *ctx, short leng) {
ctx->srl_tx_bytes_counter = 1;
// setting a pointer to transmit buffer to the internal buffer inside the driver
ctx->srl_tx_buf_pointer = srl_usart1_tx_buffer;
//ctx->srl_tx_buf_pointer = srl_usart1_tx_buffer;
if (ctx->te_port != 0)
GPIO_SetBits(ctx->te_port, ctx->te_pin);
ctx->port->CR1 |= USART_CR1_TE;
ctx->port->SR &= (0xFFFFFFFF ^ USART_SR_TC);
ctx->port->DR = ctx->srl_tx_buf_pointer[0];
// check if delay should be applied to transmission
if (ctx->srl_tx_start_time == 0xFFFFFFFFu) {
ctx->port->CR1 |= USART_CR1_TE;
ctx->port->SR &= (0xFFFFFFFF ^ USART_SR_TC);
ctx->port->DR = ctx->srl_tx_buf_pointer[0];
ctx->srl_tx_state = SRL_TXING;
ctx->srl_tx_state = SRL_TXING;
ctx->port->CR1 |= USART_CR1_TXEIE; // przerwanie zg<7A>aszane kiedy rejsetr DR jest pusty
ctx->port->CR1 |= USART_CR1_TCIE; // przerwanie zg<7A>aszane po transmisji bajtu
// je<6A>eli rejestr DR jest nadal pusty
ctx->port->CR1 |= USART_CR1_TXEIE;
ctx->port->CR1 |= USART_CR1_TCIE;
}
else {
ctx->srl_tx_state = SRL_TX_WAITING;
ctx->srl_tx_start_time = main_get_master_time();
}
return SRL_OK;
}
@ -479,6 +486,24 @@ void srl_irq_handler(srl_context_t *ctx) {
// storing received byte into buffer
ctx->srl_rx_buf_pointer[ctx->srl_rx_bytes_counter] = (uint8_t)ctx->port->DR;
// check if termination callback pointer has been set
if (ctx->srl_rx_term != NULL) {
// if yes call it
stop_rxing = ctx->srl_rx_term( ctx->srl_rx_buf_pointer[ctx->srl_rx_bytes_counter],
ctx->srl_rx_buf_pointer,
ctx->srl_rx_bytes_counter);
// and check the return value
if (stop_rxing == 1) {
// if this was the last byte of transmission switch the state
// of receiving part to done
ctx->srl_rx_state = SRL_RX_DONE;
ctx->srl_triggered_stop = 0;
}
}
// checking if this byte in stream holds the protocol information about
// how many bytes needs to be received.
if (ctx->srl_rx_lenght_param_addres == ctx->srl_rx_bytes_counter) {
@ -500,23 +525,6 @@ void srl_irq_handler(srl_context_t *ctx) {
// moving buffer pointer forward
ctx->srl_rx_bytes_counter++;
// check if termination callback pointer has been set
if (ctx->srl_rx_term != NULL) {
// if yes call it
stop_rxing = ctx->srl_rx_term( ctx->srl_rx_buf_pointer[ctx->srl_rx_bytes_counter],
ctx->srl_rx_buf_pointer,
ctx->srl_rx_bytes_counter);
// and check the return value
if (stop_rxing == 1) {
// if this was the last byte of transmission switch the state
// of receiving part to done
ctx->srl_rx_state = SRL_RX_DONE;
ctx->srl_triggered_stop = 0;
}
}
}
// if the user want the driver to stop receiving after certain is received
@ -632,6 +640,46 @@ uint8_t* srl_get_rx_buffer(srl_context_t *ctx) {
return ctx->srl_rx_buf_pointer;
}
void srl_keep_tx_delay(srl_context_t *ctx) {
if (ctx != 0) {
// check if pre tx delay is enabled by an user
if (ctx->srl_tx_start_time != 0xFFFFFFFFu) {
// if it is enabled then check if the serial port is currently set to waiting state
if (ctx->srl_tx_state == SRL_TX_WAITING) {
// check if a delay has expired
if (main_get_master_time() - ctx->srl_tx_start_time >= SRL_TX_DELAY_IN_MS) {
// if yes start the transmission
ctx->port->CR1 |= USART_CR1_TE;
ctx->port->SR &= (0xFFFFFFFF ^ USART_SR_TC);
ctx->port->DR = ctx->srl_tx_buf_pointer[0];
ctx->srl_tx_state = SRL_TXING;
ctx->port->CR1 |= USART_CR1_TXEIE;
ctx->port->CR1 |= USART_CR1_TCIE;
}
}
}
}
}
void srl_switch_tx_delay(srl_context_t *ctx, uint8_t disable_enable) {
if (ctx != 0) {
if (disable_enable == 1) {
ctx->srl_tx_start_time = 0x0u;
}
else {
ctx->srl_tx_start_time = 0xFFFFFFFFu;
}
}
}
void srl_switch_timeout(srl_context_t *ctx, uint8_t disable_enable, uint32_t value) {
if (disable_enable == 1)
ctx->srl_rx_timeout_enable = 1;

Wyświetl plik

@ -16,7 +16,7 @@ int32_t rtu_parser_03_04_registers(uint8_t* input, uint16_t input_ln, rtu_regist
uint16_t data = 0;
// iterator through input table and registers table
int i = 0, j = 6;
int i = 0, j = 4;
// 7 bytes is the shortest meaningful Modbus RTU frame
// with a value of single register
@ -31,12 +31,12 @@ int32_t rtu_parser_03_04_registers(uint8_t* input, uint16_t input_ln, rtu_regist
output->slave_address = data;
// fetch function code
data = *(input + 2) << 8 | *(input + 3);
data = *(input + 2);
// 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);
data = *(input + 3);
// store amount of registers in this response
output->number_of_registers = data / 2;
@ -49,6 +49,8 @@ int32_t rtu_parser_03_04_registers(uint8_t* input, uint16_t input_ln, rtu_regist
j += 2;
}
retval = MODBUS_RET_OK;
}
else {
// if not exit with an error as this isn't

Wyświetl plik

@ -34,6 +34,9 @@ typedef enum rtu_pool_state {
rtu_pool_state_t rtu_pool = RTU_POOL_STOP;
/**
* Timestamp of last received modbus RTU response with good CRC
*/
uint32_t rtu_time_of_last_receive = 0;
/**
@ -42,7 +45,14 @@ uint32_t rtu_time_of_last_receive = 0;
uint16_t rtu_serial_previous_crc = 0xFFFF;
/**
* A callback for stream CRC calculation
* Cleared by 'rtu_serial_callback' when first byte from range 0x1..0xF7 is received
*/
uint8_t rtu_waiting_for_slave_addr = 0x1;
/**
* The callback for stream CRC calculation
*/
uint8_t rtu_serial_callback(uint8_t current_data, const uint8_t * const rx_buffer, uint16_t rx_bytes_counter) {
@ -50,17 +60,36 @@ 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_crc_stream(rtu_serial_previous_crc, current_data);
// check if the callback still waits for first 'valid' byte to be received from RTU slave
if (rtu_waiting_for_slave_addr == 0x1) {
// if the new CRC value equals 0x0000 it means that this was MSB
// of CRC from correctly received Modbus-RTU frame
if (new_crc == 0) {
// return '1' to terminate the transmission
retval = 1;
// check if the byte which was received from the slave is valid address
if (current_data >= 0x01 && current_data <= 0xF7) {
// clear this flag to start CRC calculation and data receiving
rtu_waiting_for_slave_addr = 0;
}
else {
// RTU slave cannot respond with the broadcast address (0x00), also 0xF8..0xFF
// are not valid RTU address
;
}
}
else {
rtu_serial_previous_crc = new_crc;
// the second 'if' clause checks if the slave response has began
if (rtu_waiting_for_slave_addr == 0x0) {
// calculate new crc
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
if (new_crc == 0) {
// return '1' to terminate the transmission
retval = 1;
}
else {
rtu_serial_previous_crc = new_crc;
}
}
return retval;
@ -179,6 +208,8 @@ int32_t rtu_serial_pool(rtu_pool_queue_t* queue, srl_context_t* serial_context)
rtu_serial_previous_crc = 0xFFFF;
rtu_waiting_for_slave_addr = 1;
// if serial transmission has been starter
if (result == SRL_OK) {
// proceed to the next state (transmitting)
@ -200,13 +231,14 @@ int32_t rtu_serial_pool(rtu_pool_queue_t* queue, srl_context_t* serial_context)
case RTU_POOL_TRANSMITTING: {
// if transmission is still pending
if (serial_context->srl_tx_state == SRL_TXING) {
if (serial_context->srl_tx_state == SRL_TXING || serial_context->srl_tx_state == SRL_TX_WAITING) {
// wait until it will finish
;
}
else {
// trigger reception
srl_receive_data_with_callback(serial_context, rtu_serial_callback);
//srl_receive_data(serial_context, 8, 0, 0, 0, 0, 0);
// switch the state
rtu_pool = RTU_POOL_RECEIVING;