A basic library for RS485 communication

Dependencies:   BufferedSerial

Dependents:   mbed_blinko

Committer:
Allar
Date:
Mon Feb 27 21:53:25 2017 +0000
Revision:
0:dccd2df6a07c
Adding comments to library

Who changed what in which revision?

UserRevisionLine numberNew 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