You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
15 KiB
C++
497 lines
15 KiB
C++
4 weeks ago
|
/*
|
||
|
* ModbusRTUTransceiver.cpp
|
||
|
*
|
||
|
* Author: Aleksey Gerasimenko
|
||
|
* gerasimenko.aleksey.n@gmail.com
|
||
|
*/
|
||
|
|
||
|
#include "MODBUSRTU/ModbusRTUTransceiver.h"
|
||
|
|
||
|
namespace MODBUSRTU
|
||
|
{
|
||
|
//CONSTRUCTOR
|
||
|
//ModbusRTUTransceiver::ModbusRTUTransceiver(DSP28335::SCIBase& sciport, DSP28335::CPUTimers& cputimer, MODBUSRTU::ModbusRTUCRC& crc):
|
||
|
ModbusRTUTransceiver::ModbusRTUTransceiver(DSP28335::SCIBase& sciport, DSP28335::MeasureTimeInterval& interval_measure, MODBUSRTU::ModbusRTUCRC& crc):
|
||
|
m_sci_port(sciport),
|
||
|
m_sci_config(),
|
||
|
m_node_id(0),
|
||
|
//
|
||
|
m_state_machine(MODBUSRTU::SCAN),
|
||
|
m_event(MODBUSRTU::ENTRY),
|
||
|
//
|
||
|
//m_interval(cputimer.CPUTimer),
|
||
|
m_interval_measure(interval_measure),
|
||
|
m_interval_pause((Uint32)0),
|
||
|
m_interval_b5((Uint32)0),
|
||
|
m_interval_b75((Uint32)0),
|
||
|
m_interval_1b((Uint32)0),
|
||
|
m_interval_1b25((Uint32)0),
|
||
|
m_interval_1b5((Uint32)0),
|
||
|
m_interval_1b75((Uint32)0),
|
||
|
m_interval_3b5((Uint32)0),
|
||
|
m_interval_freeze((Uint32)0),
|
||
|
m_interval_current((Uint32)0),
|
||
|
//
|
||
|
m_rx_buffer(),
|
||
|
m_tx_buffer(),
|
||
|
m_rx_count(0),
|
||
|
m_tx_count(0),
|
||
|
m_tx_length(0),
|
||
|
//
|
||
|
m_aux_rx_buf(0),
|
||
|
m_aux_rx_count(0),
|
||
|
m_aux_tx_buf(0),
|
||
|
m_aux_tx_count(0),
|
||
|
//
|
||
|
m_crc_status(false),
|
||
|
m_crc(crc),
|
||
|
m_crc_rx_frame(0),
|
||
|
m_crc_tx_frame(0),
|
||
|
//
|
||
|
m_rx_external_buffer(m_rx_buffer),
|
||
|
m_tx_external_buffer(m_tx_buffer),
|
||
|
m_rx_messaage_length(&m_rx_count),
|
||
|
m_tx_message_length(&m_tx_count),
|
||
|
//
|
||
|
m_destination(0),
|
||
|
m_source_start(0),
|
||
|
m_source_end(0),
|
||
|
m_copy_length(0),
|
||
|
//
|
||
|
_execute(&ModbusRTUTransceiver::_execute_transceiver),
|
||
|
_frame_transceiver(&ModbusRTUTransceiver::_frame_receive_node_id),
|
||
|
//
|
||
|
_re_de_setup(&DSP28335::GPIO::gpio_scib_re_de_setup),
|
||
|
_driver_enable(&DSP28335::GPIO::gpio_scib_re_de_set),
|
||
|
_receiver_enable(&DSP28335::GPIO::gpio_scib_re_de_clear)
|
||
|
//
|
||
|
{}//CONSTRUCTOR
|
||
|
|
||
|
|
||
|
|
||
|
void ModbusRTUTransceiver::setup(ModbusRTUTransceiverSetup& setup)
|
||
|
{
|
||
|
//m_interval.setup();
|
||
|
_re_de_setup = setup.gpio_re_de_setup;
|
||
|
_driver_enable = setup.gpio_driver_enable;
|
||
|
_receiver_enable = setup.gpio_receiver_enable;
|
||
|
|
||
|
|
||
|
(*_re_de_setup)();
|
||
|
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
void ModbusRTUTransceiver::configure(ModbusRTUTransceiverConfiguration& config)
|
||
|
{
|
||
|
m_sci_config = config.config;
|
||
|
m_node_id = config.node_id;
|
||
|
|
||
|
if(!m_sci_port.compare_configuration(m_sci_config))
|
||
|
{
|
||
|
m_sci_port.set_configuration(m_sci_config);
|
||
|
//
|
||
|
}//if
|
||
|
|
||
|
switch(m_sci_config.baudrate)
|
||
|
{
|
||
|
case DSP28335::BR2400: {m_interval_b5 = (Uint32)250000; m_interval_b75 = (Uint32)375000; m_interval_1b = (Uint32)500000; m_interval_1b25 = (Uint32)625000; m_interval_1b5 = (Uint32)750000; m_interval_1b75 = (Uint32)875000; m_interval_3b5 = (Uint32)1750000; m_interval_freeze = (Uint32)2000000; break;}
|
||
|
case DSP28335::BR4800: {m_interval_b5 = (Uint32)125000; m_interval_b75 = (Uint32)187500; m_interval_1b = (Uint32)250000; m_interval_1b25 = (Uint32)312500; m_interval_1b5 = (Uint32)375000; m_interval_1b75 = (Uint32)250000; m_interval_3b5 = (Uint32) 875000; m_interval_freeze = (Uint32)1000000; break;}
|
||
|
case DSP28335::BR9600: {m_interval_b5 = (Uint32) 62500; m_interval_b75 = (Uint32) 93750; m_interval_1b = (Uint32)125000; m_interval_1b25 = (Uint32)156250; m_interval_1b5 = (Uint32)187500; m_interval_1b75 = (Uint32)218750; m_interval_3b5 = (Uint32) 437500; m_interval_freeze = (Uint32) 500000; break;}
|
||
|
case DSP28335::BR19200: {m_interval_b5 = (Uint32) 31250; m_interval_b75 = (Uint32) 46875; m_interval_1b = (Uint32) 62500; m_interval_1b25 = (Uint32)78125; m_interval_1b5 = (Uint32) 93750; m_interval_1b75 = (Uint32)109375; m_interval_3b5 = (Uint32) 218750; m_interval_freeze = (Uint32) 250000; break;}
|
||
|
case DSP28335::BR38400: {m_interval_b5 = (Uint32)15625; m_interval_b75 = (Uint32)23437; m_interval_1b = (Uint32) 31250; m_interval_1b25 = (Uint32)39062; m_interval_1b5 = (Uint32) 46875; m_interval_1b75 = (Uint32) 54687; m_interval_3b5 = (Uint32) 109375; m_interval_freeze = (Uint32) 125000; break;}
|
||
|
default: {m_interval_b5 = (Uint32)62500; m_interval_b75 = (Uint32)93750; m_interval_1b = (Uint32)125000; m_interval_1b25 = (Uint32)156250; m_interval_1b5 = (Uint32)187500; m_interval_1b75 = (Uint32)218750; m_interval_3b5 = (Uint32) 437500; m_interval_freeze = (Uint32) 500000; break;}
|
||
|
}//switch
|
||
|
|
||
|
m_interval_pause = m_interval_1b * 0.1;
|
||
|
//m_interval_pause = m_interval_1b * 0.2;
|
||
|
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
|
||
|
void ModbusRTUTransceiver::port_reset()
|
||
|
{
|
||
|
m_sci_port.set_configuration(m_sci_config);
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
bool ModbusRTUTransceiver::compare_state(MODBUSRTU::transceiver_state_machine_t state_machine)
|
||
|
{
|
||
|
return m_state_machine == state_machine;
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
void ModbusRTUTransceiver::execute()
|
||
|
{
|
||
|
(this->*_execute)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
|
||
|
void ModbusRTUTransceiver::_execute_transceiver()
|
||
|
{
|
||
|
if(m_sci_port.SciRegs.SCIRXST.bit.BRKDT)
|
||
|
{
|
||
|
_set_break_condition();
|
||
|
//
|
||
|
}//if
|
||
|
//
|
||
|
(this->*_frame_transceiver)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
void ModbusRTUTransceiver::_execute_break()
|
||
|
{
|
||
|
//m_interval_current = m_interval.interval();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
void ModbusRTUTransceiver::setRXBuffer(uint16_t *bufferStart, uint16_t *messageLen)
|
||
|
{
|
||
|
m_rx_external_buffer = bufferStart;
|
||
|
m_rx_messaage_length = messageLen;
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
void ModbusRTUTransceiver::setTXBuffer(uint16_t *bufferStart, uint16_t *messageLen)
|
||
|
{
|
||
|
m_tx_external_buffer = bufferStart;
|
||
|
m_tx_message_length = messageLen;
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_set_receive_node_id()
|
||
|
{
|
||
|
m_state_machine = MODBUSRTU::SCAN;
|
||
|
_frame_transceiver = &ModbusRTUTransceiver::_frame_receive_node_id;
|
||
|
_execute = &ModbusRTUTransceiver::_execute_transceiver;
|
||
|
(*_receiver_enable)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_set_receive_function()
|
||
|
{
|
||
|
m_state_machine = MODBUSRTU::RECEIVE;
|
||
|
_frame_transceiver = &ModbusRTUTransceiver::_frame_receive_function;
|
||
|
_execute = &ModbusRTUTransceiver::_execute_transceiver;
|
||
|
(*_receiver_enable)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_set_receive_data()
|
||
|
{
|
||
|
m_state_machine = MODBUSRTU::RECEIVE;
|
||
|
_frame_transceiver = &ModbusRTUTransceiver::_frame_receive_data;
|
||
|
_execute = &ModbusRTUTransceiver::_execute_transceiver;
|
||
|
(*_receiver_enable)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_set_wait_response()
|
||
|
{
|
||
|
m_state_machine = MODBUSRTU::WAIT_RESPONSE;
|
||
|
_frame_transceiver = &ModbusRTUTransceiver::_frame_wait_response;
|
||
|
_execute = &ModbusRTUTransceiver::_execute_transceiver;
|
||
|
(*_receiver_enable)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_set_transmit_data()
|
||
|
{
|
||
|
m_state_machine = MODBUSRTU::TRANSMIT;
|
||
|
_frame_transceiver = &ModbusRTUTransceiver::_frame_transmit_data;
|
||
|
_execute = &ModbusRTUTransceiver::_execute_transceiver;
|
||
|
(*_driver_enable)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_set_break_condition()
|
||
|
{
|
||
|
m_state_machine = MODBUSRTU::BREAK;
|
||
|
_frame_transceiver = &ModbusRTUTransceiver::_frame_break_condition;
|
||
|
_execute = &ModbusRTUTransceiver::_execute_break;
|
||
|
(*_receiver_enable)();
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_receive_node_id()
|
||
|
{
|
||
|
if(m_sci_port.SciRegs.SCIRXST.bit.RXRDY)
|
||
|
{
|
||
|
m_aux_rx_buf = m_sci_port.SciRegs.SCIRXBUF.bit.RXDT;
|
||
|
|
||
|
while(m_sci_port.SciRegs.SCIRXST.bit.RXRDY){}
|
||
|
|
||
|
if((m_node_id == m_aux_rx_buf)||(MODBUSRTU_FUNCTION_BROADCAST == m_aux_rx_buf))
|
||
|
{
|
||
|
m_rx_buffer[0] = m_aux_rx_buf;
|
||
|
|
||
|
m_aux_rx_count = 1;
|
||
|
m_interval_measure.start();
|
||
|
_set_receive_function();
|
||
|
//
|
||
|
}//if
|
||
|
}
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_receive_function()
|
||
|
{
|
||
|
if(m_sci_port.SciRegs.SCIRXST.bit.RXRDY)
|
||
|
{
|
||
|
m_aux_rx_buf = m_sci_port.SciRegs.SCIRXBUF.bit.RXDT;
|
||
|
|
||
|
while(m_sci_port.SciRegs.SCIRXST.bit.RXRDY){}
|
||
|
|
||
|
if(//(MODBUSRTU_FUNCTION_BROADCAST == m_aux_rx_buf)||
|
||
|
(MODBUSRTU_FUNCTION_READ_COIL_STATUS == m_aux_rx_buf)||
|
||
|
//(MODBUSRTU_FUNCTION_READ_INPUT_STATUS == m_aux_rx_buf)||
|
||
|
(MODBUSRTU_FUNCTION_READ_HOLDING_REGISTERS == m_aux_rx_buf)||
|
||
|
//(MODBUSRTU_FUNCTION_READ_INPUT_REGISTERS == m_aux_rx_buf)||
|
||
|
(MODBUSRTU_FUNCTION_FORCE_SINGLE_COIL == m_aux_rx_buf)||
|
||
|
(MODBUSRTU_FUNCTION_PRESET_SINGLE_REGISTER == m_aux_rx_buf)||
|
||
|
(MODBUSRTU_FUNCTION_FORCE_MULTIPLE_COILS == m_aux_rx_buf)||
|
||
|
(MODBUSRTU_FUNCTION_PRESET_MULTIPLE_REGISTERS == m_aux_rx_buf))
|
||
|
{
|
||
|
m_rx_buffer[1] = m_aux_rx_buf;
|
||
|
m_aux_rx_count = 2;
|
||
|
m_interval_measure.start();
|
||
|
_set_receive_data();
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// wrong function, break receive
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_interval_current = m_interval_measure.interval();
|
||
|
if(m_interval_current > m_interval_1b5)
|
||
|
{
|
||
|
// exceed time interval, break receive
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//if
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}//
|
||
|
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_receive_data()
|
||
|
{
|
||
|
if(m_sci_port.SciRegs.SCIRXST.bit.RXRDY)
|
||
|
{
|
||
|
m_aux_rx_buf = m_sci_port.SciRegs.SCIRXBUF.bit.RXDT;
|
||
|
|
||
|
while(m_sci_port.SciRegs.SCIRXST.bit.RXRDY){}
|
||
|
|
||
|
m_rx_buffer[m_aux_rx_count] = m_aux_rx_buf;
|
||
|
m_aux_rx_count++;
|
||
|
m_interval_measure.start();
|
||
|
|
||
|
if(m_aux_rx_count >= 256)
|
||
|
{
|
||
|
// exceed count, break receive
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//if
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
m_interval_current = m_interval_measure.interval();
|
||
|
if(m_interval_current >= m_interval_1b5)
|
||
|
{
|
||
|
//
|
||
|
// count must be more then 4
|
||
|
if(m_aux_rx_count > 4)
|
||
|
{
|
||
|
// stop receive, frame is ended
|
||
|
// check message
|
||
|
m_rx_count = m_aux_rx_count;
|
||
|
|
||
|
m_crc_calculate = m_crc.calculate(m_rx_buffer, m_rx_count - 2);
|
||
|
|
||
|
m_crc_rx_frame = (m_rx_buffer[m_rx_count - 1] << 8) | m_rx_buffer[m_rx_count - 2];
|
||
|
|
||
|
m_crc_status = m_crc_calculate == m_crc_rx_frame ? true : false;
|
||
|
|
||
|
if(m_crc_status)
|
||
|
{
|
||
|
m_destination = m_rx_external_buffer;
|
||
|
m_source_start = m_rx_buffer;
|
||
|
m_source_end = m_rx_buffer + m_rx_count - 1;
|
||
|
m_copy_length = m_rx_count;
|
||
|
*m_rx_messaage_length = m_rx_count;
|
||
|
m_event = MODBUSRTU::RXREADY;
|
||
|
//_frame_copy();
|
||
|
_frame_copy_erase();
|
||
|
_set_wait_response();
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}//
|
||
|
else
|
||
|
{
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}// if else
|
||
|
//
|
||
|
}//if
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_wait_response()
|
||
|
{
|
||
|
if(m_sci_port.SciRegs.SCIRXST.bit.RXRDY)
|
||
|
{
|
||
|
m_aux_rx_buf = m_sci_port.SciRegs.SCIRXBUF.bit.RXDT;
|
||
|
|
||
|
while(m_sci_port.SciRegs.SCIRXST.bit.RXRDY){}
|
||
|
|
||
|
// error protocol, reset message
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_interval_current = m_interval_measure.interval();
|
||
|
if(m_interval_current >= m_interval_3b5)
|
||
|
{
|
||
|
m_interval_measure.stop();
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(*m_tx_message_length != 0)
|
||
|
{
|
||
|
// copy external tx buffer
|
||
|
m_tx_length = *m_tx_message_length;
|
||
|
m_source_start = m_tx_external_buffer;
|
||
|
m_source_end = m_tx_external_buffer + m_tx_length - 1;
|
||
|
m_destination = m_tx_buffer;
|
||
|
//_frame_copy_erase();
|
||
|
_frame_copy();
|
||
|
*m_tx_message_length = 0;
|
||
|
m_tx_count = 0;
|
||
|
_set_transmit_data();
|
||
|
_frame_transmit_data();
|
||
|
m_interval_measure.stop();
|
||
|
//
|
||
|
}//if
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_transmit_data()
|
||
|
{
|
||
|
if(m_sci_port.SciRegs.SCICTL2.bit.TXRDY & m_sci_port.SciRegs.SCICTL2.bit.TXEMPTY)
|
||
|
{
|
||
|
// data was transmitted
|
||
|
if(m_tx_count >= m_tx_length)
|
||
|
{
|
||
|
// all message was transmitted
|
||
|
// break transmit mode, go to the receive mode
|
||
|
_set_receive_node_id();
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_sci_port.SciRegs.SCITXBUF = m_tx_buffer[m_tx_count];
|
||
|
|
||
|
while(m_sci_port.SciRegs.SCICTL2.bit.TXEMPTY == 1){}
|
||
|
|
||
|
m_tx_count++;
|
||
|
//
|
||
|
}//if else
|
||
|
//
|
||
|
}// if
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_break_condition()
|
||
|
{
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
inline void ModbusRTUTransceiver::_frame_copy()
|
||
|
{
|
||
|
while(m_source_start <= m_source_end)
|
||
|
{
|
||
|
*m_destination++ = *m_source_start++;
|
||
|
//
|
||
|
}//while
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
inline void ModbusRTUTransceiver::_frame_copy_erase()
|
||
|
{
|
||
|
while(m_source_start <= m_source_end)
|
||
|
{
|
||
|
*m_destination++ = *m_source_start;
|
||
|
*m_source_start++ = 0;
|
||
|
//
|
||
|
}//while
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
// #pragma CODE_SECTION("ramfuncs");
|
||
|
void ModbusRTUTransceiver::_frame_copy(uint16_t *source, uint16_t length, uint16_t *destination)
|
||
|
{
|
||
|
m_destination = destination;
|
||
|
m_source_start = source;
|
||
|
m_source_end = destination + length - 1;
|
||
|
m_copy_length = length;
|
||
|
|
||
|
while(m_source_start <= m_source_end)
|
||
|
{
|
||
|
*m_destination++ = *m_source_start++;
|
||
|
//
|
||
|
}//while
|
||
|
//
|
||
|
}//
|
||
|
//
|
||
|
|
||
|
} /* namespace MODBUSRTU */
|