rosaria/Legacy/Aria/src/ArLMS2xxPacketReceiver.cpp

274 lines
7.9 KiB
C++
Raw Normal View History

2021-12-16 15:07:59 +01:00
/*
Adept MobileRobots Robotics Interface for Applications (ARIA)
Copyright (C) 2004, 2005 ActivMedia Robotics LLC
Copyright (C) 2006, 2007, 2008, 2009, 2010 MobileRobots Inc.
Copyright (C) 2011, 2012, 2013 Adept Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
If you wish to redistribute ARIA under different terms, contact
Adept MobileRobots for information about a commercial version of ARIA at
robots@mobilerobots.com or
Adept MobileRobots, 10 Columbia Drive, Amherst, NH 03031; +1-603-881-7960
*/
#include "ArExport.h"
#include "ariaOSDef.h"
#include "ArLMS2xxPacketReceiver.h"
#include "ArLog.h"
#include "ariaUtil.h"
/*
allocatePackets: whether to allocate memory for the packets before
returning them (true) or to just return a pointer to an internal
packet (false)... most everything should use false as this will help prevent
many memory leaks or corruptions
*/
AREXPORT ArLMS2xxPacketReceiver::ArLMS2xxPacketReceiver(
unsigned char receivingAddress, bool allocatePackets,
bool useBase0Address)
{
myAllocatePackets = allocatePackets;
myReceivingAddress = receivingAddress;
myDeviceConn = NULL;
myUseBase0Address = useBase0Address;
}
/*
allocatePackets: whether to allocate memory for the packets before
returning them (true) or to just return a pointer to an internal
packet (false)... most everything should use false as this will help prevent
many memory leaks or corruptions
*/
AREXPORT ArLMS2xxPacketReceiver::ArLMS2xxPacketReceiver(
ArDeviceConnection *deviceConnection,
unsigned char receivingAddress, bool allocatePackets,
bool useBase0Address)
{
myDeviceConn = deviceConnection;
myAllocatePackets = allocatePackets;
myReceivingAddress = receivingAddress;
myUseBase0Address = useBase0Address;
}
AREXPORT ArLMS2xxPacketReceiver::~ArLMS2xxPacketReceiver()
{
}
AREXPORT void ArLMS2xxPacketReceiver::setDeviceConnection(
ArDeviceConnection *deviceConnection)
{
myDeviceConn = deviceConnection;
}
AREXPORT ArDeviceConnection *ArLMS2xxPacketReceiver::getDeviceConnection(void)
{
return myDeviceConn;
}
/**
@param msWait how long to block for the start of a packet, nonblocking if 0
@return NULL if there are no packets in alloted time, otherwise a pointer
to the packet received, if allocatePackets is true than the place that
called this function owns the packet and should delete the packet when
done... if allocatePackets is false then nothing must store a pointer to
this packet, the packet must be used and done with by the time this
method is called again
*/
AREXPORT ArLMS2xxPacket *ArLMS2xxPacketReceiver::receivePacket(
unsigned int msWait)
{
ArLMS2xxPacket *packet;
unsigned char c;
char buf[2048];
long count = 0;
// state can be one of the STATE_ enums in the class
int state = STATE_START;
//unsigned int timeDone;
//unsigned int curTime;
long timeToRunFor;
long packetLength;
ArTime timeDone;
ArTime lastDataRead;
ArTime packetReceived;
int numRead;
if (myDeviceConn == NULL ||
myDeviceConn->getStatus() != ArDeviceConnection::STATUS_OPEN)
{
myDeviceConn->debugEndPacket(false, -10);
return NULL;
}
timeDone.setToNow();
if (!timeDone.addMSec(msWait)) {
ArLog::log(ArLog::Normal,
"ArLMS2xxPacketReceiver::receivePacket() error adding msecs (%i)",
msWait);
}
do
{
timeToRunFor = timeDone.mSecTo();
if (timeToRunFor < 0)
timeToRunFor = 0;
if (state == STATE_START)
myDeviceConn->debugStartPacket();
if (myDeviceConn->read((char *)&c, 1, timeToRunFor) == 0)
{
myDeviceConn->debugBytesRead(0);
if (state == STATE_START)
{
myDeviceConn->debugEndPacket(false, -20);
return NULL;
}
else
{
//ArUtil::sleep(1);
continue;
}
}
myDeviceConn->debugBytesRead(1);
//printf("%x\n", c);
switch (state) {
case STATE_START:
if (c == 0x02) // move on, resetting packet
{
//printf("###############\n");
state = STATE_ADDR;
myPacket.empty();
myPacket.setLength(0);
myPacket.uByteToBuf(c);
packetReceived = myDeviceConn->getTimeRead(0);
myPacket.setTimeReceived(packetReceived);
}
/*else
{
//printf(" BAD\n");
}*/
break;
case STATE_ADDR:
// if this is correct move on, adding this byte... this is taken
// out in favor of a more inclusive approach, if someone ever
// wnats to drive multiple robots off of one serial port just
// put this back in, or I don't know, punt
//if (c == ((unsigned char)0x80 + myReceivingAddress))
if (!myUseBase0Address && c >= 0x80 && c <= 0x84)
{
state = STATE_START_COUNT;
myPacket.uByteToBuf(c);
}
// c will always be >= 0 since its unsigned
else if (myUseBase0Address && c <= 0x4)
{
state = STATE_START_COUNT;
myPacket.uByteToBuf(c);
}
else // go back to beginning, packet hosed
{
ArLog::log(ArLog::Terse,
"ArLMS2xxPacketReceiver::receivePacket: wrong address (0x%x instead of 0x%x)", c, (unsigned) 0x80 + myReceivingAddress);
state = STATE_START;
}
break;
case STATE_START_COUNT:
packetLength = c;
myPacket.uByteToBuf(c);
state = STATE_ACQUIRE_DATA;
break;
case STATE_ACQUIRE_DATA:
// the character c is high ordre byte of the packet length count
// so we'll just build the length of the packet then get the
//rest of the data
myPacket.uByteToBuf(c);
packetLength = packetLength | (c << 8);
count = 0;
// make sure the length isn't longer than the maximum packet length...
// getting some wierd 25k or 44k long packets (um, no)
if (packetLength > ((long)myPacket.getMaxLength() -
(long)myPacket.getHeaderLength()))
{
ArLog::log(ArLog::Normal,
"ArLMS2xxPacketReceiver::receivePacket: packet too long, it is %d long while the maximum is %d.", packetLength, myPacket.getMaxLength());
state = STATE_START;
//myPacket.log();
break;
}
// here we read until we get as much as we want, OR until
// we go 100 ms without data... its arbitrary but it doesn't happen often
// and it'll mean a bad packet anyways
lastDataRead.setToNow();
while (count < packetLength + 2)
{
numRead = myDeviceConn->read(buf + count, packetLength + 2- count, 1);
if (numRead > 0)
{
myDeviceConn->debugBytesRead(numRead);
lastDataRead.setToNow();
}
else
{
myDeviceConn->debugBytesRead(0);
}
if (lastDataRead.mSecTo() < -100)
{
myDeviceConn->debugEndPacket(false, -30);
return NULL;
}
count += numRead;
}
myPacket.dataToBuf(buf, packetLength + 2);
if (myPacket.verifyCRC())
{
myPacket.resetRead();
myDeviceConn->debugEndPacket(true, myPacket.getID());
//printf("Received ");
//myPacket.log();
if (myAllocatePackets)
{
packet = new ArLMS2xxPacket;
packet->duplicatePacket(&myPacket);
return packet;
}
else
return &myPacket;
}
else
{
ArLog::log(ArLog::Normal,
"ArLMS2xxPacketReceiver::receivePacket: bad packet, bad checksum");
state = STATE_START;
//myPacket.log();
break;
}
break;
default:
break;
}
} while (timeDone.mSecTo() >= 0 || state != STATE_START);
myDeviceConn->debugEndPacket(false, -40);
//printf("finished the loop...\n");
return NULL;
}