diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
index efa6ee5..38940f3 100644
--- a/.settings/language.settings.xml
+++ b/.settings/language.settings.xml
@@ -5,7 +5,7 @@
-
+
@@ -16,7 +16,7 @@
-
+
diff --git a/src/it_handlers.c b/src/it_handlers.c
index a79f9f9..d3688ec 100644
--- a/src/it_handlers.c
+++ b/src/it_handlers.c
@@ -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();
diff --git a/src/main.c b/src/main.c
index 8572f5d..9dfdf75 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
diff --git a/system/include/drivers/serial.h b/system/include/drivers/serial.h
index 0c7be8e..144e6b9 100644
--- a/system/include/drivers/serial.h
+++ b/system/include/drivers/serial.h
@@ -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�cy pocz�tek istotnych danych do odbebrania
- uint8_t srl_stop_trigger; // znak oznaczaj�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);
diff --git a/system/include/modbus_rtu/rtu_crc.h b/system/include/modbus_rtu/rtu_crc.h
index 547f2d5..6864fbb 100644
--- a/system/include/modbus_rtu/rtu_crc.h
+++ b/system/include/modbus_rtu/rtu_crc.h
@@ -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);
}
diff --git a/system/src/drivers/serial.c b/system/src/drivers/serial.c
index 3ff6d33..0c6717b 100644
--- a/system/src/drivers/serial.c
+++ b/system/src/drivers/serial.c
@@ -8,23 +8,21 @@
#include
-int srlBRRegValue = 0x09C4 ; // dla symulacji ---- baudrate 9600bps
-//int SrlBRRegValue = 0x0209; // dla realnego uk��du
#ifdef SEPARATE_TX_BUFF
-uint8_t srl_usart1_tx_buffer[TX_BUFFER_1_LN] = {'\0'}; // dane do wys�ania do zdalnego urz�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�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�ania do zdalnego urz�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�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�aszane kiedy rejsetr DR jest pusty
- ctx->port->CR1 |= USART_CR1_TCIE; // przerwanie zg�aszane po transmisji bajtu
- // je�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;
diff --git a/system/src/modbus_rtu/rtu_parser.c b/system/src/modbus_rtu/rtu_parser.c
index 2f977cc..c88f79b 100644
--- a/system/src/modbus_rtu/rtu_parser.c
+++ b/system/src/modbus_rtu/rtu_parser.c
@@ -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
diff --git a/system/src/modbus_rtu/rtu_serial_io.c b/system/src/modbus_rtu/rtu_serial_io.c
index 52024e3..94b20c5 100644
--- a/system/src/modbus_rtu/rtu_serial_io.c
+++ b/system/src/modbus_rtu/rtu_serial_io.c
@@ -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;