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.
CCS-COMM_BOARD/MODBUSRTU/ModbusRTUTransceiver.cpp

497 lines
15 KiB
C++

/*
* 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 */