Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Adafruit_GFX_128x64 DS3231 PinDetect SDFileSystem USBDevice mbed RealtimeMath MODSERIAL
comms.cpp@21:2fa676f214fe, 2014-06-07 (annotated)
- Committer:
- ellingjp
- Date:
- Sat Jun 07 07:12:25 2014 +0000
- Revision:
- 21:2fa676f214fe
- Child:
- 22:9350752f5414
Working sync
Who changed what in which revision?
| User | Revision | Line number | New contents of line | 
|---|---|---|---|
| ellingjp | 21:2fa676f214fe | 1 | #include "comms.h" | 
| ellingjp | 21:2fa676f214fe | 2 | #include "debug.h" | 
| ellingjp | 21:2fa676f214fe | 3 | |
| ellingjp | 21:2fa676f214fe | 4 | const int Packet::HEADER_SIZE = 5; | 
| ellingjp | 21:2fa676f214fe | 5 | |
| ellingjp | 21:2fa676f214fe | 6 | /* If successful, loads p with a new packet. User is responsible for deleting. | 
| ellingjp | 21:2fa676f214fe | 7 | * Returns > 0 on success | 
| ellingjp | 21:2fa676f214fe | 8 | 0 on timeout | 
| ellingjp | 21:2fa676f214fe | 9 | < 0 on error | 
| ellingjp | 21:2fa676f214fe | 10 | */ | 
| ellingjp | 21:2fa676f214fe | 11 | int Comms::receivePacket(Packet **p, int timeout) { | 
| ellingjp | 21:2fa676f214fe | 12 | // PC_PRINTLN("receivePacket: getting header"); | 
| ellingjp | 21:2fa676f214fe | 13 | uint8_t headerBuf[Packet::HEADER_SIZE]; | 
| ellingjp | 21:2fa676f214fe | 14 | if (!getBytes(headerBuf, Packet::HEADER_SIZE, timeout)) | 
| ellingjp | 21:2fa676f214fe | 15 | return 0; | 
| ellingjp | 21:2fa676f214fe | 16 | |
| ellingjp | 21:2fa676f214fe | 17 | uint8_t cmd = headerBuf[0]; | 
| ellingjp | 21:2fa676f214fe | 18 | uint16_t packetNumber = headerBuf[1]; | 
| ellingjp | 21:2fa676f214fe | 19 | uint16_t dataLength = headerBuf[3]; | 
| ellingjp | 21:2fa676f214fe | 20 | |
| ellingjp | 21:2fa676f214fe | 21 | PC_PRINTLNF("receivePacket: cmd = %d", cmd); | 
| ellingjp | 21:2fa676f214fe | 22 | PC_PRINTLNF("receivePacket: packetNumber = %d", packetNumber); | 
| ellingjp | 21:2fa676f214fe | 23 | PC_PRINTLNF("receivePacket: dataLength = %d", dataLength); | 
| ellingjp | 21:2fa676f214fe | 24 | |
| ellingjp | 21:2fa676f214fe | 25 | uint8_t data[dataLength]; | 
| ellingjp | 21:2fa676f214fe | 26 | if (!getBytes(data, dataLength, timeout)) | 
| ellingjp | 21:2fa676f214fe | 27 | return 0; | 
| ellingjp | 21:2fa676f214fe | 28 | |
| ellingjp | 21:2fa676f214fe | 29 | PC_PRINTLN("receivePacket: getting checksum"); | 
| ellingjp | 21:2fa676f214fe | 30 | uint16_t checkSum; | 
| ellingjp | 21:2fa676f214fe | 31 | if (!getBytes((uint8_t *) &checkSum, sizeof(checkSum), timeout)) | 
| ellingjp | 21:2fa676f214fe | 32 | return 0; | 
| ellingjp | 21:2fa676f214fe | 33 | |
| ellingjp | 21:2fa676f214fe | 34 | PC_PRINTLN("receivePacket: verifying checksum"); | 
| ellingjp | 21:2fa676f214fe | 35 | *p = Packet::createAndVerify(cmd, packetNumber, dataLength, data, checkSum); | 
| ellingjp | 21:2fa676f214fe | 36 | if (*p == NULL) | 
| ellingjp | 21:2fa676f214fe | 37 | return -1; | 
| ellingjp | 21:2fa676f214fe | 38 | |
| ellingjp | 21:2fa676f214fe | 39 | return 1; | 
| ellingjp | 21:2fa676f214fe | 40 | } | 
| ellingjp | 21:2fa676f214fe | 41 | |
| ellingjp | 21:2fa676f214fe | 42 | /* Sends packet p, and deletes it */ | 
| ellingjp | 21:2fa676f214fe | 43 | void Comms::sendPacket(Packet *p) { | 
| ellingjp | 21:2fa676f214fe | 44 | sendBytes((uint8_t *)&p->cmd, sizeof(p->cmd)); | 
| ellingjp | 21:2fa676f214fe | 45 | sendBytes((uint8_t *)&p->packetNumber, sizeof(p->packetNumber)); | 
| ellingjp | 21:2fa676f214fe | 46 | sendBytes((uint8_t *)&p->dataLength, sizeof(p->dataLength)); | 
| ellingjp | 21:2fa676f214fe | 47 | sendBytes((uint8_t *) p->data, p->dataLength); | 
| ellingjp | 21:2fa676f214fe | 48 | sendBytes((uint8_t *)&p->checkSum, sizeof(p->checkSum)); | 
| ellingjp | 21:2fa676f214fe | 49 | } | 
| ellingjp | 21:2fa676f214fe | 50 | |
| ellingjp | 21:2fa676f214fe | 51 | void Comms::sendBytes(uint8_t *bytes, int nElms) { | 
| ellingjp | 21:2fa676f214fe | 52 | for (int i = 0; i < nElms; i++) | 
| ellingjp | 21:2fa676f214fe | 53 | bt.putc(bytes[i]); | 
| ellingjp | 21:2fa676f214fe | 54 | } | 
| ellingjp | 21:2fa676f214fe | 55 | |
| ellingjp | 21:2fa676f214fe | 56 | void Comms::sendByte(uint8_t byte) { | 
| ellingjp | 21:2fa676f214fe | 57 | bt.putc(byte); | 
| ellingjp | 21:2fa676f214fe | 58 | } | 
| ellingjp | 21:2fa676f214fe | 59 | |
| ellingjp | 21:2fa676f214fe | 60 | /* Loads buf with a byte from the bluetooth stream. | 
| ellingjp | 21:2fa676f214fe | 61 | * Returns true if successful, false on timeout. */ | 
| ellingjp | 21:2fa676f214fe | 62 | bool Comms::getBytes(uint8_t *buf, int n, int timeout) { | 
| ellingjp | 21:2fa676f214fe | 63 | for (int i = 0; i < n; i++) { | 
| ellingjp | 21:2fa676f214fe | 64 | // PC_PRINTLNF("getBytes: waiting for byte %d", i); | 
| ellingjp | 21:2fa676f214fe | 65 | if (!getByte(buf+i, timeout)) { | 
| ellingjp | 21:2fa676f214fe | 66 | // PC_PRINTLN("getBytes: failed to get byte"); | 
| ellingjp | 21:2fa676f214fe | 67 | return false; | 
| ellingjp | 21:2fa676f214fe | 68 | } | 
| ellingjp | 21:2fa676f214fe | 69 | // PC_PRINTLNF("getBytes: got byte %d", *(buf+i)); | 
| ellingjp | 21:2fa676f214fe | 70 | } | 
| ellingjp | 21:2fa676f214fe | 71 | |
| ellingjp | 21:2fa676f214fe | 72 | // PC_PRINTLN("getBytes: got bytes"); | 
| ellingjp | 21:2fa676f214fe | 73 | return true; | 
| ellingjp | 21:2fa676f214fe | 74 | } | 
| ellingjp | 21:2fa676f214fe | 75 | |
| ellingjp | 21:2fa676f214fe | 76 | /* Loads c with a byte from the bluetooth stream. | 
| ellingjp | 21:2fa676f214fe | 77 | * Returns true if successful, false on timeout. */ | 
| ellingjp | 21:2fa676f214fe | 78 | bool Comms::getByte(uint8_t *byte, int timeout) { | 
| ellingjp | 21:2fa676f214fe | 79 | // PC_PRINTLN("getByte: getting byte"); | 
| ellingjp | 21:2fa676f214fe | 80 | if (timeout != INT_MAX) | 
| ellingjp | 21:2fa676f214fe | 81 | timer.start(); | 
| ellingjp | 21:2fa676f214fe | 82 | |
| ellingjp | 21:2fa676f214fe | 83 | // PC_PRINTLN("getByte: waiting for bt readable"); | 
| ellingjp | 21:2fa676f214fe | 84 | // Spin until byte available or timeout | 
| ellingjp | 21:2fa676f214fe | 85 | while ( !bt.readable() ) | 
| ellingjp | 21:2fa676f214fe | 86 | if (timer.read_ms() > timeout) | 
| ellingjp | 21:2fa676f214fe | 87 | return false; | 
| ellingjp | 21:2fa676f214fe | 88 | |
| ellingjp | 21:2fa676f214fe | 89 | // PC_PRINTLN("getByte: byte available"); | 
| ellingjp | 21:2fa676f214fe | 90 | timer.stop(); | 
| ellingjp | 21:2fa676f214fe | 91 | timer.reset(); | 
| ellingjp | 21:2fa676f214fe | 92 | *byte = bt.getc(); | 
| ellingjp | 21:2fa676f214fe | 93 | |
| ellingjp | 21:2fa676f214fe | 94 | // PC_PRINTLNF("getByte: byte read = %d", *byte); | 
| ellingjp | 21:2fa676f214fe | 95 | return true; | 
| ellingjp | 21:2fa676f214fe | 96 | } | 
| ellingjp | 21:2fa676f214fe | 97 | |
| ellingjp | 21:2fa676f214fe | 98 | /* Returns a new packet. Copies dataLength bytes from data, and verifies the checkSum. | 
| ellingjp | 21:2fa676f214fe | 99 | * If the given checkSum is incorrect, returns NULL. | 
| ellingjp | 21:2fa676f214fe | 100 | * User is responsible for deleting the returned packet. */ | 
| ellingjp | 21:2fa676f214fe | 101 | Packet *Packet::createAndVerify(uint8_t cmd, uint16_t packetNumber, uint16_t dataLength, uint8_t *data, uint16_t checkSum) { | 
| ellingjp | 21:2fa676f214fe | 102 | if (dataLength > 0 && data == NULL) | 
| ellingjp | 21:2fa676f214fe | 103 | return NULL; | 
| ellingjp | 21:2fa676f214fe | 104 | |
| ellingjp | 21:2fa676f214fe | 105 | Packet *p = new Packet(cmd, packetNumber, dataLength, data); | 
| ellingjp | 21:2fa676f214fe | 106 | if (p->checkSum != checkSum) | 
| ellingjp | 21:2fa676f214fe | 107 | return NULL; | 
| ellingjp | 21:2fa676f214fe | 108 | else | 
| ellingjp | 21:2fa676f214fe | 109 | return p; | 
| ellingjp | 21:2fa676f214fe | 110 | } | 
| ellingjp | 21:2fa676f214fe | 111 | |
| ellingjp | 21:2fa676f214fe | 112 | /* Returns a new packet. Copies dataLength bytes from data, and generates the checksum. | 
| ellingjp | 21:2fa676f214fe | 113 | * User is responsible for deleting the returned packet. */ | 
| ellingjp | 21:2fa676f214fe | 114 | Packet *Packet::create(uint8_t cmd, uint16_t packetNumber, uint16_t dataLength, uint8_t *data) { | 
| ellingjp | 21:2fa676f214fe | 115 | if (dataLength > 0 && data == NULL) | 
| ellingjp | 21:2fa676f214fe | 116 | return NULL; | 
| ellingjp | 21:2fa676f214fe | 117 | |
| ellingjp | 21:2fa676f214fe | 118 | return new Packet(cmd, packetNumber, dataLength, data); | 
| ellingjp | 21:2fa676f214fe | 119 | } | 
| ellingjp | 21:2fa676f214fe | 120 | |
| ellingjp | 21:2fa676f214fe | 121 | /* Copies dataLength bytes from data */ | 
| ellingjp | 21:2fa676f214fe | 122 | Packet::Packet(uint8_t cmd, uint16_t packetNumber, uint16_t dataLength, uint8_t *data) { | 
| ellingjp | 21:2fa676f214fe | 123 | checkSum = 0; | 
| ellingjp | 21:2fa676f214fe | 124 | |
| ellingjp | 21:2fa676f214fe | 125 | this->cmd = cmd; | 
| ellingjp | 21:2fa676f214fe | 126 | this->packetNumber = packetNumber; | 
| ellingjp | 21:2fa676f214fe | 127 | this->dataLength = dataLength; | 
| ellingjp | 21:2fa676f214fe | 128 | |
| ellingjp | 21:2fa676f214fe | 129 | checkSum ^= cmd; | 
| ellingjp | 21:2fa676f214fe | 130 | checkSum ^= packetNumber; | 
| ellingjp | 21:2fa676f214fe | 131 | checkSum ^= dataLength; | 
| ellingjp | 21:2fa676f214fe | 132 | |
| ellingjp | 21:2fa676f214fe | 133 | this->data = new uint8_t[dataLength]; | 
| ellingjp | 21:2fa676f214fe | 134 | for (int i = 0; i < dataLength; i++) { | 
| ellingjp | 21:2fa676f214fe | 135 | this->data[i] = data[i]; | 
| ellingjp | 21:2fa676f214fe | 136 | checkSum ^= data[i]; | 
| ellingjp | 21:2fa676f214fe | 137 | } | 
| ellingjp | 21:2fa676f214fe | 138 | } | 
| ellingjp | 21:2fa676f214fe | 139 | |
| ellingjp | 21:2fa676f214fe | 140 | Packet::~Packet() { | 
| ellingjp | 21:2fa676f214fe | 141 | delete[] data; | 
| ellingjp | 21:2fa676f214fe | 142 | } |