1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
/*
* Copyright (c) 2007, Technische Universitaet Berlin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of the Technische Universitaet Berlin nor the names
* of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Philipp Huppertz <huppertz@tkn.tu-berlin.de>
*/
#ifndef SERIALCOMM_H
#define SERIALCOMM_H
#include "basecomm.h"
#include "sfpacket.h"
#include "packetbuffer.h"
#include "sharedinfo.h"
#include <sys/select.h>
#include <pthread.h>
#include <termios.h>
#include <string>
#include <sstream>
#include <iostream>
// #define DEBUG_SERIALCOMM
// #define DEBUG_RAW_SERIALCOMM
#undef DEBUG
#ifdef DEBUG_SERIALCOMM
#include <iostream>
#define DEBUG(message) std::cout << message << std::endl;
#else
#define DEBUG(message)
#endif
class SerialComm : public BaseComm
{
/** Constants **/
protected:
// max serial MTU
static const int maxMTU = (SFPacket::cMaxPacketLength+1)*2;
// min serial MTU
static const int minMTU = 4;
// byte count of serial header
static const int serialHeaderBytes = 5;
// byte offset of type field
static const int typeOffset = 0;
// byte offset of sequence number field
static const int seqnoOffset = 1;
// byte offset of payload field
static const int payloadOffset = 2;
// timeout for acks in s
static const int ackTimeout = 1000 * 1000 * 200;
// max. reties for packets from pc to node
static const int maxRetries = 25;
// how many bytes do we attempt to read from the serial line in one go?
static const int rawReadBytes = 20;
enum rx_states_t {
WAIT_FOR_SYNC,
IN_SYNC,
ESCAPED
};
/** Member vars */
protected:
/* pthread for serial reading */
pthread_t readerThread;
bool readerThreadRunning;
/* pthread for serial writing */
pthread_t writerThread;
bool writerThreadRunning;
// thread safe ack
typedef struct
{
// mutex lock for any of this vars
pthread_mutex_t lock;
// notempty cond
pthread_cond_t received;
} ackCondition_t;
ackCondition_t ack;
/* raw read buffer */
struct rawFifo_t {
char queue[maxMTU];
int head;
int tail;
};
rawFifo_t rawFifo;
/* reference to read packet buffer */
PacketBuffer &readBuffer;
/* reference to write packet buffer */
PacketBuffer &writeBuffer;
/* number of dropped (read) packets */
int droppedReadPacketCount;
/* number of dropped (write) packets */
int droppedWritePacketCount;
/* number of read packets */
int readPacketCount;
/* number of written packets */
int writtenPacketCount;
/* number of bad packets read from serial line, counts resynchronizations! */
int badPacketCount;
/* sum retry attempts for all packets */
int sumRetries;
/* device port of this sf */
std::string device;
/* baudrate of connected device */
int baudrate;
/* read fd set */
fd_set rfds;
/* write fd set */
fd_set wfds;
/* fd for reading from serial device */
int serialReadFD;
/* fd for writing to serial device */
int serialWriteFD;
/* seqno for serial data packets */
int seqno;
/* indicates that an error occured */
bool errorReported;
/* error message of reportError call */
std::ostringstream errorMsg;
/* for noticing the parent thread of cancelation */
sharedControlInfo_t &control;
/** Member functions */
/* needed to start pthreads */
friend void* readSerialThread(void* ob);
friend void* writeSerialThread(void* ob);
private:
/* do not allow standard constructor */
SerialComm();
protected:
char nextRaw();
/* claculates crc byte-wise */
inline static uint16_t byteCRC(uint8_t byte, uint16_t crc) {
crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= byte;
crc ^= (uint8_t)(crc & 0xff) >> 4;
crc ^= crc << 12;
crc ^= (crc & 0xff) << 5;
return crc;
}
inline static uint16_t calcCRC(uint8_t *bytes, uint16_t len) {
uint16_t crc = 0;
for(unsigned i = 0; i < len; i++) {
crc = SerialComm::byteCRC(bytes[i], crc);
}
return crc;
}
inline static uint16_t checkCrc(uint8_t *bytes, uint16_t count) {
bool crcOk = false;
if(count > 2) {
uint16_t crc = calcCRC(bytes, count - 2);
uint16_t packetCrc = (bytes[count-1] << 8) | bytes[count-2];
if(crc == packetCrc) crcOk = true;
}
return crcOk;
}
/* HDLC encode (byte stuff) count bytes from buffer from into buffer to.
* to must be at least count * 2 bytes large. Returns the number of bytes
* written into to.
*/
int hdlcEncode(int count, const char* from, char *to);
/**
* try to read at least count bytes in one go, but may read up to maxCount bytes.
*/
virtual int readFD(int fd, char *buffer, int count, int maxCount, int *err);
/* enables byte escaping. overwrites method from base class.*/
virtual int writeFD(int fd, const char *buffer, int count, int *err);
/* reads a packet (blocking) */
bool readPacket(SFPacket &pPacket);
/* writes a packet to serial source */
bool writePacket(SFPacket &pPacket);
/* returns tcflag of requested baudrate */
static tcflag_t parseBaudrate(int requested);
int reportError(const char *msg, int result);
/* checks for messages from node - producer thread */
void readSerial();
/* write messages to serial / node - consumer thread */
void writeSerial();
public:
SerialComm(const char* pDevice, int pBaudrate, PacketBuffer &pReadBuffer, PacketBuffer &pWriteBuffer, sharedControlInfo_t& pControl);
~SerialComm();
/* cancels all running threads */
void cancel();
std::string getDevice() const;
int getBaudRate() const;
void reportStatus(std::ostream& os);
/* returns if error occurred */
bool isErrorReported() { return errorReported; }
};
#endif
|