├── .gitignore ├── LICENCE ├── README.md └── SerialBuster ├── Buffer.cpp ├── Buffer.h ├── SerialBuster.cpp ├── SerialBuster.h └── examples ├── echo └── echo.ino ├── fifo └── fifo.ino ├── filo └── filo.ino ├── littleendian └── littleendian.ino ├── receive └── receive.ino ├── receive_test2 └── receive_test2.ino ├── send └── send.ino └── store └── store.ino /.gitignore: -------------------------------------------------------------------------------- 1 | *.un~ 2 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, BREAKFAST LLC 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the BREAKFAST LLC nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BREAKFAST LLC BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Arduino SerialBuster 2 | 3 | A protocol for communicating between several nodes on a single serial bus. This 4 | protocol is mainly developed for an RS485 network with one master and a number 5 | of slave devices. 6 | 7 | + Non blocking, meaning no delays blocking the loop() from running 8 | + Send arbitrary sized package payloads 9 | + Binary safe 10 | + CRC8 checksum 11 | 12 | Notes 13 | -- 14 | 15 | All data is stored as bytes, unsigned int (16 bit) or unsigned long (32 bit). If 16 | you store data that needs signedness, make sure to cast it when reading it. 17 | 18 | 16 and 32 bit data structures are stored in Buffer as Little Endian. 19 | 20 | Compatible libraries 21 | -- 22 | 23 | - node.js https://github.com/breakfastny/node-serialbuster 24 | -------------------------------------------------------------------------------- /SerialBuster/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO) && ARDUINO >= 100 2 | #include "Arduino.h" 3 | #else 4 | #include "WProgram.h" 5 | #endif 6 | 7 | #include // memcpy 8 | #include "Buffer.h" 9 | 10 | Buffer::Buffer() {} 11 | 12 | void Buffer::init(uint16_t _size) { 13 | buf = (uint8_t *) calloc(_size, sizeof(uint8_t)); 14 | size = _size; 15 | length = 0; 16 | cursor_in = 0; 17 | cursor_out = 0; 18 | } 19 | 20 | // returns index of newly enqueued byte 21 | uint16_t Buffer::enqueueUInt8(uint8_t b) { 22 | uint16_t ret = 0; 23 | length++; 24 | cursor_in %= size; 25 | buf[cursor_in] = b; 26 | ret = cursor_in; 27 | cursor_in++; 28 | return ret; 29 | } 30 | 31 | uint16_t Buffer::enqueueUInt8(uint8_t * data, uint16_t len) { 32 | uint16_t ret = 0; 33 | bool first = false; 34 | for (uint16_t i=0; i> 8) & 0xFF; 93 | } 94 | 95 | uint16_t Buffer::readUInt16(uint16_t offset) { 96 | return (uint16_t) (buf[(offset+1 % size)] << 8 | buf[(offset % size)]); 97 | } 98 | 99 | void Buffer::writeUInt32(uint32_t val, uint16_t offset) { 100 | buf[offset+0 % size] = (val & 0xFF); 101 | buf[offset+1 % size] = ((val >> 8) & 0xFF); 102 | buf[offset+2 % size] = ((val >> 16) & 0xFF); 103 | buf[offset+3 % size] = ((val >> 24) & 0xFF); 104 | } 105 | 106 | uint32_t Buffer::readUInt32(uint16_t offset) { 107 | return (uint32_t) ((uint32_t) buf[offset+0 % size] | 108 | (uint32_t) buf[offset+1 % size] << 8 | 109 | (uint32_t) buf[offset+2 % size] << 16 | 110 | (uint32_t) buf[offset+3 % size] << 24); 111 | } 112 | 113 | void Buffer::writeFloat(float val, uint16_t offset) { 114 | union buffer_u u; 115 | u.f = val; 116 | for (uint8_t i = 0; i < 4; i++) 117 | buf[offset+i % size] = u.b[i]; 118 | } 119 | 120 | float Buffer::readFloat(uint16_t offset) { 121 | union buffer_u u; 122 | for (uint8_t i = 0; i < 4; i++) 123 | u.b[i] = buf[offset+i % size]; 124 | return u.f; 125 | } 126 | 127 | uint16_t Buffer::readCursorPos() { 128 | return cursor_out; 129 | } 130 | 131 | uint16_t Buffer::getDataLength() { 132 | return length; 133 | } 134 | 135 | uint16_t Buffer::getSize() { 136 | return size; 137 | } 138 | 139 | uint8_t & Buffer::operator[] (uint16_t index) { 140 | return buf[(index % size)]; 141 | } 142 | 143 | void Buffer::release() { 144 | free(buf); 145 | } 146 | 147 | Buffer::~Buffer() { 148 | release(); 149 | } 150 | -------------------------------------------------------------------------------- /SerialBuster/Buffer.h: -------------------------------------------------------------------------------- 1 | 2 | // FIFO Ring buffer of dynamic size 3 | // 4 | // Can also be used to read and write bytes 5 | // at specific indexes, altho it's stongly 6 | // discouraged to use both interfaces at the 7 | // same time for one of these intances. 8 | // all values are read and written as Little Endian. 9 | 10 | 11 | #ifndef Buffer_h 12 | #define Buffer_h 13 | 14 | #if defined(ARDUINO) && ARDUINO >= 100 15 | #include "Arduino.h" 16 | #else 17 | #include "WProgram.h" 18 | #endif 19 | 20 | // For converting floats 21 | union buffer_u { 22 | uint8_t b[4]; 23 | float f; 24 | }; 25 | 26 | class Buffer { 27 | public: 28 | Buffer(); 29 | ~Buffer(); 30 | void init(uint16_t length); 31 | 32 | // Queue functions 33 | uint16_t enqueueUInt8(uint8_t b); 34 | uint16_t enqueueUInt8(uint8_t * data, uint16_t len); 35 | uint16_t enqueueUInt16(uint16_t bb); 36 | uint8_t dequeue(); 37 | uint8_t pop(); 38 | 39 | // Index based functions 40 | void writeUInt8(uint8_t val, uint16_t offset); 41 | uint8_t readUInt8(uint16_t offset); 42 | 43 | void writeUInt16(uint16_t val, uint16_t offset); 44 | uint16_t readUInt16(uint16_t offset); 45 | 46 | void writeUInt32(uint32_t val, uint16_t offset); 47 | uint32_t readUInt32(uint16_t offset); 48 | 49 | void writeFloat(float val, uint16_t offset); 50 | float readFloat(uint16_t offset); 51 | 52 | // access position of cursor so we can read index based. 53 | uint16_t readCursorPos(); // returns the position of the read cursor. 54 | 55 | uint8_t peek(); 56 | void clear(); 57 | uint16_t getDataLength(); 58 | uint16_t getSize(); 59 | uint8_t& operator[] (uint16_t index); 60 | void release(); 61 | protected: 62 | uint8_t * buf; // main byte store 63 | uint16_t size; // size of the buffer 64 | uint16_t length; // length of data currently put in buffer 65 | uint16_t cursor_in; // cursor for writing 66 | uint16_t cursor_out; // cursor for reading 67 | }; 68 | 69 | #endif // Buffer_h 70 | -------------------------------------------------------------------------------- /SerialBuster/SerialBuster.cpp: -------------------------------------------------------------------------------- 1 | 2 | #if defined(ARDUINO) && ARDUINO >= 100 3 | #include "Arduino.h" 4 | #else 5 | #include "WProgram.h" 6 | #endif 7 | 8 | #include "SerialBuster.h" 9 | #include "Buffer.h" 10 | 11 | 12 | SerialBuster::SerialBuster(uint16_t in_size, uint16_t out_size, uint16_t max_packet_size) { 13 | _in_buf = (Buffer*)malloc(sizeof(Buffer)); 14 | _out_buf = (Buffer*)malloc(sizeof(Buffer)); 15 | _packet_buf = (Buffer*)malloc(sizeof(Buffer)); 16 | _in_buf->init(in_size); 17 | _out_buf->init(out_size); 18 | _packet_buf->init(max_packet_size); 19 | _cb = NULL; 20 | _address = 0x00; // MASTER 21 | _tx_timer = 0; 22 | _in_tx_mode = false; 23 | _useRS485pins = false; 24 | } 25 | 26 | void SerialBuster::init(long baud_rate) { 27 | Serial.begin(baud_rate); 28 | } 29 | 30 | void SerialBuster::setRS485pins(uint8_t tx_enable, uint8_t rx_enable) { 31 | pinMode(tx_enable, OUTPUT); 32 | pinMode(rx_enable, OUTPUT); 33 | _tx_enable_pin = tx_enable; 34 | _rx_enable_pin = rx_enable; 35 | _useRS485pins = true; 36 | } 37 | 38 | void SerialBuster::enableTx(bool tx_enable) { 39 | if(!_useRS485pins) { 40 | return; 41 | } 42 | // TODO: make this switch faster, more efficient by not using digitalWrite 43 | digitalWrite(_tx_enable_pin, tx_enable ? HIGH : LOW); 44 | digitalWrite(_rx_enable_pin, tx_enable ? HIGH : LOW); 45 | _in_tx_mode = tx_enable; 46 | } 47 | 48 | void SerialBuster::setAddress(uint8_t address) { 49 | _address = address; 50 | // master should be transmitting by default. 51 | if(_address == SB_MASTER) { 52 | enableTx(true); 53 | }else{ 54 | enableTx(false); 55 | } 56 | } 57 | 58 | bool SerialBuster::isSending() { 59 | return _out_buf->getDataLength() > 0; 60 | } 61 | 62 | bool SerialBuster::isReceiving() { 63 | return _in_buf->getDataLength() > 0; 64 | } 65 | 66 | uint8_t SerialBuster::sendPacket(uint8_t recipient, Buffer * payload, uint16_t length) { 67 | uint8_t pay[length]; 68 | uint16_t c = 0; 69 | while(payload->getDataLength()){ 70 | pay[c++] = payload->dequeue(); 71 | } 72 | return sendPacket(recipient, pay, length); 73 | } 74 | 75 | uint8_t SerialBuster::sendPacket(uint8_t recipient, int payload) { 76 | return sendPacket(recipient, 77 | static_cast(static_cast(&payload)), sizeof(int)); 78 | } 79 | 80 | uint8_t SerialBuster::sendPacket(uint8_t recipient, const uint8_t * payload, uint16_t length) { 81 | 82 | _packet_buf->clear(); 83 | 84 | // Write header 85 | _packet_buf->enqueueUInt8(SB_START); 86 | _packet_buf->enqueueUInt8(recipient); 87 | _packet_buf->enqueueUInt8(_address); 88 | _packet_buf->enqueueUInt16(length); 89 | 90 | // Append payload 91 | _packet_buf->enqueueUInt8((uint8_t *)payload, length); 92 | 93 | // Calculate checksum for outgoing packet 94 | uint8_t checksum = crc8((Buffer *)_packet_buf, SB_PACKET_HEADER_SIZE + length, 0); 95 | 96 | // Put the checksum in the packet 97 | _packet_buf->enqueueUInt8(checksum); 98 | 99 | // Put the start byte into the output buffer and 100 | // throw away start byte from packet buffer since we don't 101 | // want to escape it. 102 | _out_buf->enqueueUInt8(SB_START); 103 | _packet_buf->dequeue(); 104 | 105 | // Now copy _packet_buf (skip SB_START) into output buffer 106 | // and escape all data while doing so. 107 | while(_packet_buf->getDataLength()) { 108 | uint8_t b = _packet_buf->dequeue(); 109 | switch(b) { 110 | case SB_START: 111 | _out_buf->enqueueUInt8(SB_ESC); 112 | _out_buf->enqueueUInt8(SB_ESC_START); 113 | break; 114 | case SB_END: 115 | _out_buf->enqueueUInt8(SB_ESC); 116 | _out_buf->enqueueUInt8(SB_ESC_END); 117 | break; 118 | case SB_ESC: 119 | _out_buf->enqueueUInt8(SB_ESC); 120 | _out_buf->enqueueUInt8(SB_ESC_ESC); 121 | break; 122 | default: 123 | _out_buf->enqueueUInt8(b); 124 | break; 125 | } 126 | } 127 | 128 | // Finally add the END byte 129 | _out_buf->enqueueUInt8(SB_END); 130 | 131 | // open up for TX and next call to send will empty our out buffer 132 | enableTx(true); 133 | send(); 134 | } 135 | 136 | void SerialBuster::update() { 137 | 138 | // check if we should drop into RX mode 139 | if(_tx_timer != 0 && (millis() - _tx_timer) > SB_RS485_TX_GRACETIME) { // wait 10ms 140 | enableTx(false); 141 | _tx_timer = 0; 142 | } 143 | 144 | // read one byte at the time 145 | while(Serial.available() > 0) { 146 | appendIncoming(Serial.read()); 147 | } 148 | } 149 | 150 | void SerialBuster::send() { 151 | 152 | while(_out_buf->getDataLength() > 0) { 153 | if((SB_UCSRA) & (1 << SB_UDRE)) { 154 | Serial.write(_out_buf->dequeue()); 155 | } 156 | } 157 | 158 | // we've emptied our buffer into 159 | // the serial output. if we're not 160 | // master we should start a timer 161 | // for when to disable TX. 162 | if(_address != SB_MASTER) { 163 | _tx_timer = millis(); 164 | } 165 | 166 | } 167 | 168 | void SerialBuster::setCallback(void (*cb)(uint8_t recipient, Buffer * payload, uint16_t length)) { 169 | _cb = cb; 170 | } 171 | 172 | void SerialBuster::appendIncoming(uint8_t inbyte){ 173 | 174 | // TODO: Read head as soon as it's written and if recipient isn't for us, then 175 | // we can set a flag to ignore LENGTH many incoming bytes. 176 | 177 | uint16_t checksum_index = 0; 178 | uint8_t checksum; 179 | uint8_t recipient; 180 | uint8_t sender; 181 | uint16_t esc_wait = 400; // max ticks to wait for next char 182 | 183 | switch(inbyte) { 184 | 185 | // We're starting a new packet 186 | case SB_START: 187 | _in_buf->clear(); 188 | //Serial.print('S'); 189 | // save startbyte since we need it for crc8 check 190 | _in_buf->enqueueUInt8(inbyte); 191 | break; 192 | 193 | // if it's an END character then we're done with the packet 194 | case SB_END: 195 | // last piece of the packet stored. 196 | _in_buf->enqueueUInt8(inbyte); 197 | //Serial.print('E'); 198 | 199 | // Check the recipient 200 | recipient = _in_buf->readUInt8(1); 201 | 202 | // wrong recipient 203 | if(recipient != _address && recipient != SB_BROADCAST) { 204 | //Serial.print('R'); 205 | return; 206 | } 207 | 208 | // Now we'll see if the packet if valid by 209 | // making a CRC8 check on the header + payload 210 | checksum_index = _in_buf->getDataLength() - 2; 211 | checksum = crc8((Buffer *)_in_buf, checksum_index, 0); 212 | 213 | if(checksum == _in_buf->readUInt8(checksum_index) && _cb != NULL) { 214 | 215 | // TODO: Make copy of the payload and send it to _cb 216 | sender = _in_buf->readUInt8(2); 217 | 218 | // forward out cursor past the header so the next call to dequeue 219 | // will start returning payload data. 220 | for(uint8_t i = 0; i < SB_PACKET_HEADER_SIZE; ++i){ 221 | _in_buf->dequeue(); 222 | } 223 | 224 | // remove tail bytes 225 | _in_buf->pop(); 226 | _in_buf->pop(); 227 | 228 | // dispatch payload 229 | _cb(sender, _in_buf, _in_buf->getDataLength()); 230 | return; 231 | }else{ 232 | // Bad checksum or no callback 233 | // 234 | //Serial.print('C'); 235 | } 236 | 237 | break; 238 | 239 | // if it's the same code as an ESC character, we'll wait for the next char and see what to do 240 | case SB_ESC: 241 | 242 | do { 243 | inbyte = Serial.read(); 244 | } while (inbyte == 255 && esc_wait-- != 0); 245 | 246 | // Serial.print("E"); 247 | // Serial.write(inbyte); 248 | 249 | switch(inbyte) { 250 | 251 | //if "inbyte" is not one of these two, then we 252 | //have a protocol violation. The best bet 253 | //seems to be to leave the byte alone and 254 | //just stuff it into the packet 255 | // 256 | case SB_ESC_END: 257 | inbyte = SB_END; 258 | break; 259 | case SB_ESC_START: 260 | inbyte = SB_START; 261 | break; 262 | case SB_ESC_ESC: 263 | inbyte = SB_ESC; 264 | break; 265 | } 266 | 267 | // here we fall into the default handler and let 268 | // it store the character for us 269 | default: 270 | //Serial.print('P'); 271 | _in_buf->enqueueUInt8(inbyte); 272 | } 273 | } 274 | 275 | uint8_t SerialBuster::crc8(Buffer * data, uint16_t len, uint16_t offset) { 276 | uint8_t crc=0; 277 | for (uint16_t i=offset; ireadUInt8(i); 279 | for (uint8_t j=0;j<8;j++){ 280 | uint8_t mix = (crc ^ inbyte) & 0x01; 281 | crc >>= 1; 282 | if (mix) 283 | crc ^= 0x8C; 284 | inbyte >>= 1; 285 | } 286 | } 287 | return crc; 288 | } 289 | 290 | 291 | SerialBuster::~SerialBuster() { 292 | free(_in_buf); 293 | free(_out_buf); 294 | free(_packet_buf); 295 | } 296 | -------------------------------------------------------------------------------- /SerialBuster/SerialBuster.h: -------------------------------------------------------------------------------- 1 | // Serial read/write over rs485 with automatic tx/rx switching 2 | // some basic inspiration from J. Romkey SLIP http://www.ietf.org/rfc/rfc1055.txt 3 | 4 | // Supports the use of custom commands and custom callbacks each command 5 | 6 | // Protocol structure: 7 | // START 1byte (uint8) 8 | // RECIPIENT 1byte (uint8) 9 | // SENDER 1byte (uint8) 10 | // LENGTH 2byte (uint16) 11 | // PAYLOAD Nbyte 12 | // CRC8 1byte (uint8) 13 | // END 1byte (uint8) 14 | 15 | 16 | #ifndef SerialBuster_h 17 | #define SerialBuster_h 18 | 19 | #if defined(ARDUINO) && ARDUINO >= 100 20 | #include "Arduino.h" 21 | #else 22 | #include "WProgram.h" 23 | #endif 24 | 25 | #include "Buffer.h" 26 | 27 | typedef void (*event_cb_t)(uint8_t recipient, Buffer * payload, uint16_t length); 28 | 29 | // for checking if the serial line is busy 30 | #if defined(__AVR_ATmega8__) 31 | #define SB_UCSRA UCSRA 32 | #define SB_UDRE UDRE 33 | #else 34 | #define SB_UCSRA UCSR0A 35 | #define SB_UDRE UDRE0 36 | #endif 37 | 38 | // protocol constants 39 | #define SB_START 0x02 40 | #define SB_ESC 0x1B 41 | #define SB_END 0x03 42 | #define SB_ESC_END 0x1C 43 | #define SB_ESC_ESC 0x1D 44 | #define SB_ESC_START 0x1E 45 | #define SB_BROADCAST 0xFF 46 | #define SB_MASTER 0x00 47 | 48 | #define SB_ENVELOPE_SIZE 7 49 | #define SB_PACKET_HEADER_SIZE 5 50 | #define SB_RS485_TX_GRACETIME 2 //ms 51 | 52 | class SerialBuster { 53 | public: 54 | SerialBuster(uint16_t in_size, uint16_t out_size, uint16_t max_packet_size); 55 | ~SerialBuster(); 56 | void init(long baud_rate); 57 | void setRS485pins(uint8_t tx_enable, uint8_t rx_enable); 58 | void enableTx(bool tx_enable); 59 | void setCallback(void (*cb)(uint8_t recipient, Buffer * payload, uint16_t length)); 60 | void setAddress(uint8_t address); 61 | 62 | void send(); 63 | void update(); // call in loop 64 | 65 | bool isSending(); 66 | bool isReceiving(); 67 | 68 | uint8_t sendPacket(uint8_t recipient, Buffer * payload, uint16_t length); 69 | uint8_t sendPacket(uint8_t recipient, int payload); 70 | uint8_t sendPacket(uint8_t recipient, const uint8_t * payload, uint16_t length); 71 | uint8_t crc8(Buffer * data, uint16_t len, uint16_t offset); 72 | 73 | protected: 74 | void appendIncoming(uint8_t incoming); 75 | 76 | event_cb_t _cb; 77 | Buffer* _in_buf; 78 | Buffer* _out_buf; 79 | Buffer* _packet_buf; 80 | uint16_t _address; 81 | uint8_t _tx_enable_pin; 82 | uint8_t _rx_enable_pin; 83 | bool _in_tx_mode; 84 | uint64_t _tx_timer; // timer for when to disable tx. 85 | bool _useRS485pins; 86 | }; 87 | 88 | 89 | #endif // SerialBuster_h 90 | -------------------------------------------------------------------------------- /SerialBuster/examples/echo/echo.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | SerialBuster sb = SerialBuster(256, 256, 128); 5 | boolean led_toggle = true; 6 | long mover = 0; 7 | 8 | 9 | void setup() { 10 | pinMode(13, OUTPUT); 11 | digitalWrite(13, LOW); 12 | sb.init(115200); 13 | sb.setCallback(incomingPacket); 14 | sb.setAddress(1); 15 | delay(50); 16 | } 17 | 18 | void loop() { 19 | sb.update(); 20 | 21 | // if(mover++ % 100000 == 0) { 22 | // Serial.print("mem: "); 23 | // Serial.println((((float)availableMemory()) / 2048.0) * 100); 24 | // Serial.flush(); 25 | // } 26 | } 27 | 28 | void incomingPacket (uint8_t from, Buffer * buffer) { 29 | blink_led(); 30 | uint16_t length = buffer->getDataLength(); 31 | uint8_t payload[length]; 32 | int i = 0; 33 | while(buffer->getDataLength()) { 34 | payload[i++] = buffer->dequeue(); 35 | } 36 | // echo payload back to sender 37 | sb.sendPacket(from, payload, length); 38 | } 39 | 40 | void blink_led() { 41 | digitalWrite(13, led_toggle ? HIGH : LOW); 42 | led_toggle = !led_toggle; 43 | } 44 | 45 | // only for debugging 46 | int availableMemory() { 47 | int size = 2048; // Use 2048 with ATmega328 48 | byte *buf; 49 | while ((buf = (byte *) malloc(--size)) == NULL) 50 | ; 51 | 52 | free(buf); 53 | return size; 54 | } 55 | -------------------------------------------------------------------------------- /SerialBuster/examples/fifo/fifo.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | Buffer b = Buffer(); 5 | 6 | void setup() { 7 | //ser.init(9600); 8 | Serial.begin(9600); 9 | Serial.println("init"); 10 | b.init(16); 11 | 12 | delay(100); 13 | 14 | b.enqueueUInt8(1); 15 | b.enqueueUInt8(2); 16 | b.enqueueUInt8(3); 17 | 18 | while(b.getDataLength()) 19 | Serial.println(b.dequeue()); 20 | 21 | b.enqueueUInt8(-4); 22 | b.enqueueUInt8(-51); 23 | 24 | while(b.getDataLength()) 25 | Serial.println((int8_t)b.dequeue()); 26 | 27 | } 28 | 29 | void loop() { 30 | 31 | } 32 | -------------------------------------------------------------------------------- /SerialBuster/examples/filo/filo.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | Buffer b = Buffer(); 5 | 6 | void setup() { 7 | //ser.init(9600); 8 | Serial.begin(57600); 9 | Serial.println("init"); 10 | b.init(16); 11 | 12 | delay(100); 13 | 14 | b.enqueueUInt8(1); 15 | b.enqueueUInt8(2); 16 | b.enqueueUInt8(3); 17 | 18 | while(b.getDataLength()) 19 | Serial.println(b.pop()); 20 | 21 | b.enqueueUInt8(4); 22 | Serial.println(b.pop()); 23 | } 24 | 25 | void loop() { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /SerialBuster/examples/littleendian/littleendian.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | Buffer b = Buffer(); 5 | 6 | void setup() { 7 | //ser.init(9600); 8 | Serial.begin(9600); 9 | Serial.println("init"); 10 | b.init(16); 11 | 12 | delay(100); 13 | 14 | b.writeUInt16(12345, 0); 15 | 16 | int i = b[1] << 8 | b[0]; 17 | 18 | Serial.print("12345 == "); 19 | Serial.println(i); 20 | 21 | Serial.print("12345 == "); 22 | Serial.println(b.readUInt16(0)); 23 | 24 | } 25 | 26 | void loop() { 27 | 28 | } 29 | -------------------------------------------------------------------------------- /SerialBuster/examples/receive/receive.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | #define FLOAT_TOLERANCE 0.0001 5 | 6 | union u_tag { 7 | uint8_t b[4]; 8 | float f; 9 | }; 10 | 11 | SerialBuster sb = SerialBuster(256, 256, 128); 12 | int testCase = 1; 13 | 14 | void setup() { 15 | pinMode(13, OUTPUT); 16 | digitalWrite(13, LOW); 17 | sb.init(9600); 18 | sb.setCallback(incomingPacket); 19 | send(2); 20 | } 21 | 22 | void loop() { 23 | sb.update(); 24 | } 25 | 26 | void incomingPacket (uint8_t from, Buffer * buffer, uint16_t len) { 27 | 28 | uint8_t payload[len]; 29 | int counter = 0; 30 | while(buffer->getDataLength()) { 31 | payload[counter++] = buffer->dequeue(); 32 | } 33 | 34 | switch(testCase) { 35 | 36 | case 1: 37 | payload[0] == 0x01 ? ok() : fail(); 38 | break; 39 | 40 | 41 | case 2: 42 | payload[0] == 0xCA ? ok() : fail(); 43 | break; 44 | 45 | 46 | case 3: 47 | (int)(payload[1] << 8 | payload[0]) == 12345 ? ok() : fail(); 48 | break; 49 | 50 | 51 | case 4: 52 | (long)(payload[3] << 24 | payload[2] << 16 | payload[1] << 8 | payload[0]) == 100 * 1000 * 1000 ? ok() : fail(); 53 | break; 54 | 55 | 56 | case 5: 57 | (long)(payload[3] << 24 | payload[2] << 16 | payload[1] << 8 | payload[0]) == 100 * 1000 * 1000 * -1 ? ok() : fail(); 58 | break; 59 | 60 | 61 | case 6: 62 | (int)(payload[1] << 8 | payload[0]) == -10293 ? ok() : fail(); 63 | break; 64 | 65 | 66 | case 7: 67 | union u_tag u1; 68 | for (int i = 0; i < 4; i++) 69 | u1.b[i] = payload[i]; 70 | 71 | abs(u1.f - 5.1) < FLOAT_TOLERANCE ? ok() : fail(); 72 | break; 73 | 74 | 75 | case 8: 76 | union u_tag u2; 77 | for (int i = 0; i < 4; i++) 78 | u2.b[i] = payload[i]; 79 | 80 | abs(u2.f - (-39172.3971)) < FLOAT_TOLERANCE ? ok() : fail(); 81 | break; 82 | 83 | }; 84 | 85 | 86 | // get ready for the next test 87 | testCase++; 88 | 89 | // tell master we're ready 90 | } 91 | 92 | void ok() { 93 | digitalWrite(13, HIGH); 94 | delay(200); 95 | digitalWrite(13, LOW); 96 | delay(50); 97 | send(1); 98 | } 99 | 100 | void fail() { 101 | for(int i = 0; i < 10; i++) { 102 | digitalWrite(13, HIGH); 103 | delay(50); 104 | digitalWrite(13, LOW); 105 | delay(50); 106 | } 107 | send(0); 108 | } 109 | 110 | void send(int n) { 111 | sb.sendPacket(SB_MASTER, n); 112 | } 113 | 114 | // only for debugging 115 | int availableMemory() { 116 | int size = 2048; // Use 2048 with ATmega328 117 | byte *buf; 118 | while ((buf = (byte *) malloc(--size)) == NULL) 119 | ; 120 | 121 | free(buf); 122 | return size; 123 | } 124 | -------------------------------------------------------------------------------- /SerialBuster/examples/receive_test2/receive_test2.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | #define FLOAT_TOLERANCE 0.0001 5 | 6 | union u_tag { 7 | uint8_t b[4]; 8 | float f; 9 | }; 10 | 11 | SerialBuster sb = SerialBuster(256, 256, 128); 12 | int testCase = 1; 13 | 14 | void setup() { 15 | pinMode(13, OUTPUT); 16 | digitalWrite(13, LOW); 17 | sb.init(9600); 18 | sb.setCallback(incomingPacket); 19 | delay(5000); 20 | send(2); 21 | } 22 | 23 | void loop() { 24 | sb.update(); 25 | } 26 | 27 | void incomingPacket (uint8_t from, Buffer * buffer, uint16_t len) { 28 | 29 | int readcursor = buffer->readCursorPos(); 30 | 31 | switch(testCase) { 32 | 33 | case 1: 34 | buffer->readUInt8(readcursor) == 0x01 ? ok() : fail(); 35 | break; 36 | 37 | 38 | case 2: 39 | buffer->readUInt8(readcursor) == 0xCA ? ok() : fail(); 40 | break; 41 | 42 | 43 | case 3: 44 | buffer->readUInt16(readcursor) == 12345 ? ok() : fail(); 45 | break; 46 | 47 | 48 | case 4: 49 | (long)buffer->readUInt32(readcursor) == 100l * 1000l * 1000l ? ok() : fail(); 50 | break; 51 | 52 | 53 | case 5: 54 | (long)buffer->readUInt32(readcursor) == 100l * 1000l * 1000l * -1 ? ok() : fail(); 55 | break; 56 | 57 | 58 | case 6: 59 | (int)buffer->readUInt16(readcursor) == -10293 ? ok() : fail(); 60 | break; 61 | 62 | 63 | case 7: 64 | abs(buffer->readFloat(readcursor) - 5.1) < FLOAT_TOLERANCE ? ok() : fail(); 65 | break; 66 | 67 | 68 | case 8: 69 | abs(buffer->readFloat(readcursor) - (-39172.3971)) < FLOAT_TOLERANCE ? ok() : fail(); 70 | break; 71 | 72 | 73 | case 9: 74 | buffer->readUInt8(readcursor) == 'a' ? ok() : fail(); 75 | break; 76 | 77 | 78 | case 10: 79 | char a = buffer->readUInt8(readcursor); 80 | char b = buffer->readUInt8(readcursor + 1); 81 | char bang = buffer->readUInt8(readcursor + 2); 82 | (a == 'a' && b == 'b' && bang == '!') ? ok() : fail(); 83 | break; 84 | 85 | }; 86 | 87 | 88 | // get ready for the next test 89 | testCase++; 90 | } 91 | 92 | void ok() { 93 | digitalWrite(13, HIGH); 94 | delay(200); 95 | digitalWrite(13, LOW); 96 | delay(50); 97 | send(1); 98 | } 99 | 100 | void fail() { 101 | for(int i = 0; i < 10; i++) { 102 | digitalWrite(13, HIGH); 103 | delay(50); 104 | digitalWrite(13, LOW); 105 | delay(50); 106 | } 107 | send(0); 108 | } 109 | 110 | void send(int n) { 111 | sb.sendPacket(SB_MASTER, n); 112 | } 113 | 114 | // only for debugging 115 | int availableMemory() { 116 | int size = 2048; // Use 2048 with ATmega328 117 | byte *buf; 118 | while ((buf = (byte *) malloc(--size)) == NULL) 119 | ; 120 | 121 | free(buf); 122 | return size; 123 | } 124 | -------------------------------------------------------------------------------- /SerialBuster/examples/send/send.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | SerialBuster sb = SerialBuster(256, 256, 128); 5 | long mover = 0; 6 | 7 | void setup() { 8 | pinMode(13, OUTPUT); 9 | digitalWrite(13, LOW); 10 | sb.init(9600); 11 | //sb.setCallback(incomingPacket); 12 | delay(50); 13 | } 14 | 15 | void loop() { 16 | sb.update(); 17 | if(mover++ % 10000 == 0) { 18 | 19 | // const uint8_t * payload = (const uint8_t *)"An end (\x03) char!"; 20 | // sb.sendPacket(255, payload, strlen((const char *)payload)); 21 | 22 | int a = availableMemory(); 23 | float percent = ((float)a) / 2048.0; 24 | Serial.print("mem: "); 25 | Serial.println(percent * 100); 26 | } 27 | } 28 | 29 | // only for debugging 30 | int availableMemory() { 31 | int size = 2048; // Use 2048 with ATmega328 32 | byte *buf; 33 | while ((buf = (byte *) malloc(--size)) == NULL) 34 | ; 35 | 36 | free(buf); 37 | return size; 38 | } 39 | -------------------------------------------------------------------------------- /SerialBuster/examples/store/store.ino: -------------------------------------------------------------------------------- 1 | #include "SerialBuster.h" 2 | #include "Buffer.h" 3 | 4 | Buffer b = Buffer(); 5 | 6 | void setup() { 7 | //ser.init(9600); 8 | Serial.begin(9600); 9 | Serial.println("init"); 10 | b.init(256); 11 | 12 | //delay(100); 13 | 14 | // store using [] operator 15 | b[0] = 1; 16 | b[1] = 2; 17 | b[2] = -3; 18 | 19 | Serial.println(b[0]); 20 | Serial.println(b[1]); 21 | Serial.println((int8_t)b[2]); 22 | 23 | // store 16bit vars 24 | b.writeUInt16(65535, 2); 25 | Serial.println(b.readUInt16(2)); 26 | 27 | b.writeUInt16(-25000, 2); 28 | Serial.println((int)b.readUInt16(2)); 29 | 30 | //b.clear(); 31 | 32 | b.writeUInt8(0xCA, 0); 33 | Serial.println(b.readUInt8(0), HEX); 34 | 35 | uint32_t l = 2000l * 1000l * 1000l; // two billion 36 | b.writeUInt32(l, 0); 37 | Serial.println(b.readUInt32(0)); 38 | 39 | 40 | int32_t l2 = 2000l * 1000l * 1000 *-1l; // negative two billion 41 | b.writeUInt32(l2, 0); 42 | Serial.println((int32_t)b.readUInt32(0)); 43 | 44 | float f1 = 123.456; 45 | b.writeFloat(f1, 0); 46 | Serial.println(b.readFloat(0), 3); 47 | 48 | float f2 = -123.456; 49 | b.writeFloat(f2, 0); 50 | Serial.println(b.readFloat(0), 3); 51 | 52 | 53 | } 54 | 55 | void loop() { 56 | 57 | } 58 | --------------------------------------------------------------------------------