Jordan Earls
/
pjon_testing
Testing getting PJON working on mbed https://github.com/gioblu/PJON
pjon.cpp@1:bd0ee507dd4c, 2016-01-10 (annotated)
- Committer:
- earlz
- Date:
- Sun Jan 10 09:41:00 2016 +0000
- Revision:
- 1:bd0ee507dd4c
- Parent:
- 0:fa2f348efd7e
- Child:
- 2:5648483c5dbc
Use the network analysis example
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
earlz | 0:fa2f348efd7e | 1 | |
earlz | 0:fa2f348efd7e | 2 | /*-O//\ __ __ |
earlz | 0:fa2f348efd7e | 3 | |-gfo\ |__| | | | |\ | |
earlz | 0:fa2f348efd7e | 4 | |!y°o:\ | __| |__| | \| v1.0 |
earlz | 0:fa2f348efd7e | 5 | |y"s§+`\ Giovanni Blu Mitolo 2012 - 2015 |
earlz | 0:fa2f348efd7e | 6 | /so+:-..`\ gioscarab@gmail.com |
earlz | 0:fa2f348efd7e | 7 | |+/:ngr-*.`\ |
earlz | 0:fa2f348efd7e | 8 | |5/:%&-a3f.:;\ PJON is a device communications bus system that connects up to 255 |
earlz | 0:fa2f348efd7e | 9 | \+//u/+g%{osv,,\ arduino boards over one wire up to 5.29kB/s data communication speed. |
earlz | 0:fa2f348efd7e | 10 | \=+&/osw+olds.\\ Contains acknowledge, collision detection, CRC and encpryption all done |
earlz | 0:fa2f348efd7e | 11 | \:/+-.-°-:+oss\ with micros() and delayMicroseconds(), with no use of interrupts or timers. |
earlz | 0:fa2f348efd7e | 12 | | | \oy\\ Pull down resistor on the bus is generally used to reduce interference. |
earlz | 0:fa2f348efd7e | 13 | > < |
earlz | 0:fa2f348efd7e | 14 | -| |- |
earlz | 0:fa2f348efd7e | 15 | |
earlz | 0:fa2f348efd7e | 16 | Copyright (c) 2012-2015, Giovanni Blu Mitolo All rights reserved. |
earlz | 0:fa2f348efd7e | 17 | |
earlz | 0:fa2f348efd7e | 18 | Redistribution and use in source and binary forms, with or without |
earlz | 0:fa2f348efd7e | 19 | modification, are permitted provided that the following conditions are met: |
earlz | 0:fa2f348efd7e | 20 | - Redistributions of source code must retain the above copyright |
earlz | 0:fa2f348efd7e | 21 | notice, this list of conditions and the following disclaimer. |
earlz | 0:fa2f348efd7e | 22 | |
earlz | 0:fa2f348efd7e | 23 | - Redistributions in binary form must reproduce the above copyright |
earlz | 0:fa2f348efd7e | 24 | notice, this list of conditions and the following disclaimer in the |
earlz | 0:fa2f348efd7e | 25 | documentation and/or other materials provided with the distribution. |
earlz | 0:fa2f348efd7e | 26 | |
earlz | 0:fa2f348efd7e | 27 | - All advertising materials mentioning features or use of this software |
earlz | 0:fa2f348efd7e | 28 | must display the following acknowledgement: |
earlz | 0:fa2f348efd7e | 29 | This product includes PJON software developed by Giovanni Blu Mitolo. |
earlz | 0:fa2f348efd7e | 30 | |
earlz | 0:fa2f348efd7e | 31 | - Neither the name of PJON, PJON_ASK nor the |
earlz | 0:fa2f348efd7e | 32 | names of its contributors may be used to endorse or promote products |
earlz | 0:fa2f348efd7e | 33 | derived from this software without specific prior written permission. |
earlz | 0:fa2f348efd7e | 34 | |
earlz | 0:fa2f348efd7e | 35 | This software is provided by the copyright holders and contributors"as is" |
earlz | 0:fa2f348efd7e | 36 | and any express or implied warranties, including, but not limited to, the |
earlz | 0:fa2f348efd7e | 37 | implied warranties of merchantability and fitness for a particular purpose |
earlz | 0:fa2f348efd7e | 38 | are disclaimed. In no event shall the copyright holder or contributors be |
earlz | 0:fa2f348efd7e | 39 | liable for any direct, indirect, incidental, special, exemplary, or consequential |
earlz | 0:fa2f348efd7e | 40 | damages (including, but not limited to, procurement of substitute goods or services; |
earlz | 0:fa2f348efd7e | 41 | loss of use, data, or profits; or business interruption) however caused and on any |
earlz | 0:fa2f348efd7e | 42 | theory of liability, whether in contract, strict liability, or tort (including |
earlz | 0:fa2f348efd7e | 43 | negligence or otherwise) arising in any way out of the use of this software, even if |
earlz | 0:fa2f348efd7e | 44 | advised of the possibility of such damage. */ |
earlz | 0:fa2f348efd7e | 45 | |
earlz | 0:fa2f348efd7e | 46 | #include "pjon.h" |
earlz | 0:fa2f348efd7e | 47 | |
earlz | 0:fa2f348efd7e | 48 | /* Initiate PJON passing pin number: |
earlz | 0:fa2f348efd7e | 49 | Device's id has to be set through set_id() |
earlz | 0:fa2f348efd7e | 50 | before transmitting on the PJON network. */ |
earlz | 0:fa2f348efd7e | 51 | |
earlz | 0:fa2f348efd7e | 52 | PJON::PJON(PinName input_pin) : _input_pin(input_pin){ |
earlz | 0:fa2f348efd7e | 53 | //_input_pin = DigitalInOut(input_pin); |
earlz | 0:fa2f348efd7e | 54 | this->initialize(); |
earlz | 0:fa2f348efd7e | 55 | } |
earlz | 0:fa2f348efd7e | 56 | |
earlz | 0:fa2f348efd7e | 57 | |
earlz | 0:fa2f348efd7e | 58 | /* Initiate PJON passing pin number and the device's id: */ |
earlz | 0:fa2f348efd7e | 59 | |
earlz | 0:fa2f348efd7e | 60 | PJON::PJON(PinName input_pin, uint8_t device_id) : _input_pin(input_pin) { |
earlz | 0:fa2f348efd7e | 61 | _device_id = device_id; |
earlz | 0:fa2f348efd7e | 62 | this->initialize(); |
earlz | 0:fa2f348efd7e | 63 | } |
earlz | 0:fa2f348efd7e | 64 | |
earlz | 0:fa2f348efd7e | 65 | |
earlz | 0:fa2f348efd7e | 66 | /* Initialization tasks: */ |
earlz | 0:fa2f348efd7e | 67 | |
earlz | 0:fa2f348efd7e | 68 | void PJON::initialize() { |
earlz | 0:fa2f348efd7e | 69 | this->set_error(dummy_error_handler); |
earlz | 0:fa2f348efd7e | 70 | _reg_timer.start(); |
earlz | 0:fa2f348efd7e | 71 | for(int i = 0; i < MAX_PACKETS; i++) { |
earlz | 0:fa2f348efd7e | 72 | packets[i].state = NULL; |
earlz | 0:fa2f348efd7e | 73 | packets[i].timing = 0; |
earlz | 0:fa2f348efd7e | 74 | packets[i].attempts = 0; |
earlz | 0:fa2f348efd7e | 75 | } |
earlz | 0:fa2f348efd7e | 76 | } |
earlz | 0:fa2f348efd7e | 77 | |
earlz | 0:fa2f348efd7e | 78 | |
earlz | 0:fa2f348efd7e | 79 | /* Set the device id, passing a single byte (watch out to id collision) */ |
earlz | 0:fa2f348efd7e | 80 | |
earlz | 0:fa2f348efd7e | 81 | void PJON::set_id(uint8_t id) { |
earlz | 0:fa2f348efd7e | 82 | _device_id = id; |
earlz | 0:fa2f348efd7e | 83 | } |
earlz | 0:fa2f348efd7e | 84 | |
earlz | 0:fa2f348efd7e | 85 | |
earlz | 0:fa2f348efd7e | 86 | /* Pass as a parameter a void function you previously defined in your code. |
earlz | 0:fa2f348efd7e | 87 | This will be called when a correct message will be received. |
earlz | 0:fa2f348efd7e | 88 | Inside there you can code how to react when data is received. |
earlz | 0:fa2f348efd7e | 89 | |
earlz | 0:fa2f348efd7e | 90 | void receiver_function(uint8_t length, uint8_t *payload) { |
earlz | 0:fa2f348efd7e | 91 | for(int i = 0; i < length; i++) |
earlz | 0:fa2f348efd7e | 92 | Serial.print((char)payload[i]); |
earlz | 0:fa2f348efd7e | 93 | |
earlz | 0:fa2f348efd7e | 94 | Serial.print(" "); |
earlz | 0:fa2f348efd7e | 95 | Serial.println(length); |
earlz | 0:fa2f348efd7e | 96 | }; |
earlz | 0:fa2f348efd7e | 97 | |
earlz | 0:fa2f348efd7e | 98 | network.set_receiver(receiver_function); */ |
earlz | 0:fa2f348efd7e | 99 | |
earlz | 0:fa2f348efd7e | 100 | void PJON::set_receiver(receiver r) { |
earlz | 0:fa2f348efd7e | 101 | _receiver = r; |
earlz | 0:fa2f348efd7e | 102 | } |
earlz | 0:fa2f348efd7e | 103 | |
earlz | 0:fa2f348efd7e | 104 | |
earlz | 0:fa2f348efd7e | 105 | /* Pass as a parameter a void function you previously defined in your code. |
earlz | 0:fa2f348efd7e | 106 | This will be called when an error in communication occurs |
earlz | 0:fa2f348efd7e | 107 | |
earlz | 0:fa2f348efd7e | 108 | void error_handler(uint8_t code, uint8_t data) { |
earlz | 0:fa2f348efd7e | 109 | Serial.print(code); |
earlz | 0:fa2f348efd7e | 110 | Serial.print(" "); |
earlz | 0:fa2f348efd7e | 111 | Serial.println(data); |
earlz | 0:fa2f348efd7e | 112 | }; |
earlz | 0:fa2f348efd7e | 113 | |
earlz | 0:fa2f348efd7e | 114 | network.set_error(error_handler); */ |
earlz | 0:fa2f348efd7e | 115 | |
earlz | 0:fa2f348efd7e | 116 | void PJON::set_error(pjon_error e) { |
earlz | 0:fa2f348efd7e | 117 | _error = e; |
earlz | 0:fa2f348efd7e | 118 | } |
earlz | 0:fa2f348efd7e | 119 | |
earlz | 0:fa2f348efd7e | 120 | |
earlz | 0:fa2f348efd7e | 121 | /* Check if the channel is free for transmission: |
earlz | 0:fa2f348efd7e | 122 | If an entire byte received contains no 1s it means |
earlz | 0:fa2f348efd7e | 123 | that there is no active transmission */ |
earlz | 0:fa2f348efd7e | 124 | |
earlz | 0:fa2f348efd7e | 125 | bool PJON::can_start() { |
earlz | 0:fa2f348efd7e | 126 | _input_pin.input(); //pinMode(_input_pin, INPUT); |
earlz | 0:fa2f348efd7e | 127 | this->send_bit(0, 2); |
earlz | 0:fa2f348efd7e | 128 | if(!this->read_byte()) |
earlz | 0:fa2f348efd7e | 129 | return true; |
earlz | 0:fa2f348efd7e | 130 | |
earlz | 0:fa2f348efd7e | 131 | return false; |
earlz | 0:fa2f348efd7e | 132 | } |
earlz | 0:fa2f348efd7e | 133 | |
earlz | 0:fa2f348efd7e | 134 | |
earlz | 0:fa2f348efd7e | 135 | /* Send a bit to the pin: |
earlz | 0:fa2f348efd7e | 136 | digitalWriteFast is used instead of standard digitalWrite |
earlz | 0:fa2f348efd7e | 137 | function to optimize transmission time */ |
earlz | 0:fa2f348efd7e | 138 | |
earlz | 0:fa2f348efd7e | 139 | void PJON::send_bit(uint8_t VALUE, int duration) { |
earlz | 1:bd0ee507dd4c | 140 | _input_pin = VALUE > 0; //digitalWrite(_input_pin, VALUE); |
earlz | 0:fa2f348efd7e | 141 | wait_us(duration); |
earlz | 0:fa2f348efd7e | 142 | } |
earlz | 0:fa2f348efd7e | 143 | |
earlz | 0:fa2f348efd7e | 144 | |
earlz | 0:fa2f348efd7e | 145 | /* Every byte is prepended with 2 synchronization padding bits. The first |
earlz | 0:fa2f348efd7e | 146 | is a longer than standard logic 1 followed by a standard logic 0. |
earlz | 0:fa2f348efd7e | 147 | __________ ___________________________ |
earlz | 0:fa2f348efd7e | 148 | | SyncPad | Byte | |
earlz | 0:fa2f348efd7e | 149 | |______ |___ ___ _____ | |
earlz | 0:fa2f348efd7e | 150 | | | | | | | | | | | |
earlz | 0:fa2f348efd7e | 151 | | | 1 | 0 | 1 | 0 0 | 1 | 0 | 1 1 | 0 | |
earlz | 0:fa2f348efd7e | 152 | |_|____|___|___|_____|___|___|_____|___| |
earlz | 0:fa2f348efd7e | 153 | | |
earlz | 0:fa2f348efd7e | 154 | ACCEPTANCE |
earlz | 0:fa2f348efd7e | 155 | |
earlz | 0:fa2f348efd7e | 156 | The reception tecnique is based on finding a logic 1 as long as the |
earlz | 0:fa2f348efd7e | 157 | first padding bit within a certain threshold, synchronizing to its |
earlz | 0:fa2f348efd7e | 158 | falling edge and checking if it is followed by a logic 0. If this |
earlz | 0:fa2f348efd7e | 159 | pattern is recognised, reception starts, if not, interference, |
earlz | 0:fa2f348efd7e | 160 | synchronization loss or simply absence of communication is |
earlz | 0:fa2f348efd7e | 161 | detected at byte level. */ |
earlz | 0:fa2f348efd7e | 162 | |
earlz | 0:fa2f348efd7e | 163 | void PJON::send_byte(uint8_t b) { |
earlz | 0:fa2f348efd7e | 164 | _input_pin = 1; //digitalWriteFast(_input_pin, HIGH); |
earlz | 0:fa2f348efd7e | 165 | wait_us(BIT_SPACER); |
earlz | 0:fa2f348efd7e | 166 | _input_pin = 0; //digitalWriteFast(_input_pin, LOW); |
earlz | 0:fa2f348efd7e | 167 | wait_us(BIT_WIDTH); |
earlz | 0:fa2f348efd7e | 168 | |
earlz | 0:fa2f348efd7e | 169 | for(uint8_t mask = 0x01; mask; mask <<= 1) { |
earlz | 1:bd0ee507dd4c | 170 | _input_pin = (b & mask) > 0; //digitalWriteFast(_input_pin, b & mask); |
earlz | 0:fa2f348efd7e | 171 | wait_us(BIT_WIDTH); |
earlz | 0:fa2f348efd7e | 172 | } |
earlz | 0:fa2f348efd7e | 173 | } |
earlz | 0:fa2f348efd7e | 174 | |
earlz | 0:fa2f348efd7e | 175 | |
earlz | 0:fa2f348efd7e | 176 | /* An Example of how the string "@" is formatted and sent: |
earlz | 0:fa2f348efd7e | 177 | |
earlz | 0:fa2f348efd7e | 178 | ID 12 LENGTH 4 CONTENT 64 CRC 130 |
earlz | 0:fa2f348efd7e | 179 | ________________ ________________ ________________ __________________ |
earlz | 0:fa2f348efd7e | 180 | |Sync | Byte |Sync | Byte |Sync | Byte |Sync | Byte | |
earlz | 0:fa2f348efd7e | 181 | |___ | __ |___ | _ |___ | _ |___ | _ _ | |
earlz | 0:fa2f348efd7e | 182 | | | | | | | | | | | | | | | | | | | | | | | | |
earlz | 0:fa2f348efd7e | 183 | | 1 |0|0000|11|00| 1 |0|00000|1|00| 1 |0|0|1|000000| 1 |0|0|1|0000|1|0| |
earlz | 0:fa2f348efd7e | 184 | |___|_|____|__|__|___|_|_____|_|__|___|_|_|_|______|___|_|_|_|____|_|_| |
earlz | 0:fa2f348efd7e | 185 | |
earlz | 0:fa2f348efd7e | 186 | A standard packet transmission is a bidirectional communication between |
earlz | 0:fa2f348efd7e | 187 | two devices that can be divided in 3 different phases: |
earlz | 0:fa2f348efd7e | 188 | |
earlz | 0:fa2f348efd7e | 189 | Channel analysis Transmission Response |
earlz | 0:fa2f348efd7e | 190 | _____ _____________________________ _____ |
earlz | 0:fa2f348efd7e | 191 | | C-A | | ID | LENGTH | CONTENT | CRC | | ACK | |
earlz | 0:fa2f348efd7e | 192 | <--|-----|---------|----|--------|---------|-----|--> <----|-----| |
earlz | 0:fa2f348efd7e | 193 | | 0 | | 12 | 4 | 64 | 130 | | 6 | |
earlz | 0:fa2f348efd7e | 194 | |_____| |____|________|_________|_____| |_____| */ |
earlz | 0:fa2f348efd7e | 195 | |
earlz | 0:fa2f348efd7e | 196 | int PJON::send_string(uint8_t id, char *string, uint8_t length) { |
earlz | 0:fa2f348efd7e | 197 | if (!*string) return FAIL; |
earlz | 0:fa2f348efd7e | 198 | |
earlz | 0:fa2f348efd7e | 199 | if(!this->can_start()) return BUSY; |
earlz | 0:fa2f348efd7e | 200 | |
earlz | 0:fa2f348efd7e | 201 | uint8_t CRC = 0; |
earlz | 0:fa2f348efd7e | 202 | _input_pin.output(); //pinModeFast(_input_pin, OUTPUT); |
earlz | 0:fa2f348efd7e | 203 | |
earlz | 0:fa2f348efd7e | 204 | this->send_byte(id); |
earlz | 0:fa2f348efd7e | 205 | CRC ^= id; |
earlz | 0:fa2f348efd7e | 206 | this->send_byte(length + 3); |
earlz | 0:fa2f348efd7e | 207 | CRC ^= length + 3; |
earlz | 0:fa2f348efd7e | 208 | |
earlz | 0:fa2f348efd7e | 209 | for(uint8_t i = 0; i < length; i++) { |
earlz | 0:fa2f348efd7e | 210 | this->send_byte(string[i]); |
earlz | 0:fa2f348efd7e | 211 | CRC ^= string[i]; |
earlz | 0:fa2f348efd7e | 212 | } |
earlz | 0:fa2f348efd7e | 213 | |
earlz | 0:fa2f348efd7e | 214 | this->send_byte(CRC); |
earlz | 0:fa2f348efd7e | 215 | _input_pin = 0; //digitalWriteFast(_input_pin, LOW); |
earlz | 0:fa2f348efd7e | 216 | |
earlz | 0:fa2f348efd7e | 217 | if(id == BROADCAST) return ACK; |
earlz | 0:fa2f348efd7e | 218 | Timer t; |
earlz | 0:fa2f348efd7e | 219 | t.start(); |
earlz | 0:fa2f348efd7e | 220 | //unsigned long time = micros(); |
earlz | 0:fa2f348efd7e | 221 | int response = FAIL; |
earlz | 0:fa2f348efd7e | 222 | |
earlz | 0:fa2f348efd7e | 223 | /* Receive byte for an initial BIT_SPACER bit + standard bit total duration. |
earlz | 0:fa2f348efd7e | 224 | (freak condition used to avoid micros() overflow bug) */ |
earlz | 0:fa2f348efd7e | 225 | while(response == FAIL && !(t.read_us() >= BIT_SPACER + BIT_WIDTH)) |
earlz | 0:fa2f348efd7e | 226 | response = this->receive_byte(); |
earlz | 0:fa2f348efd7e | 227 | |
earlz | 0:fa2f348efd7e | 228 | t.stop(); |
earlz | 0:fa2f348efd7e | 229 | if (response == ACK || response == NAK) return response; |
earlz | 0:fa2f348efd7e | 230 | |
earlz | 0:fa2f348efd7e | 231 | return FAIL; |
earlz | 0:fa2f348efd7e | 232 | }; |
earlz | 0:fa2f348efd7e | 233 | |
earlz | 0:fa2f348efd7e | 234 | |
earlz | 0:fa2f348efd7e | 235 | /* Insert a packet in the send list: |
earlz | 0:fa2f348efd7e | 236 | The added packet will be sent in the next update() call. |
earlz | 0:fa2f348efd7e | 237 | Using the timing parameter you can set the delay between every |
earlz | 0:fa2f348efd7e | 238 | transmission cyclically sending the packet (use remove() function stop it) |
earlz | 0:fa2f348efd7e | 239 | |
earlz | 0:fa2f348efd7e | 240 | int hi = network.send(99, "HI!", 3, 1000000); // Send hi every second |
earlz | 0:fa2f348efd7e | 241 | _________________________________________________________________________ |
earlz | 0:fa2f348efd7e | 242 | | | | | | | | | |
earlz | 0:fa2f348efd7e | 243 | | device_id | length | content | state | attempts | timing | registration | |
earlz | 0:fa2f348efd7e | 244 | |___________|________|_________|_______|__________|________|______________| */ |
earlz | 0:fa2f348efd7e | 245 | |
earlz | 0:fa2f348efd7e | 246 | int PJON::send(uint8_t id, char *packet, uint8_t length, unsigned long timing) { |
earlz | 0:fa2f348efd7e | 247 | |
earlz | 0:fa2f348efd7e | 248 | char *str = (char *) malloc(length); |
earlz | 0:fa2f348efd7e | 249 | |
earlz | 0:fa2f348efd7e | 250 | if(str == NULL) { |
earlz | 0:fa2f348efd7e | 251 | this->_error(MEMORY_FULL, FAIL); |
earlz | 0:fa2f348efd7e | 252 | return FAIL; |
earlz | 0:fa2f348efd7e | 253 | } |
earlz | 0:fa2f348efd7e | 254 | |
earlz | 0:fa2f348efd7e | 255 | memcpy(str, packet, length); |
earlz | 0:fa2f348efd7e | 256 | |
earlz | 0:fa2f348efd7e | 257 | for(uint8_t i = 0; i < MAX_PACKETS; i++) |
earlz | 0:fa2f348efd7e | 258 | if(packets[i].state == NULL) { |
earlz | 0:fa2f348efd7e | 259 | packets[i].content = str; |
earlz | 0:fa2f348efd7e | 260 | packets[i].device_id = id; |
earlz | 0:fa2f348efd7e | 261 | packets[i].length = length; |
earlz | 0:fa2f348efd7e | 262 | packets[i].state = TO_BE_SENT; |
earlz | 0:fa2f348efd7e | 263 | if(timing > 0) { |
earlz | 0:fa2f348efd7e | 264 | packets[i].registration = _reg_timer.read_us(); |
earlz | 0:fa2f348efd7e | 265 | packets[i].timing = timing; |
earlz | 0:fa2f348efd7e | 266 | } |
earlz | 0:fa2f348efd7e | 267 | return i; |
earlz | 0:fa2f348efd7e | 268 | } |
earlz | 0:fa2f348efd7e | 269 | |
earlz | 0:fa2f348efd7e | 270 | this->_error(PACKETS_BUFFER_FULL, MAX_PACKETS); |
earlz | 0:fa2f348efd7e | 271 | return FAIL; |
earlz | 0:fa2f348efd7e | 272 | } |
earlz | 0:fa2f348efd7e | 273 | |
earlz | 0:fa2f348efd7e | 274 | |
earlz | 0:fa2f348efd7e | 275 | /* Update the state of the send list: |
earlz | 0:fa2f348efd7e | 276 | check if there are packets to be sent or to be erased |
earlz | 0:fa2f348efd7e | 277 | if correctly delivered */ |
earlz | 0:fa2f348efd7e | 278 | |
earlz | 0:fa2f348efd7e | 279 | void PJON::update() { |
earlz | 0:fa2f348efd7e | 280 | for(uint8_t i = 0; i < MAX_PACKETS; i++) { |
earlz | 0:fa2f348efd7e | 281 | if(packets[i].state != NULL) |
earlz | 0:fa2f348efd7e | 282 | if(_reg_timer.read_us() - packets[i].registration > packets[i].timing + (packets[i].attempts * packets[i].attempts)) //pow((float)packets[i].attempts, 2)) //avoid float operation |
earlz | 0:fa2f348efd7e | 283 | packets[i].state = send_string(packets[i].device_id, packets[i].content, packets[i].length); |
earlz | 0:fa2f348efd7e | 284 | |
earlz | 0:fa2f348efd7e | 285 | if(packets[i].state == ACK) { |
earlz | 0:fa2f348efd7e | 286 | if(!packets[i].timing) |
earlz | 0:fa2f348efd7e | 287 | this->remove(i); |
earlz | 0:fa2f348efd7e | 288 | else { |
earlz | 0:fa2f348efd7e | 289 | packets[i].attempts = 0; |
earlz | 0:fa2f348efd7e | 290 | packets[i].registration = _reg_timer.read_us(); |
earlz | 0:fa2f348efd7e | 291 | packets[i].state = TO_BE_SENT; |
earlz | 0:fa2f348efd7e | 292 | } |
earlz | 0:fa2f348efd7e | 293 | } |
earlz | 0:fa2f348efd7e | 294 | if(packets[i].state == FAIL) { |
earlz | 0:fa2f348efd7e | 295 | packets[i].attempts++; |
earlz | 0:fa2f348efd7e | 296 | |
earlz | 0:fa2f348efd7e | 297 | if(packets[i].attempts > MAX_ATTEMPTS) { |
earlz | 0:fa2f348efd7e | 298 | this->_error(CONNECTION_LOST, packets[i].device_id); |
earlz | 0:fa2f348efd7e | 299 | if(!packets[i].timing) |
earlz | 0:fa2f348efd7e | 300 | this->remove(i); |
earlz | 0:fa2f348efd7e | 301 | else { |
earlz | 0:fa2f348efd7e | 302 | packets[i].attempts = 0; |
earlz | 0:fa2f348efd7e | 303 | packets[i].registration = _reg_timer.read_us(); |
earlz | 0:fa2f348efd7e | 304 | packets[i].state = TO_BE_SENT; |
earlz | 0:fa2f348efd7e | 305 | } |
earlz | 0:fa2f348efd7e | 306 | } |
earlz | 0:fa2f348efd7e | 307 | } |
earlz | 0:fa2f348efd7e | 308 | } |
earlz | 0:fa2f348efd7e | 309 | } |
earlz | 0:fa2f348efd7e | 310 | |
earlz | 0:fa2f348efd7e | 311 | |
earlz | 0:fa2f348efd7e | 312 | /* Remove a packet from the send list: */ |
earlz | 0:fa2f348efd7e | 313 | |
earlz | 0:fa2f348efd7e | 314 | void PJON::remove(int id) { |
earlz | 0:fa2f348efd7e | 315 | free(packets[id].content); |
earlz | 0:fa2f348efd7e | 316 | packets[id].attempts = 0; |
earlz | 0:fa2f348efd7e | 317 | packets[id].device_id = NULL; |
earlz | 0:fa2f348efd7e | 318 | packets[id].length = NULL; |
earlz | 0:fa2f348efd7e | 319 | packets[id].state = NULL; |
earlz | 0:fa2f348efd7e | 320 | packets[id].registration = NULL; |
earlz | 0:fa2f348efd7e | 321 | } |
earlz | 0:fa2f348efd7e | 322 | |
earlz | 0:fa2f348efd7e | 323 | |
earlz | 0:fa2f348efd7e | 324 | /* Syncronize with transmitter: |
earlz | 0:fa2f348efd7e | 325 | This function is used only in byte syncronization. |
earlz | 0:fa2f348efd7e | 326 | READ_DELAY has to be tuned to correctly send and |
earlz | 0:fa2f348efd7e | 327 | receive transmissions because this variable shifts |
earlz | 0:fa2f348efd7e | 328 | in which portion of the bit, the reading will be |
earlz | 0:fa2f348efd7e | 329 | executed by the next read_byte function */ |
earlz | 0:fa2f348efd7e | 330 | |
earlz | 0:fa2f348efd7e | 331 | uint8_t PJON::syncronization_bit() { |
earlz | 0:fa2f348efd7e | 332 | wait_us((BIT_WIDTH / 2) - READ_DELAY); |
earlz | 0:fa2f348efd7e | 333 | uint8_t bit_value = _input_pin; //digitalReadFast(_input_pin); |
earlz | 0:fa2f348efd7e | 334 | wait_us(BIT_WIDTH / 2); |
earlz | 0:fa2f348efd7e | 335 | return bit_value; |
earlz | 0:fa2f348efd7e | 336 | } |
earlz | 0:fa2f348efd7e | 337 | |
earlz | 0:fa2f348efd7e | 338 | |
earlz | 0:fa2f348efd7e | 339 | /* Check if a byte is coming from the pin: |
earlz | 0:fa2f348efd7e | 340 | This function is looking for padding bits before a byte. |
earlz | 0:fa2f348efd7e | 341 | If value is 1 for more than ACCEPTANCE and after |
earlz | 0:fa2f348efd7e | 342 | that comes a 0 probably a byte is coming: |
earlz | 0:fa2f348efd7e | 343 | ________ |
earlz | 0:fa2f348efd7e | 344 | | Init | |
earlz | 0:fa2f348efd7e | 345 | |--------| |
earlz | 0:fa2f348efd7e | 346 | |_____ | |
earlz | 0:fa2f348efd7e | 347 | | | | | |
earlz | 0:fa2f348efd7e | 348 | |1 | |0 | |
earlz | 0:fa2f348efd7e | 349 | |__|__|__| |
earlz | 0:fa2f348efd7e | 350 | | |
earlz | 0:fa2f348efd7e | 351 | ACCEPTANCE */ |
earlz | 0:fa2f348efd7e | 352 | |
earlz | 0:fa2f348efd7e | 353 | int PJON::receive_byte() { |
earlz | 0:fa2f348efd7e | 354 | Timer t; |
earlz | 0:fa2f348efd7e | 355 | /* Initialize the pin and set it to LOW to reduce interference */ |
earlz | 0:fa2f348efd7e | 356 | _input_pin.input(); //pinModeFast(_input_pin, INPUT); |
earlz | 0:fa2f348efd7e | 357 | _input_pin = 0; //digitalWriteFast(_input_pin, LOW); |
earlz | 0:fa2f348efd7e | 358 | //unsigned long time = micros(); |
earlz | 0:fa2f348efd7e | 359 | t.start(); |
earlz | 0:fa2f348efd7e | 360 | int time=0; |
earlz | 0:fa2f348efd7e | 361 | /* Do nothing until the pin stops to be HIGH or passed more time than |
earlz | 0:fa2f348efd7e | 362 | BIT_SPACER duration (freak condition used to avoid micros() overflow bug) */ //MBED needed? |
earlz | 0:fa2f348efd7e | 363 | while (_input_pin && !(t.read_us() >= BIT_SPACER)); |
earlz | 0:fa2f348efd7e | 364 | /* Save how much time passed */ |
earlz | 0:fa2f348efd7e | 365 | time = t.read_us(); |
earlz | 0:fa2f348efd7e | 366 | /* is for sure less than BIT_SPACER, and if is more than ACCEPTANCE |
earlz | 0:fa2f348efd7e | 367 | (a minimum HIGH duration) and what is coming after is a LOW bit |
earlz | 0:fa2f348efd7e | 368 | probably a byte is coming so try to receive it. */ |
earlz | 0:fa2f348efd7e | 369 | t.stop(); |
earlz | 0:fa2f348efd7e | 370 | if(time >= ACCEPTANCE && !this->syncronization_bit()){ |
earlz | 0:fa2f348efd7e | 371 | return (int)this->read_byte(); |
earlz | 0:fa2f348efd7e | 372 | } |
earlz | 0:fa2f348efd7e | 373 | |
earlz | 0:fa2f348efd7e | 374 | return FAIL; |
earlz | 0:fa2f348efd7e | 375 | } |
earlz | 0:fa2f348efd7e | 376 | |
earlz | 0:fa2f348efd7e | 377 | |
earlz | 0:fa2f348efd7e | 378 | /* Read a byte from the pin */ |
earlz | 0:fa2f348efd7e | 379 | |
earlz | 0:fa2f348efd7e | 380 | uint8_t PJON::read_byte() { |
earlz | 0:fa2f348efd7e | 381 | uint8_t byte_value = 0xB00000000; |
earlz | 0:fa2f348efd7e | 382 | wait_us(BIT_WIDTH / 2); |
earlz | 0:fa2f348efd7e | 383 | for (uint8_t i = 0; i < 8; i++) { |
earlz | 0:fa2f348efd7e | 384 | byte_value += _input_pin << i; |
earlz | 0:fa2f348efd7e | 385 | wait_us(BIT_WIDTH); |
earlz | 0:fa2f348efd7e | 386 | } |
earlz | 0:fa2f348efd7e | 387 | return byte_value; |
earlz | 0:fa2f348efd7e | 388 | } |
earlz | 0:fa2f348efd7e | 389 | |
earlz | 0:fa2f348efd7e | 390 | |
earlz | 0:fa2f348efd7e | 391 | /* Try to receive a packet from the pin: */ |
earlz | 0:fa2f348efd7e | 392 | |
earlz | 0:fa2f348efd7e | 393 | int PJON::receive() { |
earlz | 0:fa2f348efd7e | 394 | int package_length = PACKET_MAX_LENGTH; |
earlz | 0:fa2f348efd7e | 395 | uint8_t CRC = 0; |
earlz | 0:fa2f348efd7e | 396 | |
earlz | 0:fa2f348efd7e | 397 | for (uint8_t i = 0; i <= package_length; i++) { |
earlz | 0:fa2f348efd7e | 398 | data[i] = this->receive_byte(); |
earlz | 0:fa2f348efd7e | 399 | |
earlz | 0:fa2f348efd7e | 400 | if (data[i] == FAIL) return FAIL; |
earlz | 0:fa2f348efd7e | 401 | |
earlz | 0:fa2f348efd7e | 402 | if(i == 0 && data[i] != _device_id && data[i] != BROADCAST) |
earlz | 0:fa2f348efd7e | 403 | return BUSY; |
earlz | 0:fa2f348efd7e | 404 | |
earlz | 0:fa2f348efd7e | 405 | if(i == 1) |
earlz | 0:fa2f348efd7e | 406 | if(data[i] > 0 && data[i] < PACKET_MAX_LENGTH) |
earlz | 0:fa2f348efd7e | 407 | package_length = data[i]; |
earlz | 0:fa2f348efd7e | 408 | else return FAIL; |
earlz | 0:fa2f348efd7e | 409 | |
earlz | 0:fa2f348efd7e | 410 | CRC ^= data[i]; |
earlz | 0:fa2f348efd7e | 411 | } |
earlz | 0:fa2f348efd7e | 412 | |
earlz | 0:fa2f348efd7e | 413 | _input_pin.output(); //pinModeFast(_input_pin, OUTPUT); |
earlz | 0:fa2f348efd7e | 414 | |
earlz | 0:fa2f348efd7e | 415 | if (!CRC) { |
earlz | 0:fa2f348efd7e | 416 | if(data[0] != BROADCAST) { |
earlz | 0:fa2f348efd7e | 417 | this->send_byte(ACK); |
earlz | 0:fa2f348efd7e | 418 | _input_pin = 0; //digitalWriteFast(_input_pin, LOW); |
earlz | 0:fa2f348efd7e | 419 | } |
earlz | 0:fa2f348efd7e | 420 | this->_receiver(data[1] - 3, data + 2); |
earlz | 0:fa2f348efd7e | 421 | return ACK; |
earlz | 0:fa2f348efd7e | 422 | } else { |
earlz | 0:fa2f348efd7e | 423 | if(data[0] != BROADCAST) { |
earlz | 0:fa2f348efd7e | 424 | this->send_byte(NAK); |
earlz | 0:fa2f348efd7e | 425 | _input_pin = 0; //digitalWriteFast(_input_pin, LOW); |
earlz | 0:fa2f348efd7e | 426 | } |
earlz | 0:fa2f348efd7e | 427 | return NAK; |
earlz | 0:fa2f348efd7e | 428 | } |
earlz | 0:fa2f348efd7e | 429 | } |
earlz | 0:fa2f348efd7e | 430 | |
earlz | 0:fa2f348efd7e | 431 | |
earlz | 0:fa2f348efd7e | 432 | /* Try to receive a packet from the pin repeatedly with a maximum duration: */ |
earlz | 0:fa2f348efd7e | 433 | |
earlz | 0:fa2f348efd7e | 434 | int PJON::receive(unsigned long duration) { |
earlz | 0:fa2f348efd7e | 435 | int response; |
earlz | 0:fa2f348efd7e | 436 | Timer t; |
earlz | 0:fa2f348efd7e | 437 | t.start(); |
earlz | 0:fa2f348efd7e | 438 | //long time = micros(); |
earlz | 0:fa2f348efd7e | 439 | /* (freak condition used to avoid micros() overflow bug) */ |
earlz | 0:fa2f348efd7e | 440 | while(!(t.read_us() >= duration)) { |
earlz | 0:fa2f348efd7e | 441 | response = this->receive(); |
earlz | 0:fa2f348efd7e | 442 | if(response == ACK){ |
earlz | 0:fa2f348efd7e | 443 | t.stop(); |
earlz | 0:fa2f348efd7e | 444 | return ACK; |
earlz | 0:fa2f348efd7e | 445 | } |
earlz | 0:fa2f348efd7e | 446 | } |
earlz | 0:fa2f348efd7e | 447 | return response; |
earlz | 0:fa2f348efd7e | 448 | } |