00001
00002 #ifndef INCLUDED_DynamixelProtocol_h_
00003 #define INCLUDED_DynamixelProtocol_h_
00004
00005 #include "IPC/Thread.h"
00006 #include "Shared/debuget.h"
00007 #include <cstddef>
00008 #include <iostream>
00009 #include <map>
00010 #include <string>
00011
00012 #define IS_MXEX(m) (m==MODEL_MX28 || m==MODEL_MX64 || m==MODEL_MX106 || m==MODEL_EX106P)
00013
00014
00015 namespace DynamixelProtocol {
00016
00017 const unsigned int MAX_ID=0xFD;
00018 const unsigned int BROADCAST_ID=0xFE;
00019 const unsigned int INVALID_ID=0xFF;
00020 const unsigned int MARKER_VALUE=0xFF;
00021
00022 extern const char* MODEL_UNKNOWN_NAME;
00023 enum ModelID_t {
00024 MODEL_DX113=113,
00025 MODEL_DX116=116,
00026 MODEL_DX117=117,
00027 MODEL_AX12=12,
00028 MODEL_AX18=18,
00029 MODEL_AXS1=13,
00030 MODEL_RX10=10,
00031 MODEL_RX24=24,
00032 MODEL_RX28=28,
00033 MODEL_RX64=64,
00034 MODEL_MX28=29,
00035 MODEL_MX64=310,
00036 MODEL_MX106=320,
00037 MODEL_EX106P=107,
00038 MODEL_UNKNOWN=static_cast<size_t>(1<<16)
00039 };
00040
00041 extern const std::map<DynamixelProtocol::ModelID_t, const std::string> dynamixelModels;
00042
00043
00044 enum StatusResponseLevel {
00045 RESPOND_NONE=0,
00046 RESPOND_READ=1,
00047 RESPOND_ALL=2
00048 };
00049
00050
00051
00052
00053 inline unsigned char nchecksum(const unsigned char* p, size_t len, size_t off=0) {
00054 const unsigned char* end=p+len;
00055 p+=off;
00056 unsigned char c=0;
00057 while(p!=end) {
00058
00059 c+=*p++;
00060 }
00061 return c;
00062 }
00063
00064 inline unsigned char nchecksum(const struct GenericCmdHeader& p, size_t len);
00065
00066 inline unsigned char nchecksum(const struct GenericResponseHeader& p, size_t len);
00067
00068 template<class T> void updateChecksum(T& cmd) { cmd.checksum=~nchecksum(cmd,sizeof(cmd)-1); }
00069
00070
00071 template<class T> bool validate(const T& msg) {
00072 const unsigned char MARKER=(unsigned char)-1U;
00073 if(msg.markerA!=MARKER || msg.markerB!=MARKER) return false;
00074 if(msg.resplen!=sizeof(msg)-4) return false;
00075 typeof(msg.checksum) chk = ~nchecksum(msg,sizeof(msg)-1);
00076 return chk == msg.checksum;
00077 }
00078
00079 struct GenericCmdHeader {
00080 GenericCmdHeader(unsigned char bytelen, unsigned char instruction)
00081 : markerA(MARKER_VALUE), markerB(MARKER_VALUE), servoid(BROADCAST_ID), cmdlen(bytelen), cmdid(instruction) {}
00082 operator const char*() const { return reinterpret_cast<const char*>(&markerA); }
00083 operator const unsigned char*() const { return &markerA; }
00084 unsigned char markerA;
00085 unsigned char markerB;
00086 unsigned char servoid;
00087 unsigned char cmdlen;
00088 unsigned char cmdid;
00089 };
00090 inline unsigned char nchecksum(const struct GenericCmdHeader& p, size_t len) { return nchecksum(p,len,2); }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 template<class T>
00103 struct SyncWriteHeader : public GenericCmdHeader {
00104 SyncWriteHeader(unsigned char len)
00105 : GenericCmdHeader(sizeof(T)*len+4,0x83), addr(T::ADDRESS), writelen(sizeof(T)-1) {}
00106 unsigned char addr;
00107 unsigned char writelen;
00108 };
00109 struct SyncWriteEntry {
00110 SyncWriteEntry() : servoid() {}
00111 SyncWriteEntry(unsigned char sid) : servoid(sid) {}
00112 operator const char*() const { return reinterpret_cast<const char*>(&servoid); }
00113 operator const unsigned char*() const { return &servoid; }
00114 unsigned char servoid;
00115 };
00116
00117 struct SyncWritePosSpeedEntry : public SyncWriteEntry {
00118 SyncWritePosSpeedEntry() : SyncWriteEntry(), posl(), posh(), speedl(), speedh() {}
00119 SyncWritePosSpeedEntry(unsigned char sid, unsigned short pos, unsigned short speed)
00120 : SyncWriteEntry(sid), posl(pos), posh(pos>>8), speedl(speed), speedh(speed>>8) {}
00121 static const unsigned char ADDRESS=0x1E;
00122 unsigned char posl;
00123 unsigned char posh;
00124 unsigned char speedl;
00125 unsigned char speedh;
00126 };
00127
00128 struct SyncWriteContinuousRotationEntry : public SyncWriteEntry {
00129 SyncWriteContinuousRotationEntry() : SyncWriteEntry(), ccwlimitl(), ccwlimith() {}
00130 SyncWriteContinuousRotationEntry(unsigned char sid, bool enable, ModelID_t model) :
00131 SyncWriteEntry(sid), ccwlimitl(enable?0:0xFF),
00132 ccwlimith(IS_MXEX(model) ? (enable?0:0x0F) : (enable?0:0x03) ) {}
00133 static const unsigned char ADDRESS=0x8;
00134 unsigned char ccwlimitl;
00135 unsigned char ccwlimith;
00136 };
00137
00138 struct SyncWriteLEDEntry : public SyncWriteEntry {
00139 SyncWriteLEDEntry() : SyncWriteEntry(), led() {}
00140 SyncWriteLEDEntry(unsigned char sid, bool enable) : SyncWriteEntry(sid), led(enable?1:0) {}
00141 static const unsigned char ADDRESS=0x19;
00142 unsigned char led;
00143 };
00144 struct SyncWriteComplianceEntry : public SyncWriteEntry {
00145 SyncWriteComplianceEntry() : SyncWriteEntry(), cwmargin(), ccwmargin(), cwslope(), ccwslope() {}
00146 SyncWriteComplianceEntry(unsigned char sid, unsigned char margin, unsigned char slope) : SyncWriteEntry(sid), cwmargin(margin), ccwmargin(margin), cwslope(slope), ccwslope(slope) {}
00147 static const unsigned char ADDRESS=0x1A;
00148 unsigned char cwmargin;
00149 unsigned char ccwmargin;
00150 unsigned char cwslope;
00151 unsigned char ccwslope;
00152 };
00153 struct SyncWritePunchEntry : public SyncWriteEntry {
00154 SyncWritePunchEntry() : SyncWriteEntry(), punchl(), punchh() {}
00155 SyncWritePunchEntry(unsigned char sid, unsigned short punch) : SyncWriteEntry(sid), punchl(punch), punchh(punch>>8) {}
00156 static const unsigned char ADDRESS=0x30;
00157 unsigned char punchl;
00158 unsigned char punchh;
00159 };
00160 struct SyncWriteTorqueEntry : public SyncWriteEntry {
00161 SyncWriteTorqueEntry() : SyncWriteEntry(), maxTorqueL(), maxTorqueH() {}
00162 SyncWriteTorqueEntry(unsigned char sid, unsigned short max) : SyncWriteEntry(sid), maxTorqueL(max), maxTorqueH(max>>8) {}
00163 static const unsigned char ADDRESS=0x22;
00164 unsigned char maxTorqueL;
00165 unsigned char maxTorqueH;
00166 };
00167
00168 struct SyncWriteSoundHoldEntry : public SyncWriteEntry {
00169 SyncWriteSoundHoldEntry() : SyncWriteEntry(), sndMaxHold(0) {}
00170 SyncWriteSoundHoldEntry(unsigned char sid) : SyncWriteEntry(sid), sndMaxHold(0) {}
00171 static const unsigned char ADDRESS=0x24;
00172 unsigned char sndMaxHold;
00173 };
00174
00175
00176
00177
00178
00179 struct SyncWriteSoundCountEntry : public SyncWriteEntry {
00180 SyncWriteSoundCountEntry() : SyncWriteEntry(), sndCount(0) {}
00181 SyncWriteSoundCountEntry(unsigned char sid) : SyncWriteEntry(sid), sndCount(0) {}
00182 static const unsigned char ADDRESS=0x25;
00183 unsigned char sndCount;
00184 };
00185
00186 struct SyncWriteSoundHoldAndCountEntry : public SyncWriteEntry {
00187 SyncWriteSoundHoldAndCountEntry() : SyncWriteEntry(), sndMaxHold(0), sndCount(0) {}
00188 SyncWriteSoundHoldAndCountEntry(unsigned char sid) : SyncWriteEntry(sid), sndMaxHold(0), sndCount(0) {}
00189 static const unsigned char ADDRESS=0x24;
00190 unsigned char sndMaxHold;
00191 unsigned char sndCount;
00192 };
00193
00194
00195 struct WriteHeader : public GenericCmdHeader {
00196 WriteHeader(unsigned char address, unsigned char len)
00197 : GenericCmdHeader(len+3,0x3), addr(address) {}
00198 unsigned char addr;
00199 };
00200
00201 struct BroadcastTorqueCmd : public WriteHeader {
00202
00203 BroadcastTorqueCmd(bool enable)
00204 : WriteHeader(0x18,1), torqueEnable(enable?1:0), checksum() { updateChecksum(*this); }
00205
00206 unsigned char torqueEnable;
00207 char checksum;
00208 };
00209
00210 struct BroadcastFullComplianceCmd : public WriteHeader {
00211 BroadcastFullComplianceCmd()
00212 : WriteHeader(0x1A,4), cwmargin(0), ccwmargin(0), cwslope(0), ccwslope(0), checksum() { updateChecksum(*this); }
00213 unsigned char cwmargin;
00214 unsigned char ccwmargin;
00215 unsigned char cwslope;
00216 unsigned char ccwslope;
00217 char checksum;
00218 };
00219
00220 struct BroadcastNoPunchCmd : public WriteHeader {
00221 BroadcastNoPunchCmd()
00222 : WriteHeader(0x30,2), punchl(0), punchh(0), checksum() { updateChecksum(*this); }
00223 unsigned char punchl;
00224 unsigned char punchh;
00225 char checksum;
00226 };
00227
00228 struct BroadcastZeroSpeedCmd : public WriteHeader {
00229 BroadcastZeroSpeedCmd()
00230 : WriteHeader(0x20,2), speedl(0), speedh(0), checksum() { updateChecksum(*this); }
00231 unsigned char speedl;
00232 unsigned char speedh;
00233 char checksum;
00234 };
00235
00236 struct BroadcastBaudCmd : public WriteHeader {
00237 BroadcastBaudCmd(unsigned char divisor) : WriteHeader(0x04,1), baudDivisor(divisor), checksum() { updateChecksum(*this); }
00238 unsigned char baudDivisor;
00239 char checksum;
00240 };
00241
00242 struct SetReturnDelayTimeCmd : public WriteHeader {
00243 SetReturnDelayTimeCmd() : WriteHeader(0x05,1), delayTime(0), checksum() { updateChecksum(*this); }
00244 SetReturnDelayTimeCmd(unsigned char delay) : WriteHeader(0x05,1), delayTime(delay), checksum() { updateChecksum(*this); }
00245 SetReturnDelayTimeCmd(unsigned char sid, unsigned char delay) : WriteHeader(0x05,1), delayTime(delay), checksum() { servoid=sid; updateChecksum(*this); }
00246 unsigned char delayTime;
00247 char checksum;
00248 };
00249
00250 struct SetStatusResponseLevelCmd : public WriteHeader {
00251 SetStatusResponseLevelCmd() : WriteHeader(0x10,1), responseLevel(0), checksum() { updateChecksum(*this); }
00252 SetStatusResponseLevelCmd(StatusResponseLevel level) : WriteHeader(0x05,1), responseLevel(level), checksum() { updateChecksum(*this); }
00253 SetStatusResponseLevelCmd(unsigned char sid, StatusResponseLevel level) : WriteHeader(0x05,1), responseLevel(level), checksum() { servoid=sid; updateChecksum(*this); }
00254 unsigned char responseLevel;
00255 char checksum;
00256 };
00257
00258 struct SetServoIDCmd : public WriteHeader {
00259 SetServoIDCmd(unsigned char tgtsid, unsigned char newsid)
00260 : WriteHeader(0x03, 1), newservoid(newsid), checksum() { servoid=tgtsid; updateChecksum(*this); }
00261 unsigned char newservoid;
00262 char checksum;
00263 };
00264
00265 struct SetPosSpeedCmd : public WriteHeader {
00266 SetPosSpeedCmd() : WriteHeader(0x1E,4), posl(), posh(), speedl(), speedh(), checksum() { updateChecksum(*this); }
00267 SetPosSpeedCmd(unsigned char sid, unsigned short pos, unsigned short speed)
00268 : WriteHeader(0x1E,4), posl(pos), posh(pos>>8), speedl(speed), speedh(speed>>8), checksum() { servoid=sid; updateChecksum(*this); }
00269 unsigned char posl;
00270 unsigned char posh;
00271 unsigned char speedl;
00272 unsigned char speedh;
00273 char checksum;
00274 };
00275
00276 struct ClearSoundHoldCmd : public WriteHeader {
00277 ClearSoundHoldCmd() : WriteHeader(0x24,1), sndMaxHold(0), checksum() { updateChecksum(*this); }
00278 ClearSoundHoldCmd(unsigned char sid) : WriteHeader(0x24,1), sndMaxHold(0), checksum() { servoid=sid; updateChecksum(*this); }
00279 unsigned char sndMaxHold;
00280 char checksum;
00281 };
00282
00283
00284
00285
00286
00287 struct ClearSoundCountCmd : public WriteHeader {
00288 ClearSoundCountCmd() : WriteHeader(0x25,1), sndCount(0), checksum() { updateChecksum(*this); }
00289 ClearSoundCountCmd(unsigned char sid) : WriteHeader(0x25,1), sndCount(0), checksum() { servoid=sid; updateChecksum(*this); }
00290 unsigned char sndCount;
00291 char checksum;
00292 };
00293
00294 struct ClearSoundHoldAndCountCmd : public WriteHeader {
00295 ClearSoundHoldAndCountCmd() : WriteHeader(0x24,2), sndMaxHold(0), sndCount(0), checksum() { updateChecksum(*this); }
00296 ClearSoundHoldAndCountCmd(unsigned char sid) : WriteHeader(0x24,2), sndMaxHold(0), sndCount(0), checksum() { servoid=sid; updateChecksum(*this); }
00297 unsigned char sndMaxHold;
00298 unsigned char sndCount;
00299 char checksum;
00300 };
00301
00302
00303
00304
00305 enum ResponseError_t {
00306 VOLTAGE_ERROR=1, ANGLE_ERROR=2, HEAT_ERROR=4, RANGE_ERROR=8, CHECKSUM_ERROR=16, LOAD_ERROR=32, INSTRUCTION_ERROR=64
00307 };
00308 extern const char* ResponseErrorNames[9];
00309
00310
00311 struct GenericResponseHeader {
00312 GenericResponseHeader() : markerA(0), markerB(0), servoid(0), resplen(0), error(0) {}
00313 operator char*() { return reinterpret_cast<char*>(&markerA); }
00314 operator const char*() const { return reinterpret_cast<const char*>(&markerA); }
00315 operator const unsigned char*() const { return &markerA; }
00316 unsigned char markerA;
00317 unsigned char markerB;
00318 unsigned char servoid;
00319 unsigned char resplen;
00320 unsigned char error;
00321 };
00322 inline unsigned char nchecksum(const struct GenericResponseHeader& p, size_t len) { return nchecksum(p,len,2); }
00323
00324 const unsigned char RESPONSE_HEADER_LEN = sizeof(GenericResponseHeader)+1;
00325
00326
00327 struct WriteResponse : public GenericResponseHeader {
00328 unsigned char checksum;
00329 };
00330
00331 struct ServoSensorsResponse : public GenericResponseHeader {
00332
00333 ServoSensorsResponse() : GenericResponseHeader(), posl(), posh(), speedl(), speedh(), loadl(), loadh(), voltage(), temp(), checksum() {}
00334
00335
00336 unsigned short getPosition() const { return (static_cast<unsigned short>(posh)<<8) + posl; }
00337
00338 short getSpeed() const { short x = (static_cast<short>(speedh&0x3)<<8) | speedl; return (speedh&4) ? -x : x; }
00339
00340 short getLoad() const { short x = (static_cast<short>(loadh&0x3)<<8) | loadl; return (loadh&4) ? x : -x; }
00341
00342 unsigned char posl;
00343 unsigned char posh;
00344 unsigned char speedl;
00345 unsigned char speedh;
00346 unsigned char loadl;
00347 unsigned char loadh;
00348 unsigned char voltage;
00349 unsigned char temp;
00350 unsigned char checksum;
00351 };
00352
00353 struct AXS1SensorsResponse : public GenericResponseHeader {
00354
00355 AXS1SensorsResponse() : GenericResponseHeader(),
00356 leftIR(), centerIR(), rightIR(), leftLum(), centerLum(), rightLum(),
00357 obsFlag(), lumFlag(), _robotisReserved(), sndData(), sndMaxHold(), sndCount(),
00358
00359 checksum()
00360 {}
00361
00362
00363
00364 unsigned short getDetectedTime() {
00365 return (static_cast<unsigned short>(sndTimeHigh)<<8) + sndTimeLow;
00366 }about:startpage
00367 */
00368
00369 unsigned char leftIR;
00370 unsigned char centerIR;
00371 unsigned char rightIR;
00372 unsigned char leftLum;
00373 unsigned char centerLum;
00374 unsigned char rightLum;
00375 unsigned char obsFlag;
00376 unsigned char lumFlag;
00377 unsigned char _robotisReserved;
00378 unsigned char sndData;
00379 unsigned char sndMaxHold;
00380 unsigned char sndCount;
00381
00382
00383
00384
00385
00386
00387
00388
00389 unsigned char checksum;
00390 };
00391
00392 struct TorqueResponse : public GenericResponseHeader {
00393 unsigned char torqueEnable;
00394 unsigned char checksum;
00395 };
00396
00397 struct ServoInfoResponse : public GenericResponseHeader {
00398 ServoInfoResponse() : GenericResponseHeader(), modell(0), modelh(0), version(0), checksum() {}
00399 unsigned short getModelNumber() const { return (static_cast<unsigned short>(modelh)<<8) | modell; }
00400 const char* getModelString() const {
00401 typedef typeof(dynamixelModels) modelmap_t;
00402 modelmap_t::const_iterator it = dynamixelModels.find((ModelID_t)getModelNumber());
00403 if(it==dynamixelModels.end()) {
00404 return (getModelNumber()==0 && version==0) ? "INVALID RESPONSE" : MODEL_UNKNOWN_NAME;
00405 } else {
00406 return it->second.c_str();
00407 }
00408 }
00409 unsigned char modell;
00410 unsigned char modelh;
00411 unsigned char version;
00412 unsigned char checksum;
00413 };
00414
00415
00416
00417
00418 struct ReadCmd : public GenericCmdHeader {
00419
00420 ReadCmd(unsigned char servoID, unsigned char address, unsigned char len)
00421 : GenericCmdHeader(4,0x2), addr(address), readlen(len), checksum() { servoid=servoID; updateChecksum(*this); }
00422 unsigned char addr;
00423 unsigned char readlen;
00424 unsigned char checksum;
00425 };
00426
00427 struct ReadServoSensorsCmd : public ReadCmd {
00428
00429 ReadServoSensorsCmd(unsigned char servoID) : ReadCmd(servoID,0x24,sizeof(ServoSensorsResponse)-RESPONSE_HEADER_LEN) {}
00430 };
00431
00432 struct ReadAXS1SensorsCmd : public ReadCmd {
00433
00434 ReadAXS1SensorsCmd(unsigned char servoID) : ReadCmd(servoID,0x1A,sizeof(AXS1SensorsResponse)-RESPONSE_HEADER_LEN) {}
00435 };
00436
00437 struct ReadTorqueCmd : public ReadCmd {
00438
00439 ReadTorqueCmd(unsigned char servoID) : ReadCmd(servoID,0x18,sizeof(TorqueResponse)-RESPONSE_HEADER_LEN) {}
00440 };
00441
00442 struct ReadModelCmd : public ReadCmd {
00443
00444 ReadModelCmd(unsigned char servoID) : ReadCmd(servoID,0x00,sizeof(ServoInfoResponse)-RESPONSE_HEADER_LEN) {}
00445 };
00446
00447
00448
00449 void reportErrors(unsigned int servoID, unsigned int offset, unsigned char err);
00450
00451
00452
00453 template<class R> bool readResponse(std::istream& is, R& response, unsigned int offset) {
00454
00455 is.read((char*)&response.markerA,sizeof(response.markerA)*2);
00456 if(!is || is.gcount()!=sizeof(response.markerA)*2) {
00457 Thread::testCurrentCancel();
00458 std::cerr << "Dynamixel protocol bad read! 1" << std::endl;
00459 is.sync();
00460 is.clear();
00461 return false;
00462 }
00463 size_t noiseCnt=0;
00464
00465 while(response.markerA!=DynamixelProtocol::MARKER_VALUE || response.markerB!=DynamixelProtocol::MARKER_VALUE) {
00466
00467 ++noiseCnt;
00468 response.markerA=response.markerB;
00469 try {
00470 is.read((char*)&response.markerB,sizeof(response.markerB));
00471 if(!is || is.gcount()!=sizeof(response.markerB)) {
00472 Thread::testCurrentCancel();
00473 std::cerr << "Dynamixel protocol bad read! 2" << std::endl;
00474 is.sync();
00475 is.clear();
00476 }
00477 } catch(...) {
00478 std::cerr << "Dynamixel protocol couldn't find packet start, skipped " << noiseCnt << " bytes of line noise." << std::endl;
00479 throw;
00480 }
00481 }
00482 if(noiseCnt!=0)
00483 std::cerr << "Dynamixel protocol skipping " << noiseCnt << " bytes of line noise" << std::endl;
00484 const size_t HEADER_SIZE = sizeof(response.servoid)+sizeof(response.resplen)+sizeof(response.error);
00485
00486 is.read((char*)&response.servoid,HEADER_SIZE);
00487 if(!is || (size_t)is.gcount()!=HEADER_SIZE) {
00488 Thread::testCurrentCancel();
00489 std::cerr << "Dynamixel protocol bad read! 3" << std::endl;
00490 is.sync();
00491 is.clear();
00492 return false;
00493 }
00494 if(response.resplen<2) {
00495 std::cerr << "Dynamixel protocol got bad packet, too short! (" << (int)response.resplen << ")" << std::endl;
00496 return false;
00497 }
00498
00499 if(response.resplen != sizeof(R)-sizeof(GenericResponseHeader)+1) {
00500 unsigned char tmpbuf[256];
00501 memcpy(tmpbuf,&response.servoid,HEADER_SIZE);
00502 is.read((char*)tmpbuf+HEADER_SIZE,response.resplen-sizeof(response.error));
00503 if(!is || (size_t)is.gcount()!=response.resplen-sizeof(response.error)) {
00504 Thread::testCurrentCancel();
00505 std::cerr << "Dynamixel protocol bad read! 4" << std::endl;
00506 is.sync();
00507 is.clear();
00508 return false;
00509 }
00510 unsigned char rchksum = tmpbuf[HEADER_SIZE+response.resplen-sizeof(response.error)-1];
00511 unsigned char lchksum = ~nchecksum(tmpbuf,HEADER_SIZE+response.resplen-sizeof(response.error)-1,0);
00512 if( lchksum == rchksum) {
00513 if(response.error==0)
00514 std::cerr << "Dynamixel protocol: invalid response (expected " << (sizeof(R)-sizeof(GenericResponseHeader)+1) << ", length=" << (int)response.resplen << ")" << std::endl;
00515 else
00516 reportErrors(response.servoid,offset,response.error);
00517 } else {
00518 std::cerr << "Dynamixel line noise: sensor checksum failed" << std::endl;
00519 is.sync();
00520 }
00521 return false;
00522 }
00523
00524
00525 is.read((char*)(&response.error+1),response.resplen-sizeof(response.error));
00526 if(!is || (size_t)is.gcount()!=response.resplen-sizeof(response.error)) {
00527 Thread::testCurrentCancel();
00528 std::cerr << "Dynamixel protocol bad read! 5" << std::endl;
00529 is.sync();
00530 is.clear();
00531 return false;
00532 } else if(!validate(response)) {
00533
00534
00535
00536
00537
00538 std::cerr << "Dynamixel line noise: sensor checksum failed" << std::endl;
00539 is.sync();
00540 return false;
00541 }
00542
00543 if(response.error!=0)
00544 reportErrors(response.servoid,offset,response.error);
00545 return true;
00546 }
00547
00548
00549
00550 class PingThread : public Thread {
00551 public:
00552
00553 PingThread(std::istream& is, std::ostream& os, unsigned char servoid, unsigned int outputOffset, ServoSensorsResponse* servoinfo=NULL, AXS1SensorsResponse* servoinfoS1=NULL)
00554 : Thread(), response(), icomm(is), ocomm(os), sid(servoid), output(outputOffset), info(servoinfo), infoS1(servoinfoS1), unknownModelName() { start(); }
00555
00556 ~PingThread() { if(isStarted()) stop().join(); }
00557
00558 static long getTimeout() { return timeout; }
00559 static void setTimeout(long t) { timeout = t; }
00560
00561 ServoInfoResponse response;
00562
00563 protected:
00564 virtual void * run();
00565 virtual void cancelled();
00566 static long timeout;
00567 std::istream& icomm;
00568 std::ostream& ocomm;
00569 unsigned char sid;
00570 unsigned int output;
00571 ServoSensorsResponse* info;
00572 AXS1SensorsResponse* infoS1;
00573 std::string unknownModelName;
00574
00575 private:
00576 PingThread(const PingThread&);
00577 PingThread& operator=(const PingThread&);
00578 };
00579
00580
00581
00582
00583
00584 template<class T> std::ostream& write(std::ostream& os, const T& cmd) { return os.write(cmd,sizeof(cmd)); }
00585
00586 template<class T> std::ostream& write(std::ostream& os, const T& cmd, unsigned char& checksum) { checksum+=nchecksum(cmd,sizeof(cmd)); return os.write(cmd,sizeof(cmd)); }
00587 };
00588
00589
00590
00591
00592
00593
00594 #endif