Testing Modbus RS485 commands
Dependencies: mbed BufferedSerial
RS485.cpp@0:dccd2df6a07c, 2017-02-27 (annotated)
- Committer:
- Allar
- Date:
- Mon Feb 27 21:53:25 2017 +0000
- Revision:
- 0:dccd2df6a07c
Adding comments to library
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Allar | 0:dccd2df6a07c | 1 | #include "RS485.h" |
Allar | 0:dccd2df6a07c | 2 | #include <stdarg.h> |
Allar | 0:dccd2df6a07c | 3 | |
Allar | 0:dccd2df6a07c | 4 | typedef unsigned int word; |
Allar | 0:dccd2df6a07c | 5 | typedef uint8_t byte; |
Allar | 0:dccd2df6a07c | 6 | typedef uint8_t boolean; |
Allar | 0:dccd2df6a07c | 7 | typedef void (*voidFuncPtr)(void); |
Allar | 0:dccd2df6a07c | 8 | Timer lapse; |
Allar | 0:dccd2df6a07c | 9 | const byte STX = '\2'; |
Allar | 0:dccd2df6a07c | 10 | const byte ETX = '\3'; |
Allar | 0:dccd2df6a07c | 11 | |
Allar | 0:dccd2df6a07c | 12 | RS485::RS485(PinName tx, PinName rx, PinName dere) |
Allar | 0:dccd2df6a07c | 13 | : BufferedSerial(tx, rx) |
Allar | 0:dccd2df6a07c | 14 | { |
Allar | 0:dccd2df6a07c | 15 | return; |
Allar | 0:dccd2df6a07c | 16 | } |
Allar | 0:dccd2df6a07c | 17 | |
Allar | 0:dccd2df6a07c | 18 | |
Allar | 0:dccd2df6a07c | 19 | byte RS485::crc8(const byte *addr, byte len) |
Allar | 0:dccd2df6a07c | 20 | { |
Allar | 0:dccd2df6a07c | 21 | byte crc = 0; |
Allar | 0:dccd2df6a07c | 22 | while (len--) |
Allar | 0:dccd2df6a07c | 23 | { |
Allar | 0:dccd2df6a07c | 24 | byte inbyte = *addr++; |
Allar | 0:dccd2df6a07c | 25 | for (byte i = 8; i; i--) |
Allar | 0:dccd2df6a07c | 26 | { |
Allar | 0:dccd2df6a07c | 27 | byte mix = (crc ^ inbyte) & 0x01; |
Allar | 0:dccd2df6a07c | 28 | crc >>= 1; |
Allar | 0:dccd2df6a07c | 29 | if (mix) |
Allar | 0:dccd2df6a07c | 30 | crc ^= 0x8C; |
Allar | 0:dccd2df6a07c | 31 | inbyte >>= 1; |
Allar | 0:dccd2df6a07c | 32 | } // end of for |
Allar | 0:dccd2df6a07c | 33 | } // end of while |
Allar | 0:dccd2df6a07c | 34 | return crc; |
Allar | 0:dccd2df6a07c | 35 | } // end of crc8 |
Allar | 0:dccd2df6a07c | 36 | |
Allar | 0:dccd2df6a07c | 37 | void RS485::sendComplemented( const byte what) |
Allar | 0:dccd2df6a07c | 38 | { |
Allar | 0:dccd2df6a07c | 39 | byte c ; |
Allar | 0:dccd2df6a07c | 40 | // first nibble |
Allar | 0:dccd2df6a07c | 41 | c = what >> 4; |
Allar | 0:dccd2df6a07c | 42 | putc((c << 4) | (c ^ 0x0F)); |
Allar | 0:dccd2df6a07c | 43 | |
Allar | 0:dccd2df6a07c | 44 | // second nibble |
Allar | 0:dccd2df6a07c | 45 | c = what & 0x0F; |
Allar | 0:dccd2df6a07c | 46 | putc((c << 4) | (c ^ 0x0F)); |
Allar | 0:dccd2df6a07c | 47 | } // end of sendComplemented |
Allar | 0:dccd2df6a07c | 48 | |
Allar | 0:dccd2df6a07c | 49 | |
Allar | 0:dccd2df6a07c | 50 | void RS485::sendMsg(const byte * data, const byte length) |
Allar | 0:dccd2df6a07c | 51 | { |
Allar | 0:dccd2df6a07c | 52 | putc(STX); // STX |
Allar | 0:dccd2df6a07c | 53 | for (byte i = 0; i < length; i++) |
Allar | 0:dccd2df6a07c | 54 | sendComplemented (data[i]); |
Allar | 0:dccd2df6a07c | 55 | putc(ETX); // ETX |
Allar | 0:dccd2df6a07c | 56 | sendComplemented(crc8(data, length)); |
Allar | 0:dccd2df6a07c | 57 | } // end of sendMsg |
Allar | 0:dccd2df6a07c | 58 | |
Allar | 0:dccd2df6a07c | 59 | // receive a message, maximum "length" bytes, timeout after "timeout" clock_mseconds |
Allar | 0:dccd2df6a07c | 60 | // if nothing received, or an error (eg. bad CRC, bad data) return 0 |
Allar | 0:dccd2df6a07c | 61 | // otherwise, returns length of received data |
Allar | 0:dccd2df6a07c | 62 | byte RS485::recvMsg (byte * data, // buffer to receive into |
Allar | 0:dccd2df6a07c | 63 | const byte length, // maximum buffer size |
Allar | 0:dccd2df6a07c | 64 | unsigned long timeout) // clock_mseconds before timing out |
Allar | 0:dccd2df6a07c | 65 | { |
Allar | 0:dccd2df6a07c | 66 | |
Allar | 0:dccd2df6a07c | 67 | unsigned long start_time = lapse.read_ms(); |
Allar | 0:dccd2df6a07c | 68 | |
Allar | 0:dccd2df6a07c | 69 | bool have_stx = false; |
Allar | 0:dccd2df6a07c | 70 | |
Allar | 0:dccd2df6a07c | 71 | // variables below are set when we get an STX |
Allar | 0:dccd2df6a07c | 72 | bool have_etx; |
Allar | 0:dccd2df6a07c | 73 | byte input_pos; |
Allar | 0:dccd2df6a07c | 74 | bool first_nibble; |
Allar | 0:dccd2df6a07c | 75 | byte current_byte; |
Allar | 0:dccd2df6a07c | 76 | |
Allar | 0:dccd2df6a07c | 77 | while (lapse.read_ms() - start_time < timeout) |
Allar | 0:dccd2df6a07c | 78 | { |
Allar | 0:dccd2df6a07c | 79 | if (readable() > 0) |
Allar | 0:dccd2df6a07c | 80 | { |
Allar | 0:dccd2df6a07c | 81 | byte inByte = getc(); |
Allar | 0:dccd2df6a07c | 82 | |
Allar | 0:dccd2df6a07c | 83 | switch (inByte) |
Allar | 0:dccd2df6a07c | 84 | { |
Allar | 0:dccd2df6a07c | 85 | |
Allar | 0:dccd2df6a07c | 86 | case STX: // start of text |
Allar | 0:dccd2df6a07c | 87 | have_stx = true; |
Allar | 0:dccd2df6a07c | 88 | have_etx = false; |
Allar | 0:dccd2df6a07c | 89 | input_pos = 0; |
Allar | 0:dccd2df6a07c | 90 | first_nibble = true; |
Allar | 0:dccd2df6a07c | 91 | start_time = lapse.read_ms(); // reset timeout period |
Allar | 0:dccd2df6a07c | 92 | break; |
Allar | 0:dccd2df6a07c | 93 | |
Allar | 0:dccd2df6a07c | 94 | case ETX: // end of text |
Allar | 0:dccd2df6a07c | 95 | have_etx = true; |
Allar | 0:dccd2df6a07c | 96 | break; |
Allar | 0:dccd2df6a07c | 97 | |
Allar | 0:dccd2df6a07c | 98 | default: |
Allar | 0:dccd2df6a07c | 99 | // wait until packet officially starts |
Allar | 0:dccd2df6a07c | 100 | if (!have_stx) |
Allar | 0:dccd2df6a07c | 101 | break; |
Allar | 0:dccd2df6a07c | 102 | |
Allar | 0:dccd2df6a07c | 103 | // check byte is in valid form (4 bits followed by 4 bits complemented) |
Allar | 0:dccd2df6a07c | 104 | if ((inByte >> 4) != ((inByte & 0x0F) ^ 0x0F) ) |
Allar | 0:dccd2df6a07c | 105 | return 0; // bad character |
Allar | 0:dccd2df6a07c | 106 | |
Allar | 0:dccd2df6a07c | 107 | // convert back |
Allar | 0:dccd2df6a07c | 108 | inByte >>= 4; |
Allar | 0:dccd2df6a07c | 109 | |
Allar | 0:dccd2df6a07c | 110 | // high-order nibble? |
Allar | 0:dccd2df6a07c | 111 | if (first_nibble) |
Allar | 0:dccd2df6a07c | 112 | { |
Allar | 0:dccd2df6a07c | 113 | current_byte = inByte; |
Allar | 0:dccd2df6a07c | 114 | first_nibble = false; |
Allar | 0:dccd2df6a07c | 115 | break; |
Allar | 0:dccd2df6a07c | 116 | } // end of first nibble |
Allar | 0:dccd2df6a07c | 117 | |
Allar | 0:dccd2df6a07c | 118 | // low-order nibble |
Allar | 0:dccd2df6a07c | 119 | current_byte <<= 4; |
Allar | 0:dccd2df6a07c | 120 | current_byte |= inByte; |
Allar | 0:dccd2df6a07c | 121 | first_nibble = true; |
Allar | 0:dccd2df6a07c | 122 | |
Allar | 0:dccd2df6a07c | 123 | // if we have the ETX this must be the CRC |
Allar | 0:dccd2df6a07c | 124 | if (have_etx) |
Allar | 0:dccd2df6a07c | 125 | { |
Allar | 0:dccd2df6a07c | 126 | if (crc8 (data, input_pos) != current_byte) |
Allar | 0:dccd2df6a07c | 127 | return 0; // bad crc |
Allar | 0:dccd2df6a07c | 128 | return input_pos; // return received length |
Allar | 0:dccd2df6a07c | 129 | } // end if have ETX already |
Allar | 0:dccd2df6a07c | 130 | |
Allar | 0:dccd2df6a07c | 131 | // keep adding if not full |
Allar | 0:dccd2df6a07c | 132 | if (input_pos < length) |
Allar | 0:dccd2df6a07c | 133 | data [input_pos++] = current_byte; |
Allar | 0:dccd2df6a07c | 134 | else |
Allar | 0:dccd2df6a07c | 135 | return 0; // overflow |
Allar | 0:dccd2df6a07c | 136 | break; |
Allar | 0:dccd2df6a07c | 137 | |
Allar | 0:dccd2df6a07c | 138 | } // end of switch |
Allar | 0:dccd2df6a07c | 139 | } // end of incoming data |
Allar | 0:dccd2df6a07c | 140 | } // end of while not timed out |
Allar | 0:dccd2df6a07c | 141 | |
Allar | 0:dccd2df6a07c | 142 | return 0; // timeout |
Allar | 0:dccd2df6a07c | 143 | } // end of recvMsg |