Concept code which launches two threads, one of which implements a Modbus Tunnel protocol to talk with an ISEM, the other which launches a Modbus RTU protocol to talk to a CPUM (most of the Modbus code has been removed prior to publishing.) A canned AC and DC spectra is provided to display wave forms on start-up however the project normally polls for spectra from the ISEM and then plots is (that functionality has been removed prior to publishing.)
Dependencies: LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI mbed-os BSP_DISCO_F429ZI
Plot of the initial start-up canned AC and DC spectra.
NextGen-Exerciser-Modbus.cpp@2:346119b3db6c, 2019-05-31 (annotated)
- Committer:
- Damotclese
- Date:
- Fri May 31 22:43:55 2019 +0000
- Revision:
- 2:346119b3db6c
- Parent:
- 0:387684ec9d92
Final concept code update, no further updates are expected;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Damotclese | 0:387684ec9d92 | 1 | |
Damotclese | 0:387684ec9d92 | 2 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 3 | // NextGen-Exerciser-Modbus.cpp |
Damotclese | 0:387684ec9d92 | 4 | // |
Damotclese | 0:387684ec9d92 | 5 | // Fredric L. Rice, May 2019 |
Damotclese | 0:387684ec9d92 | 6 | // |
Damotclese | 0:387684ec9d92 | 7 | // o A digital output for an LED is instantiated |
Damotclese | 0:387684ec9d92 | 8 | // o A Serial object is instantiated on Serial-1 |
Damotclese | 0:387684ec9d92 | 9 | // o A thread's mailbox object is instantiated |
Damotclese | 0:387684ec9d92 | 10 | // o A Thread object is instantiated |
Damotclese | 0:387684ec9d92 | 11 | // o The serial interface is configured |
Damotclese | 0:387684ec9d92 | 12 | // o The module's thread is start()ed |
Damotclese | 0:387684ec9d92 | 13 | // |
Damotclese | 0:387684ec9d92 | 14 | // The LED is toggled according to timing established by a periodic |
Damotclese | 0:387684ec9d92 | 15 | // wait() and according to messages pending in the thread's mailbox |
Damotclese | 0:387684ec9d92 | 16 | // |
Damotclese | 0:387684ec9d92 | 17 | // The mailbox is checked for any messages that need to go out the |
Damotclese | 0:387684ec9d92 | 18 | // serial interface, and if there are any, the message is extracted |
Damotclese | 0:387684ec9d92 | 19 | // from the mailbox and gets sent out the serial interface. If there |
Damotclese | 0:387684ec9d92 | 20 | // are no messages waiting to go out, a Modbus polling message is |
Damotclese | 0:387684ec9d92 | 21 | // sent out the serial interface instead. |
Damotclese | 0:387684ec9d92 | 22 | // |
Damotclese | 0:387684ec9d92 | 23 | // If there is serial data waiting to be read, the data is collected |
Damotclese | 0:387684ec9d92 | 24 | // in to a Modbus frame and it gets handled by examining the content |
Damotclese | 0:387684ec9d92 | 25 | // of the inbound frame. |
Damotclese | 0:387684ec9d92 | 26 | // |
Damotclese | 0:387684ec9d92 | 27 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 28 | |
Damotclese | 0:387684ec9d92 | 29 | #include "mbed.h" // The mbed operating system |
Damotclese | 0:387684ec9d92 | 30 | #include "NextGen-Exerciser-Modbus.h" // Always include ourself |
Damotclese | 0:387684ec9d92 | 31 | #include "NextGen-Exerciser-Defines.h" // For defined constants and MACROs |
Damotclese | 0:387684ec9d92 | 32 | |
Damotclese | 0:387684ec9d92 | 33 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 34 | // Allocate local data storage |
Damotclese | 0:387684ec9d92 | 35 | // |
Damotclese | 0:387684ec9d92 | 36 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 37 | |
Damotclese | 0:387684ec9d92 | 38 | static DigitalOut st_digitalOutModbusLED(LED1); |
Damotclese | 0:387684ec9d92 | 39 | static Serial st_modbusSerial(PA_9, PA_10); // TX, RX Serial 1 (This one is working) |
Damotclese | 0:387684ec9d92 | 40 | static Mail<st_pendingMessage, 16> st_modbusMailbox; |
Damotclese | 0:387684ec9d92 | 41 | static Thread st_threadModbus; |
Damotclese | 0:387684ec9d92 | 42 | static bool b_modbusInitialized = false; |
Damotclese | 0:387684ec9d92 | 43 | static char c_flipFlop = 0; |
Damotclese | 0:387684ec9d92 | 44 | |
Damotclese | 0:387684ec9d92 | 45 | static unsigned char uch_modbusPollFrame[] = |
Damotclese | 0:387684ec9d92 | 46 | { |
Damotclese | 0:387684ec9d92 | 47 | 0xF7, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xDE |
Damotclese | 0:387684ec9d92 | 48 | } ; |
Damotclese | 0:387684ec9d92 | 49 | |
Damotclese | 0:387684ec9d92 | 50 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 51 | // ModbusCheckInbound() |
Damotclese | 0:387684ec9d92 | 52 | // |
Damotclese | 0:387684ec9d92 | 53 | // This function will: |
Damotclese | 0:387684ec9d92 | 54 | // o Check to see if the serial interface is readable |
Damotclese | 0:387684ec9d92 | 55 | // o If there are bytes waiting, the bytes are read and get |
Damotclese | 0:387684ec9d92 | 56 | // assembled in to a full Modbus frame. |
Damotclese | 0:387684ec9d92 | 57 | // o The inbound message is handled by passing it to a function |
Damotclese | 0:387684ec9d92 | 58 | // which examines the content of the inbound message |
Damotclese | 0:387684ec9d92 | 59 | // |
Damotclese | 0:387684ec9d92 | 60 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 61 | static void ModbusCheckInbound(void) |
Damotclese | 0:387684ec9d92 | 62 | { |
Damotclese | 0:387684ec9d92 | 63 | // See if there is inbound serial data |
Damotclese | 0:387684ec9d92 | 64 | if (st_modbusSerial.readable()) |
Damotclese | 0:387684ec9d92 | 65 | { |
Damotclese | 0:387684ec9d92 | 66 | |
Damotclese | 0:387684ec9d92 | 67 | } |
Damotclese | 0:387684ec9d92 | 68 | } |
Damotclese | 0:387684ec9d92 | 69 | |
Damotclese | 0:387684ec9d92 | 70 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 71 | // ModbusCheckOutbound() |
Damotclese | 0:387684ec9d92 | 72 | // |
Damotclese | 0:387684ec9d92 | 73 | // This function will: |
Damotclese | 0:387684ec9d92 | 74 | // o Get a message from the thread's mailbox, waiting for up to |
Damotclese | 0:387684ec9d92 | 75 | // 2 milliseconds for a message |
Damotclese | 0:387684ec9d92 | 76 | // o If a message is pending, the message is extracted and then |
Damotclese | 0:387684ec9d92 | 77 | // gets formatted in to an output Modbus message frame |
Damotclese | 0:387684ec9d92 | 78 | // o The newly-formatted Modbus frame gets transmitted out the |
Damotclese | 0:387684ec9d92 | 79 | // serial interface |
Damotclese | 0:387684ec9d92 | 80 | // o The mailbox message gets released back in to the memory pool |
Damotclese | 0:387684ec9d92 | 81 | // o If there was no output message waiting in the mailbox, a |
Damotclese | 0:387684ec9d92 | 82 | // Modbus polling message is sent out the serial interface |
Damotclese | 0:387684ec9d92 | 83 | // |
Damotclese | 0:387684ec9d92 | 84 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 85 | static void ModbusCheckOutbound(void) |
Damotclese | 0:387684ec9d92 | 86 | { |
Damotclese | 0:387684ec9d92 | 87 | // Is there an outbound message waiting? Wait up to 2 milliseconds for one |
Damotclese | 0:387684ec9d92 | 88 | osEvent st_eventResult = st_modbusMailbox.get(2); |
Damotclese | 0:387684ec9d92 | 89 | |
Damotclese | 0:387684ec9d92 | 90 | if (st_eventResult.status == osEventMail) |
Damotclese | 0:387684ec9d92 | 91 | { |
Damotclese | 0:387684ec9d92 | 92 | // Get a pointer to the message |
Damotclese | 0:387684ec9d92 | 93 | st_pendingMessage * pst_outFrame = (st_pendingMessage *)st_eventResult.value.p; |
Damotclese | 0:387684ec9d92 | 94 | |
Damotclese | 0:387684ec9d92 | 95 | // Format and send the MODBUS frame |
Damotclese | 0:387684ec9d92 | 96 | |
Damotclese | 0:387684ec9d92 | 97 | // Finished with the message so release it even if it was not sent |
Damotclese | 0:387684ec9d92 | 98 | st_modbusMailbox.free(pst_outFrame); |
Damotclese | 0:387684ec9d92 | 99 | } |
Damotclese | 0:387684ec9d92 | 100 | else |
Damotclese | 0:387684ec9d92 | 101 | { |
Damotclese | 0:387684ec9d92 | 102 | // Send a poll frame |
Damotclese | 0:387684ec9d92 | 103 | st_modbusSerial.write((uint8_t *)uch_modbusPollFrame, sizeof(uch_modbusPollFrame), NULL); |
Damotclese | 0:387684ec9d92 | 104 | } |
Damotclese | 0:387684ec9d92 | 105 | } |
Damotclese | 0:387684ec9d92 | 106 | |
Damotclese | 0:387684ec9d92 | 107 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 108 | // ModbusThread() |
Damotclese | 0:387684ec9d92 | 109 | // |
Damotclese | 0:387684ec9d92 | 110 | // This function will: |
Damotclese | 0:387684ec9d92 | 111 | // o Get invoked as a thread under the mbed operating system |
Damotclese | 0:387684ec9d92 | 112 | // o Turn ON the lED associated with this module and protocol |
Damotclese | 0:387684ec9d92 | 113 | // o Enter in to a forever loop which wakes up ten times a second |
Damotclese | 0:387684ec9d92 | 114 | // o Drives the module's LED so that it flashes frim time to time |
Damotclese | 0:387684ec9d92 | 115 | // to indicate that the thread is running |
Damotclese | 0:387684ec9d92 | 116 | // o Check to ensure that the module has been initialized |
Damotclese | 0:387684ec9d92 | 117 | // o If the module is initialized (and it should be) checks to |
Damotclese | 0:387684ec9d92 | 118 | // see if there are inbound serial Modbus messages |
Damotclese | 0:387684ec9d92 | 119 | // o Checks to see if there are any outbound serial Modbus messages |
Damotclese | 0:387684ec9d92 | 120 | // |
Damotclese | 0:387684ec9d92 | 121 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 122 | static void ModbusThread(void) |
Damotclese | 0:387684ec9d92 | 123 | { |
Damotclese | 0:387684ec9d92 | 124 | char ch_halfSecond = 5; |
Damotclese | 0:387684ec9d92 | 125 | |
Damotclese | 0:387684ec9d92 | 126 | // Set the MODBUS LED to ON to indicate that the thread has started |
Damotclese | 0:387684ec9d92 | 127 | st_digitalOutModbusLED = 1; |
Damotclese | 0:387684ec9d92 | 128 | |
Damotclese | 0:387684ec9d92 | 129 | // Enter in to a forever loop |
Damotclese | 0:387684ec9d92 | 130 | while (true) |
Damotclese | 0:387684ec9d92 | 131 | { |
Damotclese | 0:387684ec9d92 | 132 | // Sleep for one tenth of a second |
Damotclese | 0:387684ec9d92 | 133 | wait(0.1); |
Damotclese | 0:387684ec9d92 | 134 | |
Damotclese | 0:387684ec9d92 | 135 | // Count down the half second timer and see if it expired |
Damotclese | 0:387684ec9d92 | 136 | if (0 == --ch_halfSecond) |
Damotclese | 0:387684ec9d92 | 137 | { |
Damotclese | 0:387684ec9d92 | 138 | // It has expired so restart the half second time |
Damotclese | 0:387684ec9d92 | 139 | ch_halfSecond = 5; |
Damotclese | 0:387684ec9d92 | 140 | |
Damotclese | 0:387684ec9d92 | 141 | // See if we turn on or turn off the LED |
Damotclese | 0:387684ec9d92 | 142 | if (0 == c_flipFlop) |
Damotclese | 0:387684ec9d92 | 143 | { |
Damotclese | 0:387684ec9d92 | 144 | c_flipFlop = 1; |
Damotclese | 0:387684ec9d92 | 145 | } |
Damotclese | 0:387684ec9d92 | 146 | else |
Damotclese | 0:387684ec9d92 | 147 | { |
Damotclese | 0:387684ec9d92 | 148 | c_flipFlop = 0; |
Damotclese | 0:387684ec9d92 | 149 | } |
Damotclese | 0:387684ec9d92 | 150 | |
Damotclese | 0:387684ec9d92 | 151 | st_digitalOutModbusLED = c_flipFlop; |
Damotclese | 0:387684ec9d92 | 152 | } |
Damotclese | 0:387684ec9d92 | 153 | |
Damotclese | 0:387684ec9d92 | 154 | // We check to see if there is inbound or outbound serial traffic 10 times a second |
Damotclese | 0:387684ec9d92 | 155 | if (TRUE == b_modbusInitialized) |
Damotclese | 0:387684ec9d92 | 156 | { |
Damotclese | 0:387684ec9d92 | 157 | // Check for inbound MODBUS frames |
Damotclese | 0:387684ec9d92 | 158 | ModbusCheckInbound(); |
Damotclese | 0:387684ec9d92 | 159 | |
Damotclese | 0:387684ec9d92 | 160 | // See if we need to send outbound MODBUS frames |
Damotclese | 0:387684ec9d92 | 161 | ModbusCheckOutbound(); |
Damotclese | 0:387684ec9d92 | 162 | } |
Damotclese | 0:387684ec9d92 | 163 | } |
Damotclese | 0:387684ec9d92 | 164 | } |
Damotclese | 0:387684ec9d92 | 165 | |
Damotclese | 0:387684ec9d92 | 166 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 167 | // ModbusInit() |
Damotclese | 0:387684ec9d92 | 168 | // |
Damotclese | 0:387684ec9d92 | 169 | // This function will: |
Damotclese | 0:387684ec9d92 | 170 | // o Initialize the module protocol's serial interface |
Damotclese | 0:387684ec9d92 | 171 | // o Flag the fact that things are initialized |
Damotclese | 0:387684ec9d92 | 172 | // o Launch the module's thread |
Damotclese | 0:387684ec9d92 | 173 | // |
Damotclese | 0:387684ec9d92 | 174 | // ---------------------------------------------------------------------- |
Damotclese | 0:387684ec9d92 | 175 | void ModbusInit(void) |
Damotclese | 0:387684ec9d92 | 176 | { |
Damotclese | 0:387684ec9d92 | 177 | // We configure the CPUM MODBUS serial interface |
Damotclese | 0:387684ec9d92 | 178 | st_modbusSerial.baud(115200); |
Damotclese | 0:387684ec9d92 | 179 | st_modbusSerial.format(8, SerialBase::None, 1); |
Damotclese | 0:387684ec9d92 | 180 | |
Damotclese | 0:387684ec9d92 | 181 | // Flag the fact that the module has been initialized |
Damotclese | 0:387684ec9d92 | 182 | b_modbusInitialized = true; |
Damotclese | 0:387684ec9d92 | 183 | |
Damotclese | 0:387684ec9d92 | 184 | // Launch the CPUM Modbus thread |
Damotclese | 0:387684ec9d92 | 185 | st_threadModbus.start(ModbusThread); |
Damotclese | 0:387684ec9d92 | 186 | } |
Damotclese | 0:387684ec9d92 | 187 | |
Damotclese | 0:387684ec9d92 | 188 | // End of file |
Damotclese | 0:387684ec9d92 | 189 |