00001
00060 #include <ipa_canopen_core/canopen.h>
00061 #include <sstream>
00062 #include <cstring>
00063 #include <unordered_map>
00064 #include<algorithm>
00065
00066
00067 namespace canopen
00068 {
00069
00070
00071
00072
00073 bool sdo_protect=false;
00074 BYTE protect_msg[8];
00075
00076 std::chrono::milliseconds syncInterval;
00077 std::string baudRate;
00078 std::map<uint8_t, Device> devices;
00079 std::map<std::string, DeviceGroup> deviceGroups;
00080 HANDLE h;
00081 std::vector<std::thread> managerThreads;
00082 std::vector<std::string> openDeviceFiles;
00083 bool atFirstInit=true;
00084 int initTrials=0;
00085 std::map<SDOkey, std::function<void (uint8_t CANid, BYTE data[8])> > incomingDataHandlers { { STATUSWORD, sdo_incoming }, { DRIVERTEMPERATURE, sdo_incoming }, { MODES_OF_OPERATION_DISPLAY, sdo_incoming } };
00086 std::map<SDOkey, std::function<void (uint8_t CANid, BYTE data[8])> > incomingErrorHandlers { { ERRORWORD, errorword_incoming }, { MANUFACTURER, errorword_incoming } };
00087 std::map<SDOkey, std::function<void (uint8_t CANid, BYTE data[8])> > incomingManufacturerDetails { {MANUFACTURERHWVERSION, manufacturer_incoming}, {MANUFACTURERDEVICENAME, manufacturer_incoming}, {MANUFACTURERSOFTWAREVERSION, manufacturer_incoming} };
00088 std::map<uint16_t, std::function<void (const TPCANRdMsg m)> > incomingPDOHandlers;
00089 std::map<uint16_t, std::function<void (const TPCANRdMsg m)> > incomingEMCYHandlers;
00090 bool recover_active;
00091 bool halt_active;
00092
00093 bool halt_positive;
00094 bool halt_negative;
00095
00096 bool use_limit_switch=false;
00097
00098 std::string operation_mode_param;
00099
00100 std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
00101
00102 std::chrono::duration<double> elapsed_seconds;
00103
00104
00105
00106
00107
00108
00109 bool openConnection(std::string devName, std::string baudrate)
00110 {
00111 h = LINUX_CAN_Open(devName.c_str(), O_RDWR);
00112 if (!h)
00113 return false;
00114
00115 errno = CAN_Init(h, baudrates[baudrate], CAN_INIT_TYPE_ST);
00116
00117 return true;
00118 }
00119
00120 void pre_init(std::string chainName)
00121 {
00122
00123 for (auto id : canopen::deviceGroups[chainName].getCANids())
00124 {
00125
00126
00127 getErrors(id);
00128
00129
00130
00131
00132 readManErrReg(id);
00133
00134
00135
00136
00137 canopen::uploadSDO(id, MANUFACTURERDEVICENAME);
00138 }
00139 }
00142 bool init(std::string deviceFile, std::string chainName, const int8_t mode_of_operation)
00143 {
00144 initTrials++;
00145
00146 if(initTrials == 4)
00147 {
00148 std::cout << "There are still problems with the devices. Trying a complete reset " << std::endl;
00149 canopen::sendNMT(0x00, canopen::NMT_RESET_NODE);
00150
00151 initTrials=0;
00152 }
00153
00154 if(canopen::atFirstInit)
00155 {
00156
00157 canopen::atFirstInit = false;
00158
00159 bool connection_success;
00160
00161 bool connection_is_available = std::find(canopen::openDeviceFiles.begin(), canopen::openDeviceFiles.end(), deviceFile) != canopen::openDeviceFiles.end();
00162
00163 if(!connection_is_available)
00164 {
00165
00166 CAN_Close(canopen::h);
00167 connection_success = canopen::openConnection(deviceFile, canopen::baudRate);
00168
00169 if (!connection_success)
00170 {
00171 std::cout << "Cannot open CAN device "<< deviceFile << "; aborting." << std::endl;
00172 exit(EXIT_FAILURE);
00173 }
00174 canopen::initListenerThread(canopen::defaultListener);
00175 canopen::openDeviceFiles.push_back(deviceFile);
00176 }
00177
00178 std::cout << "Resetting communication with the devices " << std::endl;
00179 canopen::sendNMT(0x00, canopen::NMT_RESET_COMMUNICATION);
00180
00181 }
00182
00183
00184 if(canopen::deviceGroups[chainName].getFirstInit())
00185 {
00186
00187 std::chrono::time_point<std::chrono::high_resolution_clock> time_start, time_end;
00188 time_start = std::chrono::high_resolution_clock::now();
00189 std::chrono::duration<double> elapsed_seconds;
00190
00191 canopen::initDeviceManagerThread(chainName,canopen::deviceManager);
00192 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00193
00194 std::cout << "Initializing " << chainName << std::endl;
00195
00196 canopen::deviceGroups[chainName].setFirstInit(false);
00197
00198 canopen::pre_init(chainName);
00199
00200 while(sdo_protect)
00201 {
00202 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00203
00204 elapsed_seconds = time_end - time_start;
00205
00206 if(elapsed_seconds.count() > 5.0)
00207 {
00208 std::cout << "not ready for operation. Probably due to communication problems with the Master." << std::endl;
00209 return false;
00210 }
00211 time_end = std::chrono::high_resolution_clock::now();
00212 }
00213
00214 time_start = std::chrono::high_resolution_clock::now();
00215
00216
00217
00218 for(auto id : canopen::deviceGroups[chainName].getCANids())
00219 {
00220
00221 bool nmt_init = devices[id].getNMTInit();
00222 std::cout << "Waiting for Node: " << (uint16_t)id << " to become available" << std::endl;
00223
00224
00225 while(!nmt_init)
00226 {
00227 elapsed_seconds = time_end - time_start;
00228
00229 if(elapsed_seconds.count() > 25.0)
00230 {
00231 std::cout << "Node: " << (uint16_t)id << " is not ready for operation. Please check for eventual problems." << std::endl;
00232 return false;
00233 }
00234
00235 std::this_thread::sleep_for(std::chrono::milliseconds(1));
00236 nmt_init = devices[id].getNMTInit();
00237 time_end = std::chrono::high_resolution_clock::now();
00238 }
00239
00240 std::cout << "Node: " << (uint16_t)id << " is now available" << std::endl;
00241
00242 canopen::sendNMT((u_int8_t)id, canopen::NMT_START_REMOTE_NODE);
00243 }
00244
00245 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00246
00247
00248 for (auto id : canopen::deviceGroups[chainName].getCANids())
00249 {
00250
00251 std::cout << "Initialized the PDO mapping for Node:" << (uint16_t)id << std::endl;
00252
00253 for(int pdo_object=0; pdo_object<=3; pdo_object++)
00254 {
00255 canopen::disableTPDO(chainName,pdo_object);
00256 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00257
00258 canopen::clearTPDOMapping(chainName, pdo_object);
00259 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00260
00261 canopen::disableRPDO(chainName,pdo_object);
00262 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00263
00264 canopen::clearRPDOMapping(chainName, pdo_object);
00265 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00266 }
00267
00268
00269 if(canopen::use_limit_switch)
00270 {
00271
00272 std::vector<std::string> tpdo1_registers {"604100", "60FD00"};
00273 std::vector<int> tpdo1_sizes {0x10,0x20};
00274
00275 canopen::makeTPDOMapping(chainName,0,tpdo1_registers, tpdo1_sizes, u_int8_t(0xFF));
00276 }
00277 else
00278 {
00279 std::vector<std::string> tpdo1_registers {"604100", "606100"};
00280 std::vector<int> tpdo1_sizes {0x10,0x08};
00281
00282 canopen::makeTPDOMapping(chainName,0,tpdo1_registers, tpdo1_sizes, u_int8_t(0xFF));
00283
00284 }
00285 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00286
00287 std::vector<std::string> tpdo4_registers {"606400", "606C00"};
00288 std::vector<int> tpdo4_sizes {0x20,0x20};
00289
00290 canopen::makeTPDOMapping(chainName,3, tpdo4_registers, tpdo4_sizes, u_int8_t(0x01));
00291 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00292
00293 std::vector<std::string> rpdo1_registers {"604000"};
00294 std::vector<int> rpdo1_sizes {0x10};
00295
00296 std::vector<std::string> rpdo2_registers {"60C101"};
00297 std::vector<int> rpdo2_sizes {0x20};
00298
00299 canopen::makeRPDOMapping(chainName,0, rpdo1_registers, rpdo1_sizes, u_int8_t(0xFF));
00300 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00301 canopen::makeRPDOMapping(chainName,1, rpdo2_registers, rpdo2_sizes, u_int8_t(0x01));
00302 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00303
00304 for(int pdo_object=0; pdo_object<=3; pdo_object++)
00305 {
00306 canopen::enableTPDO(chainName, pdo_object);
00307 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00308
00309 canopen::enableRPDO(chainName, pdo_object);
00310 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00311 }
00312
00313 std::this_thread::sleep_for(std::chrono::milliseconds(20));
00314
00315 }
00316
00317 }
00318 recover_active = false;
00319
00320 canopen::setObjects(chainName);
00321
00322
00323 for (auto id : canopen::deviceGroups[chainName].getCANids())
00324 {
00325 bool set_operation_mode = canopen::setOperationMode(id, mode_of_operation);
00326 if(!set_operation_mode)
00327 return false;
00328 canopen::setMotorState((uint16_t)id, canopen::MS_OPERATION_ENABLED);
00329
00330
00331 canopen::devices[id].setDesiredPos((double)devices[id].getActualPos());
00332 canopen::devices[id].setDesiredVel(0);
00333
00334 sendPos((uint16_t)id, (double)devices[id].getDesiredPos());
00335
00336 canopen::controlPDO(id, canopen::CONTROLWORD_ENABLE_MOVEMENT, 0x00);
00337 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00338 }
00339
00340 for (auto id : canopen::deviceGroups[chainName].getCANids())
00341 {
00342 getErrors(id);
00343 readManErrReg(id);
00344 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00345
00346 if(devices[id].getIPMode())
00347 {
00348 std::cout << "Concluded driver side init succesfully for Node" << (uint16_t)id << std::endl;
00349 canopen::devices[id].setInitialized(true);
00350 }
00351 else
00352 {
00353 std::cout << "Problems occured during driver side init for Node" << (uint16_t)id << std::endl;
00354 canopen::devices[id].setInitialized(false);
00355 return false;
00356 }
00357
00358 }
00359
00360 return true;
00361 }
00362
00363 bool init(std::string deviceFile, std::string chainName, std::chrono::milliseconds syncInterval)
00364 {
00365 bool initialized = init(deviceFile, chainName, canopen::MODES_OF_OPERATION_INTERPOLATED_POSITION_MODE);
00366
00367 for (auto id : canopen::deviceGroups[chainName].getCANids())
00368 {
00369 sendSDO((uint16_t)id, canopen::IP_TIME_UNITS, (uint8_t) syncInterval.count() );
00370 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00371 sendSDO((uint16_t)id, canopen::IP_TIME_INDEX, (uint8_t)canopen::IP_TIME_INDEX_MILLISECONDS);
00372 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00373 sendSDO((uint16_t)id, canopen::SYNC_TIMEOUT_FACTOR, (uint8_t)canopen::SYNC_TIMEOUT_FACTOR_DISABLE_TIMEOUT);
00374 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00375 }
00376 return initialized;
00377 }
00378
00379
00380 bool recover(std::string deviceFile, std::string chainName, std::chrono::milliseconds syncInterval)
00381 {
00382
00383 recover_active = true;
00384
00385 for (auto id : canopen::deviceGroups[chainName].getCANids())
00386 {
00387
00388 if(devices[id].getIPMode())
00389 {
00390 std::cout << "Node" << id << "is already operational" << std::endl;
00391 }
00392 else
00393 {
00394
00395 canopen::controlPDO(id,canopen::CONTROLWORD_HALT, 0x00);
00396 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00397
00398 canopen::controlPDO(id,canopen::CONTROLWORD_DISABLE_INTERPOLATED, 0x00);
00399 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00400
00401 canopen::controlPDO(id,canopen::CONTROL_WORD_DISABLE_VOLTAGE, 0x00);
00402 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00403
00404 canopen::controlPDO(id,canopen::CONTROLWORD_QUICKSTOP, 0x00);
00405 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00406
00407 canopen::sendSDO(id, canopen::MODES_OF_OPERATION, canopen::MODES_OF_OPERATION_INTERPOLATED_POSITION_MODE);
00408 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00409
00410 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00411
00412 canopen::setMotorState(id, canopen::MS_SWITCHED_ON_DISABLED);
00413 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00414
00415 canopen::setMotorState(id, canopen::MS_READY_TO_SWITCH_ON);
00416 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00417
00418 canopen::setMotorState(id, canopen::MS_SWITCHED_ON);
00419 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00420
00421 canopen::setMotorState(id, canopen::MS_OPERATION_ENABLED);
00422 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00423
00424 sendSDO((uint16_t)id, canopen::IP_TIME_UNITS, (uint8_t) syncInterval.count() );
00425 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00426 sendSDO((uint16_t)id, canopen::IP_TIME_INDEX, (uint8_t)canopen::IP_TIME_INDEX_MILLISECONDS);
00427 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00428 sendSDO((uint16_t)id, canopen::SYNC_TIMEOUT_FACTOR, (uint8_t)canopen::SYNC_TIMEOUT_FACTOR_DISABLE_TIMEOUT);
00429 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00430
00431 canopen::controlPDO(id, canopen::CONTROLWORD_ENABLE_MOVEMENT, 0x00);
00432 std::this_thread::sleep_for(std::chrono::milliseconds(200));
00433
00434 canopen::uploadSDO(id, canopen::STATUSWORD);
00435 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00436 canopen::uploadSDO(id, DRIVERTEMPERATURE);
00437 canopen::uploadSDO(id, MODES_OF_OPERATION_DISPLAY);
00438
00439 getErrors(id);
00440 }
00441
00442
00443 devices[id].setDesiredPos((double)devices[id].getActualPos());
00444 devices[id].setDesiredVel(0);
00445
00446 }
00447 recover_active = false;
00448
00449 for (auto id : canopen::deviceGroups[chainName].getCANids())
00450 {
00451
00452 if(devices[id].getIPMode())
00453 {
00454 std::cout << "Concluded driver side recover succesfully" << std::endl;
00455 }
00456 else
00457 {
00458 std::cout << "Problems occured during driver side recover" << std::endl;
00459 return false;
00460 }
00461 }
00462
00463 return true;
00464
00465 }
00468
00469
00470 void halt(std::string deviceFile, std::string chainName, std::chrono::milliseconds syncInterval)
00471 {
00472 CAN_Close(h);
00473
00474 NMTmsg.ID = 0;
00475 NMTmsg.MSGTYPE = 0x00;
00476 NMTmsg.LEN = 2;
00477
00478 syncMsg.ID = 0x80;
00479 syncMsg.MSGTYPE = 0x00;
00480
00481 syncMsg.LEN = 0x00;
00482
00483 if (!canopen::openConnection(deviceFile, canopen::baudRate))
00484 {
00485 std::cout << "Cannot open CAN device; aborting." << std::endl;
00486 exit(EXIT_FAILURE);
00487 }
00488 else
00489 {
00490
00491 }
00492
00493
00494 for (auto id : canopen::deviceGroups[chainName].getCANids())
00495 {
00496
00497 }
00498
00499 for (auto id : canopen::deviceGroups[chainName].getCANids())
00500 {
00501
00502
00503 canopen::sendSDO(id, canopen::CONTROLWORD, canopen:: CONTROLWORD_HALT);
00504
00505 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00506
00507 canopen::sendSDO(id, canopen::CONTROLWORD, canopen:: CONTROLWORD_DISABLE_INTERPOLATED);
00508
00509 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00510
00511 canopen::sendSDO(id, canopen::CONTROLWORD, canopen:: CONTROL_WORD_DISABLE_VOLTAGE);
00512
00513 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00514
00515 canopen::sendSDO(id, canopen::CONTROLWORD, canopen::CONTROLWORD_QUICKSTOP);
00516 canopen::uploadSDO(id, canopen::STATUSWORD);
00517 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00518
00519 }
00520 }
00521
00522
00523
00524
00525
00526 void setNMTState(uint16_t CANid, std::string targetState)
00527 {
00528
00529 }
00530
00531 bool setOperationMode(uint16_t CANid, const int8_t targetMode, double timeout)
00532 {
00533 std::chrono::time_point<std::chrono::high_resolution_clock> time_start, time_end;
00534
00535 time_start = std::chrono::high_resolution_clock::now();
00536
00537
00538 if ( devices[CANid].getMotorState() != MS_READY_TO_SWITCH_ON &&
00539 devices[CANid].getMotorState() != MS_SWITCHED_ON_DISABLED &&
00540 devices[CANid].getMotorState() != MS_SWITCHED_ON)
00541 {
00542 std::cout << "Found motor in state " << devices[CANid].getMotorState() << ", need to adjust state to SWITCHED_ON" << std::endl;
00543 setMotorState(CANid, canopen::MS_SWITCHED_ON);
00544 }
00545
00546
00547 while (devices[CANid].getCurrentModeofOperation() != targetMode)
00548 {
00549 canopen::sendSDO(CANid, canopen::MODES_OF_OPERATION, (uint8_t)targetMode);
00550 canopen::uploadSDO(CANid, canopen::MODES_OF_OPERATION_DISPLAY);
00551 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00552
00553
00554 time_end = std::chrono::high_resolution_clock::now();
00555 std::chrono::duration<double> elapsed_seconds = time_end-time_start;
00556
00557 if(elapsed_seconds.count() > timeout)
00558 {
00559 std::cout << "setting operation mode failed" << std::endl;
00560 return false;
00561 }
00562 }
00563
00564 return true;
00565 }
00566
00567 void setMotorState(uint16_t CANid, std::string targetState)
00568 {
00569
00570 start = std::chrono::high_resolution_clock::now();
00571
00572 while (devices[CANid].getMotorState() != targetState)
00573 {
00574 end = std::chrono::high_resolution_clock::now();
00575 std::chrono::duration<double> elapsed_seconds = end-start;
00576
00577 if(elapsed_seconds.count() > 3)
00578 return;
00579 canopen::uploadSDO(CANid, canopen::STATUSWORD);
00580 if (devices[CANid].getMotorState() == MS_FAULT)
00581 {
00582 canopen::uploadSDO(CANid, canopen::STATUSWORD);
00583 std::this_thread::sleep_for(std::chrono::milliseconds(50));
00584
00585 if(!devices[CANid].getFault())
00586 {
00587 canopen::controlPDO(CANid, canopen::CONTROLWORD_FAULT_RESET_0, 0x00);
00588 }
00589 else
00590 {
00591
00592 canopen::controlPDO(CANid, canopen::CONTROLWORD_FAULT_RESET_1, 0x00);
00593 }
00594
00595 }
00596
00597 if (devices[CANid].getMotorState() == MS_NOT_READY_TO_SWITCH_ON)
00598 {
00599 canopen::uploadSDO(CANid, canopen::STATUSWORD);
00600 canopen::controlPDO(CANid, canopen::CONTROLWORD_SHUTDOWN, 0x00);
00601 }
00602
00603 if (devices[CANid].getMotorState() == MS_SWITCHED_ON_DISABLED)
00604 {
00605 canopen::controlPDO(CANid, canopen::CONTROLWORD_SHUTDOWN, 0x00);
00606 }
00607
00608 if (devices[CANid].getMotorState() == MS_READY_TO_SWITCH_ON)
00609 {
00610 if (targetState == MS_SWITCHED_ON_DISABLED)
00611 {
00612 canopen::controlPDO(CANid, canopen::CONTROL_WORD_DISABLE_VOLTAGE, 0x00);
00613 }
00614 else
00615 {
00616 canopen::controlPDO(CANid, canopen::CONTROLWORD_SWITCH_ON, 0x00);
00617 }
00618 }
00619
00620 if (devices[CANid].getMotorState() == MS_SWITCHED_ON)
00621 {
00622 if (targetState == MS_SWITCHED_ON_DISABLED)
00623 {
00624 canopen::controlPDO(CANid, canopen::CONTROL_WORD_DISABLE_VOLTAGE, 0x00);
00625 }
00626 else if (targetState == MS_READY_TO_SWITCH_ON)
00627 {
00628 canopen::controlPDO(CANid, canopen::CONTROLWORD_SHUTDOWN, 0x00);
00629 }
00630 else
00631 {
00632 canopen::controlPDO(CANid, canopen::CONTROLWORD_ENABLE_OPERATION, 0x00);
00633 }
00634 }
00635
00636 if (devices[CANid].getMotorState() == MS_OPERATION_ENABLED)
00637 {
00638 if (targetState == MS_SWITCHED_ON_DISABLED)
00639 {
00640 canopen::sendSDO(CANid, canopen::CONTROLWORD, canopen::CONTROL_WORD_DISABLE_VOLTAGE);
00641 }
00642 else if (targetState == MS_READY_TO_SWITCH_ON)
00643 {
00644 canopen::sendSDO(CANid, canopen::CONTROLWORD, canopen::CONTROLWORD_SHUTDOWN);
00645 }
00646 else
00647 {
00648 canopen::sendSDO(CANid, canopen::CONTROLWORD, canopen::CONTROLWORD_DISABLE_OPERATION);
00649 }
00650 }
00651 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00652 }
00653 }
00654
00655
00656
00657
00658
00659 TPCANMsg NMTmsg;
00660
00661
00662
00663
00664
00665 TPCANMsg syncMsg;
00666
00667
00668
00669
00670
00671 void requestDataBlock1(uint8_t CANid)
00672 {
00673 TPCANMsg msg;
00674 std::memset(&msg, 0, sizeof(msg));
00675 msg.ID = CANid + 0x600;
00676 msg.MSGTYPE = 0x00;
00677 msg.LEN = 8;
00678 msg.DATA[0] = 0x60;
00679 msg.DATA[1] = 0x00;
00680 msg.DATA[2] = 0x00;
00681 msg.DATA[3] = 0x00;
00682 msg.DATA[4] = 0x00;
00683 msg.DATA[5] = 0x00;
00684 msg.DATA[6] = 0x00;
00685 msg.DATA[7] = 0x00;
00686 CAN_Write(h, &msg);
00687 }
00688
00689 void requestDataBlock2(uint8_t CANid)
00690 {
00691 TPCANMsg msg;
00692 std::memset(&msg, 0, sizeof(msg));
00693 msg.ID = CANid + 0x600;
00694 msg.MSGTYPE = 0x00;
00695 msg.LEN = 8;
00696 msg.DATA[0] = 0x70;
00697 msg.DATA[1] = 0x00;
00698 msg.DATA[2] = 0x00;
00699 msg.DATA[3] = 0x00;
00700 msg.DATA[4] = 0x00;
00701 msg.DATA[5] = 0x00;
00702 msg.DATA[6] = 0x00;
00703 msg.DATA[7] = 0x00;
00704 CAN_Write(h, &msg);
00705 }
00706
00707 void controlPDO(uint8_t CANid, u_int16_t control1, u_int16_t control2)
00708 {
00709 TPCANMsg msg;
00710 std::memset(&msg, 0, sizeof(msg));
00711 msg.ID = CANid + 0x200;
00712 msg.MSGTYPE = 0x00;
00713 msg.LEN = 2;
00714 msg.DATA[0] = control1;
00715 msg.DATA[1] = control2;
00716 CAN_Write(h, &msg);
00717 }
00718
00719 void uploadSDO(uint8_t CANid, SDOkey sdo)
00720 {
00721 TPCANMsg msg;
00722 std::memset(&msg, 0, sizeof(msg));
00723 msg.ID = CANid + 0x600;
00724 msg.MSGTYPE = 0x00;
00725 msg.LEN = 8;
00726 msg.DATA[0] = 0x40;
00727 msg.DATA[1] = sdo.index & 0xFF;
00728 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
00729 msg.DATA[3] = sdo.subindex;
00730 msg.DATA[4] = 0x00;
00731 msg.DATA[5] = 0x00;
00732 msg.DATA[6] = 0x00;
00733 msg.DATA[7] = 0x00;
00734 CAN_Write(h, &msg);
00735 }
00736
00737 void sendSDO(uint8_t CANid, SDOkey sdo, uint32_t value)
00738 {
00739 TPCANMsg msg;
00740 std::memset(&msg, 0, sizeof(msg));
00741 msg.ID = CANid + 0x600;
00742 msg.LEN = 8;
00743 msg.DATA[0] = 0x23;
00744 msg.DATA[1] = sdo.index & 0xFF;
00745 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
00746 msg.DATA[3] = sdo.subindex;
00747 msg.DATA[4] = value & 0xFF;
00748 msg.DATA[5] = (value >> 8) & 0xFF;
00749 msg.DATA[6] = (value >> 16) & 0xFF;
00750 msg.DATA[7] = (value >> 24) & 0xFF;
00751 CAN_Write(h, &msg);
00752 }
00753
00754 void sendSDO(uint8_t CANid, SDOkey sdo, int32_t value)
00755 {
00756 TPCANMsg msg;
00757 std::memset(&msg, 0, sizeof(msg));
00758 msg.ID = CANid + 0x600;
00759 msg.LEN = 8;
00760 msg.DATA[0] = 0x23;
00761 msg.DATA[1] = sdo.index & 0xFF;
00762 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
00763 msg.DATA[3] = sdo.subindex;
00764 msg.DATA[4] = value & 0xFF;
00765 msg.DATA[5] = (value >> 8) & 0xFF;
00766 msg.DATA[6] = (value >> 16) & 0xFF;
00767 msg.DATA[7] = (value >> 24) & 0xFF;
00768 CAN_Write(h, &msg);
00769 }
00770
00771 void sendSDO_unknown(uint8_t CANid, SDOkey sdo, int32_t value)
00772 {
00773 TPCANMsg msg;
00774 std::memset(&msg, 0, sizeof(msg));
00775 msg.ID = CANid + 0x600;
00776 msg.LEN = 8;
00777 msg.DATA[0] = 0x22;
00778 msg.DATA[1] = sdo.index & 0xFF;
00779 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
00780 msg.DATA[3] = sdo.subindex;
00781 msg.DATA[4] = value & 0xFF;
00782 msg.DATA[5] = (value >> 8) & 0xFF;
00783 msg.DATA[6] = (value >> 16) & 0xFF;
00784 msg.DATA[7] = (value >> 24) & 0xFF;
00785 CAN_Write(h, &msg);
00786 }
00787
00788 void sendSDO(uint8_t CANid, SDOkey sdo, uint8_t value)
00789 {
00790 TPCANMsg msg;
00791 std::memset(&msg, 0, sizeof(msg));
00792 msg.ID = CANid + 0x600;
00793 msg.LEN = 8;
00794 msg.DATA[0] = 0x2F;
00795 msg.DATA[1] = sdo.index & 0xFF;
00796 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
00797 msg.DATA[3] = sdo.subindex;
00798 msg.DATA[4] = value & 0xFF;
00799 msg.DATA[5] = 0x00;
00800 msg.DATA[6] = 0x00;
00801 msg.DATA[7] = 0x00;
00802 CAN_Write(h, &msg);
00803
00804
00805 }
00806
00807 void sendSDO(uint8_t CANid, SDOkey sdo, uint16_t value)
00808 {
00809 TPCANMsg msg;
00810 std::memset(&msg, 0, sizeof(msg));
00811 msg.ID = CANid + 0x600;
00812 msg.LEN = 8;
00813 msg.DATA[0] = 0x2B;
00814 msg.DATA[1] = sdo.index & 0xFF;
00815 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
00816 msg.DATA[3] = sdo.subindex;
00817 msg.DATA[4] = value & 0xFF;
00818 msg.DATA[5] = (value >> 8) & 0xFF;
00819 msg.DATA[6] = 0x00;
00820 msg.DATA[7] = 0x00;
00821 CAN_Write(h, &msg);
00822 }
00823
00824
00825
00826
00827
00828 void initDeviceManagerThread(std::string chainName, std::function<void (std::string)> const& deviceManager)
00829 {
00830 std::thread device_manager_thread(deviceManager, chainName);
00831 device_manager_thread.detach();
00832
00833 std::this_thread::sleep_for(std::chrono::milliseconds(10));
00834 }
00835
00836 void deviceManager(std::string chainName)
00837 {
00838 std::chrono::time_point<std::chrono::high_resolution_clock> time_start, time_end;
00839
00840
00841 while (true)
00842 {
00843 time_end = std::chrono::high_resolution_clock::now();
00844 std::chrono::duration<double> elapsed_seconds = time_end-time_start;
00845
00846 auto tic = std::chrono::high_resolution_clock::now();
00847 if (!recover_active)
00848 {
00849 for (auto id : canopen::deviceGroups[chainName].getCANids())
00850 {
00851 if(elapsed_seconds.count() > 2)
00852 {
00853 time_start = std::chrono::high_resolution_clock::now();
00854 canopen::uploadSDO(id, DRIVERTEMPERATURE);
00855 getErrors(id);
00856 readManErrReg(id);
00857 }
00858
00859 if (devices[id].getInitialized())
00860 {
00861 devices[id].updateDesiredPos();
00862 sendPos((uint16_t)id, (double)devices[id].getDesiredPos());
00863 }
00864 }
00865 canopen::sendSync();
00866 std::this_thread::sleep_for(syncInterval - (std::chrono::high_resolution_clock::now() - tic ));
00867 }
00868
00869 }
00870 }
00871
00872
00873 std::function< void (uint16_t CANid, double velocityValue) > sendVel;
00874 std::function< void (uint16_t CANid, double positionValue) > sendPos;
00875 std::function< void (uint16_t CANid, double positionValue, double velocityValue) > sendPosPPMode;
00876
00877 void defaultPDOOutgoing_interpolated(uint16_t CANid, double positionValue)
00878 {
00879 static const uint16_t myControlword = (CONTROLWORD_ENABLE_OPERATION | CONTROLWORD_ENABLE_IP_MODE);
00880 TPCANMsg msg;
00881 std::memset(&msg, 0, sizeof(msg));
00882 msg.ID = 0x300 + CANid;
00883 msg.MSGTYPE = 0x00;
00884 msg.LEN = 4;
00885 int32_t mdegPos = rad2mdeg(positionValue);
00886 msg.DATA[0] = mdegPos & 0xFF;
00887 msg.DATA[1] = (mdegPos >> 8) & 0xFF;
00888 msg.DATA[2] = (mdegPos >> 16) & 0xFF;
00889 msg.DATA[3] = (mdegPos >> 24) & 0xFF;
00890 CAN_Write(h, &msg);
00891 }
00892
00893 void defaultPDOOutgoing(uint16_t CANid, double positionValue)
00894 {
00895 static const uint16_t myControlword = (CONTROLWORD_ENABLE_OPERATION | CONTROLWORD_ENABLE_IP_MODE);
00896 TPCANMsg msg;
00897 std::memset(&msg, 0, sizeof(msg));
00898 msg.ID = 0x200 + CANid;
00899 msg.MSGTYPE = 0x00;
00900 msg.LEN = 8;
00901 msg.DATA[0] = myControlword & 0xFF;
00902 msg.DATA[1] = (myControlword >> 8) & 0xFF;
00903 msg.DATA[2] = 0x00;
00904 msg.DATA[3] = 0x00;
00905 int32_t mdegPos = rad2mdeg(positionValue);
00906 msg.DATA[4] = mdegPos & 0xFF;
00907 msg.DATA[5] = (mdegPos >> 8) & 0xFF;
00908 msg.DATA[6] = (mdegPos >> 16) & 0xFF;
00909 msg.DATA[7] = (mdegPos >> 24) & 0xFF;
00910 CAN_Write(h, &msg);
00911 }
00912
00913
00914
00915
00916 void defaultEMCY_incoming(uint16_t CANid, const TPCANRdMsg m)
00917 {
00918
00919
00920 uint16_t mydata_low = m.Msg.DATA[0];
00921 uint16_t mydata_high = m.Msg.DATA[1];
00922
00923
00924
00925
00926 }
00927
00928 void defaultPDO_incoming_status(uint16_t CANid, const TPCANRdMsg m)
00929 {
00930
00931 uint16_t mydata_low = m.Msg.DATA[0];
00932 uint16_t mydata_high = m.Msg.DATA[1];
00933
00934 int8_t mode_display = m.Msg.DATA[2];
00935
00936 if(canopen::use_limit_switch)
00937 {
00938
00939
00940 uint16_t limit_switch_ = m.Msg.DATA[2];
00941
00942 bool hardware_limit_positive = limit_switch_ & 0x02;
00943 bool hardware_limit_negative = limit_switch_ & 0x01;
00944
00945 devices[CANid].setNegativeLimit(hardware_limit_negative);
00946 devices[CANid].setPositiveLimit(hardware_limit_positive);
00947 }
00948
00949 bool ready_switch_on = mydata_low & 0x01;
00950 bool switched_on = mydata_low & 0x02;
00951 bool op_enable = mydata_low & 0x04;
00952 bool fault = mydata_low & 0x08;
00953
00954 bool volt_enable = mydata_low & 0x10;
00955 bool quick_stop = mydata_low & 0x20;
00956 bool switch_on_disabled = mydata_low & 0x40;
00957 bool warning = mydata_low & 0x80;
00958
00959 bool mode_specific = mydata_high & 0x01;
00960 bool remote = mydata_high & 0x02;
00961 bool target_reached = mydata_high & 0x04;
00962 bool internal_limit = mydata_high & 0x08;
00963 bool op_specific = mydata_high & 0x10;
00964 bool op_specific1 = mydata_high & 0x20;
00965 bool man_specific1 = mydata_high & 0x40;
00966 bool man_specific2 = mydata_high & 0x80;
00967
00968 bool ip_mode = ready_switch_on & switched_on & op_enable & volt_enable;
00969
00970
00971 if(!ready_switch_on)
00972 {
00973 if(fault)
00974 {
00975 devices[CANid].setMotorState(canopen::MS_FAULT);
00976 }
00977 else if(switch_on_disabled)
00978 {
00979 devices[CANid].setMotorState(canopen::MS_SWITCHED_ON_DISABLED);
00980 }
00981 else
00982 devices[CANid].setMotorState(canopen::MS_NOT_READY_TO_SWITCH_ON);
00983 }
00984
00985 else
00986 {
00987 if(switched_on)
00988 {
00989 if(op_enable)
00990 {
00991
00992
00993
00994 devices[CANid].setMotorState(canopen::MS_OPERATION_ENABLED);
00995
00996
00997 }
00998 else
00999 devices[CANid].setMotorState(canopen::MS_SWITCHED_ON);
01000 }
01001 else if(!quick_stop)
01002 devices[CANid].setMotorState(canopen::MS_QUICK_STOP_ACTIVE);
01003
01004 else
01005 devices[CANid].setMotorState(canopen::MS_READY_TO_SWITCH_ON);
01006
01007 }
01008
01009 if(fault & op_enable & switched_on & ready_switch_on)
01010 devices[CANid].setMotorState(canopen::MS_FAULT_REACTION_ACTIVE);
01011
01012
01013 devices[CANid].setFault(fault);
01014 devices[CANid].setIPMode(ip_mode);
01015 devices[CANid].setHoming(op_specific);
01016 devices[CANid].setOpSpec0(op_specific);
01017 devices[CANid].setOpSpec1(op_specific1);
01018 devices[CANid].setManSpec1(man_specific1);
01019 devices[CANid].setManSpec2(man_specific2);
01020 devices[CANid].setInternalLimits(internal_limit);
01021 devices[CANid].setTargetReached(target_reached);
01022 devices[CANid].setRemote(remote);
01023 devices[CANid].setModeSpec(mode_specific);
01024 devices[CANid].setWarning(warning);
01025 devices[CANid].setSwitchOnDisable(switch_on_disabled);
01026 devices[CANid].setQuickStop(quick_stop);
01027 devices[CANid].setOpEnable(op_enable);
01028 devices[CANid].setVoltageEnabled(volt_enable);
01029 devices[CANid].setReadySwitchON(ready_switch_on);
01030 devices[CANid].setSwitchON(switched_on);
01031
01032 devices[CANid].setCurrentModeofOperation(mode_display);
01033
01034
01035
01036
01037 }
01038
01039 void defaultPDO_incoming_pos(uint16_t CANid, const TPCANRdMsg m)
01040 {
01041 double newPos = mdeg2rad(m.Msg.DATA[0] + (m.Msg.DATA[1] << 8) + (m.Msg.DATA[2] << 16) + (m.Msg.DATA[3] << 24));
01042 double newVel = mdeg2rad(m.Msg.DATA[4] + (m.Msg.DATA[5] << 8) + (m.Msg.DATA[6] << 16) + (m.Msg.DATA[7] << 24));
01043
01044
01045
01046
01047 if (devices[CANid].getTimeStamp_msec() != std::chrono::milliseconds(0) || devices[CANid].getTimeStamp_usec() != std::chrono::microseconds(0))
01048 {
01049 auto deltaTime_msec = std::chrono::milliseconds(m.dwTime) - devices[CANid].getTimeStamp_msec();
01050 auto deltaTime_usec = std::chrono::microseconds(m.wUsec) - devices[CANid].getTimeStamp_usec();
01051 double deltaTime_double = static_cast<double>(deltaTime_msec.count()*1000 + deltaTime_usec.count()) * 0.000001;
01052 double result = (newPos - devices[CANid].getActualPos()) / deltaTime_double;
01053 devices[CANid].setActualVel(result);
01054 if (! devices[CANid].getInitialized())
01055 {
01056 devices[CANid].setDesiredPos(newPos);
01057 }
01058
01059 }
01060
01061 devices[CANid].setActualPos(newPos);
01062
01063
01064 devices[CANid].setTimeStamp_msec(std::chrono::milliseconds(m.dwTime));
01065 devices[CANid].setTimeStamp_usec(std::chrono::microseconds(m.wUsec));
01066
01067 }
01068 void defaultPDO_incoming(uint16_t CANid, const TPCANRdMsg m)
01069 {
01070 double newPos = mdeg2rad(m.Msg.DATA[4] + (m.Msg.DATA[5] << 8) + (m.Msg.DATA[6] << 16) + (m.Msg.DATA[7] << 24) );
01071
01072 if (devices[CANid].getTimeStamp_msec() != std::chrono::milliseconds(0) || devices[CANid].getTimeStamp_usec() != std::chrono::microseconds(0))
01073 {
01074 auto deltaTime_msec = std::chrono::milliseconds(m.dwTime) - devices[CANid].getTimeStamp_msec();
01075 auto deltaTime_usec = std::chrono::microseconds(m.wUsec) - devices[CANid].getTimeStamp_usec();
01076 double deltaTime_double = static_cast<double>(deltaTime_msec.count()*1000 + deltaTime_usec.count()) * 0.000001;
01077 double result = (newPos - devices[CANid].getActualPos()) / deltaTime_double;
01078 devices[CANid].setActualVel(result);
01079 if (! devices[CANid].getInitialized())
01080 {
01081 devices[CANid].setDesiredPos(newPos);
01082 }
01083
01084 }
01085
01086
01087 devices[CANid].setActualPos(newPos);
01088 devices[CANid].setTimeStamp_msec(std::chrono::milliseconds(m.dwTime));
01089 devices[CANid].setTimeStamp_usec(std::chrono::microseconds(m.wUsec));
01090
01091 uint16_t mydata_low = m.Msg.DATA[0];
01092 uint16_t mydata_high = m.Msg.DATA[1];
01093
01094 bool ready_switch_on = mydata_low & 0x01;
01095 bool switched_on = mydata_low & 0x02;
01096 bool op_enable = mydata_low & 0x04;
01097 bool fault = mydata_low & 0x08;
01098
01099 bool volt_enable = mydata_low & 0x10;
01100 bool quick_stop = mydata_low & 0x20;
01101 bool switch_on_disabled = mydata_low & 0x40;
01102 bool warning = mydata_low & 0x80;
01103
01104 bool mode_specific = mydata_high & 0x01;
01105 bool remote = mydata_high & 0x02;
01106 bool target_reached = mydata_high & 0x04;
01107 bool internal_limit = mydata_high & 0x08;
01108 bool op_specific = mydata_high & 0x10;
01109 bool op_specific1 = mydata_high & 0x20;
01110 bool man_specific1 = mydata_high & 0x40;
01111 bool man_specific2 = mydata_high & 0x80;
01112
01113 bool ip_mode = ready_switch_on & switched_on & op_enable & volt_enable;
01114
01115
01116 if(!ready_switch_on)
01117 {
01118 if(fault)
01119 {
01120 devices[CANid].setMotorState(canopen::MS_FAULT);
01121 }
01122 else if(switch_on_disabled)
01123 {
01124 devices[CANid].setMotorState(canopen::MS_SWITCHED_ON_DISABLED);
01125 }
01126 else
01127 devices[CANid].setMotorState(canopen::MS_NOT_READY_TO_SWITCH_ON);
01128 }
01129
01130 else
01131 {
01132 if(switched_on)
01133 {
01134 if(op_enable)
01135 {
01136
01137
01138
01139 devices[CANid].setMotorState(canopen::MS_OPERATION_ENABLED);
01140
01141
01142 }
01143 else
01144 devices[CANid].setMotorState(canopen::MS_SWITCHED_ON);
01145 }
01146 else if(!quick_stop)
01147 devices[CANid].setMotorState(canopen::MS_QUICK_STOP_ACTIVE);
01148
01149 else
01150 devices[CANid].setMotorState(canopen::MS_READY_TO_SWITCH_ON);
01151
01152 }
01153
01154 if(fault & op_enable & switched_on & ready_switch_on)
01155 devices[CANid].setMotorState(canopen::MS_FAULT_REACTION_ACTIVE);
01156
01157
01158 devices[CANid].setFault(fault);
01159 devices[CANid].setIPMode(ip_mode);
01160 devices[CANid].setHoming(op_specific);
01161 devices[CANid].setOpSpec0(op_specific);
01162 devices[CANid].setOpSpec1(op_specific1);
01163 devices[CANid].setManSpec1(man_specific1);
01164 devices[CANid].setManSpec2(man_specific2);
01165 devices[CANid].setInternalLimits(internal_limit);
01166 devices[CANid].setTargetReached(target_reached);
01167 devices[CANid].setRemote(remote);
01168 devices[CANid].setModeSpec(mode_specific);
01169 devices[CANid].setWarning(warning);
01170 devices[CANid].setSwitchOnDisable(switch_on_disabled);
01171 devices[CANid].setQuickStop(quick_stop);
01172 devices[CANid].setOpEnable(op_enable);
01173 devices[CANid].setVoltageEnabled(volt_enable);
01174 devices[CANid].setReadySwitchON(ready_switch_on);
01175 devices[CANid].setSwitchON(switched_on);
01176
01177
01178
01179
01180 }
01181
01182
01183
01184
01185
01186 void initListenerThread(std::function<void ()> const& listener)
01187 {
01188 std::thread listener_thread(listener);
01189 listener_thread.detach();
01190 std::this_thread::sleep_for(std::chrono::milliseconds(100));
01191
01192 }
01193
01194 void defaultListener()
01195 {
01196 while(true)
01197 {
01198
01199 TPCANRdMsg m;
01200 errno = LINUX_CAN_Read(h, &m);
01201 if (errno)
01202 perror("LINUX_CAN_Read() error");
01203
01204
01205 else if (m.Msg.ID == 0x080)
01206 {
01207
01208 }
01209
01210
01211 else if (m.Msg.ID >= 0x081 && m.Msg.ID <= 0x0FF)
01212 {
01213
01214 if (incomingEMCYHandlers.find(m.Msg.ID) != incomingEMCYHandlers.end())
01215 incomingEMCYHandlers[m.Msg.ID](m);
01216 }
01217
01218
01219 else if (m.Msg.ID == 0x100)
01220 {
01221
01222 }
01223
01224
01225 else if (m.Msg.ID >= 0x180 && m.Msg.ID <= 0x4FF)
01226 {
01227
01228
01229 if (incomingPDOHandlers.find(m.Msg.ID) != incomingPDOHandlers.end())
01230 incomingPDOHandlers[m.Msg.ID](m);
01231 }
01232
01233
01234 else if (m.Msg.ID >= 0x580 && m.Msg.ID <= 0x5FF)
01235 {
01236
01237 SDOkey sdoKey(m);
01238 if(sdo_protect)
01239 {
01240 std::copy(std::begin(m.Msg.DATA), std::end(m.Msg.DATA), std::begin(protect_msg));
01241 sdo_protect = false;
01242 }
01243 else
01244 {
01245 if (incomingErrorHandlers.find(sdoKey) != incomingErrorHandlers.end())
01246 incomingErrorHandlers[sdoKey](m.Msg.ID - 0x580, m.Msg.DATA);
01247 else if (incomingDataHandlers.find(sdoKey) != incomingDataHandlers.end())
01248 incomingDataHandlers[sdoKey](m.Msg.ID - 0x580, m.Msg.DATA);
01249 else if (incomingManufacturerDetails.find(sdoKey) != incomingManufacturerDetails.end())
01250 incomingManufacturerDetails[sdoKey](m.Msg.ID - 0x580, m.Msg.DATA);
01251 }
01252 }
01253
01254
01255 else if (m.Msg.ID >= 0x700 && m.Msg.ID <= 0x7FF)
01256 {
01257
01258 uint16_t CANid = (uint16_t)(m.Msg.ID - 0x700);
01259
01260 std::cout << "Bootup received. Node-ID = " << CANid << std::endl;
01261 std::map<uint8_t,Device>::const_iterator search = devices.find(CANid);
01262 if(search != devices.end())
01263 {
01264 std::cout << "Found " << (u_int16_t)search->first << "\n";
01265 devices[CANid].setNMTInit(true);
01266 }
01267 else
01268 {
01269 std::cout << "Node:" << CANid << " could not be found on the required devices list." << std::endl;
01270 std::cout << "Ignoring" << std::endl;
01271 }
01272
01273 }
01274 else
01275 {
01276
01277 }
01278 }
01279 }
01280
01281
01282
01283
01284 void getErrors(uint16_t CANid)
01285 {
01286 canopen::uploadSDO(CANid, canopen::ERRORWORD);
01287 }
01288
01289 void manufacturer_incoming(uint8_t CANid, BYTE data[8])
01290 {
01291 sdo_protect = true;
01292
01293 if(data[1]+(data[2]<<8) == 0x1008)
01294 {
01295 std::vector<char> manufacturer_device_name = canopen::obtainManDevName(CANid, data[4]);
01296
01297 devices[CANid].setManufacturerDevName(manufacturer_device_name);
01298 }
01299
01300
01301
01302
01303
01304
01305 }
01306
01307 void errorword_incoming(uint8_t CANid, BYTE data[8])
01308 {
01309 std::stringstream str_stream;
01310
01311 if(data[1]+(data[2]<<8) == 0x1001)
01312 {
01313 uint16_t error_register;
01314 error_register = data[4];
01315
01316 str_stream << "error_register=0x" << std::hex << (int)error_register << ", categories:";
01317
01318 if ( error_register & canopen::EMC_k_1001_GENERIC )
01319 str_stream << " generic,";
01320 if ( error_register & canopen::EMC_k_1001_CURRENT)
01321 str_stream << " current,";
01322 if ( error_register & canopen::EMC_k_1001_VOLTAGE )
01323 str_stream << " voltage,";
01324 if ( error_register & canopen::EMC_k_1001_TEMPERATURE )
01325 str_stream << " temperature,";
01326 if ( error_register & canopen::EMC_k_1001_COMMUNICATION )
01327 str_stream << " communication,";
01328 if ( error_register & canopen::EMC_k_1001_DEV_PROF_SPEC )
01329 str_stream << " device profile specific,";
01330 if ( error_register & canopen::EMC_k_1001_RESERVED )
01331 str_stream << " reserved,";
01332 if ( error_register & canopen::EMC_k_1001_MANUFACTURER)
01333 str_stream << " manufacturer specific";
01334 str_stream << "\n";
01335
01336 devices[CANid].setErrorRegister(str_stream.str());
01337 }
01338 else if(data[1]+(data[2]<<8) == 0x1002)
01339 {
01340 uint16_t code = data[4];
01341 uint16_t classification = data[5];
01342
01343 str_stream << "manufacturer_status_register=0x" << std::hex << int(classification) << int(code) <<
01344 ": code=0x" << std::hex << int( code ) << " (" << errorsCode[int(code)] << "),"
01345 << ", classification=0x" << std::hex << int( classification ) << std::dec;
01346 if ( classification == 0x88 )
01347 str_stream << " (CMD_ERROR)";
01348 if ( classification == 0x89 )
01349 str_stream << " (CMD_WARNING)";
01350 if ( classification == 0x8a )
01351 str_stream << " (CMD_INFO)";
01352 str_stream << "\n";
01353
01354 devices[CANid].setManufacturerErrorRegister(str_stream.str());
01355 }
01356 }
01357
01358 void readManErrReg(uint16_t CANid)
01359 {
01360 canopen::uploadSDO(CANid, canopen::MANUFACTURER);
01361 }
01362
01363 void readErrorsRegister(uint16_t CANid, std::shared_ptr<TPCANRdMsg> m)
01364 {
01365 canopen::uploadSDO(CANid, canopen::STATUSWORD);
01366 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01367 canopen::processSingleSDO(CANid, m);
01368
01369 canopen::uploadSDO(CANid, canopen::ERRORWORD);
01370 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01371 canopen::processSingleSDO(CANid, m);
01372
01373 uint16_t error_register;
01374 error_register = m->Msg.DATA[4];
01375
01376 std::cout << "error_register=0x" << std::hex << (int)error_register << ", categories:";
01377
01378 if ( error_register & canopen::EMC_k_1001_GENERIC )
01379 std::cout << " generic,";
01380 if ( error_register & canopen::EMC_k_1001_CURRENT)
01381 std::cout << " current,";
01382 if ( error_register & canopen::EMC_k_1001_VOLTAGE )
01383 std::cout << " voltage,";
01384 if ( error_register & canopen::EMC_k_1001_TEMPERATURE )
01385 std::cout << " temperature,";
01386 if ( error_register & canopen::EMC_k_1001_COMMUNICATION )
01387 std::cout << " communication,";
01388 if ( error_register & canopen::EMC_k_1001_DEV_PROF_SPEC )
01389 std::cout << " device profile specific,";
01390 if ( error_register & canopen::EMC_k_1001_RESERVED )
01391 std::cout << " reserved,";
01392 if ( error_register & canopen::EMC_k_1001_MANUFACTURER)
01393 std::cout << " manufacturer specific";
01394 std::cout << "\n";
01395 }
01396
01397 std::vector<uint16_t> obtainVendorID(uint16_t CANid)
01398 {
01399 canopen::uploadSDO(CANid, canopen::IDENTITYVENDORID);
01400 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01401 }
01402
01403 std::vector<uint16_t> obtainProdCode(uint16_t CANid, std::shared_ptr<TPCANRdMsg> m)
01404 {
01405 canopen::uploadSDO(CANid, canopen::IDENTITYPRODUCTCODE);
01406 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01407
01408 std::vector<uint16_t> product_code;
01409
01410 canopen::processSingleSDO(CANid, m);
01411
01412 uint16_t id4 = m->Msg.DATA[4];
01413 uint16_t id3 = m->Msg.DATA[5];
01414 uint16_t id2 = m->Msg.DATA[6];
01415 uint16_t id1 = m->Msg.DATA[7];
01416
01417 product_code.push_back(id1);
01418 product_code.push_back(id2);
01419 product_code.push_back(id3);
01420 product_code.push_back(id4);
01421
01422 return product_code;
01423
01424 }
01425
01426 uint16_t obtainRevNr(uint16_t CANid, std::shared_ptr<TPCANRdMsg> m)
01427 {
01428 canopen::uploadSDO(CANid, canopen::IDENTITYREVNUMBER);
01429 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01430
01431
01432 canopen::processSingleSDO(CANid, m);
01433
01434 uint16_t rev_number = m->Msg.DATA[4];
01435
01436 return rev_number;
01437
01438 }
01439
01440 std::vector<char> obtainManDevName(uint16_t CANid, int size_name)
01441 {
01442
01443 std::vector<char> manufacturer_device_name;
01444
01445 canopen::requestDataBlock1(CANid);
01446 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01447 for (auto it : protect_msg)
01448 {
01449 if(manufacturer_device_name.size() <= size_name)
01450 manufacturer_device_name.push_back(it);
01451 }
01452
01453 return manufacturer_device_name;
01454
01455 }
01456
01457
01458
01459
01460 std::vector<char> obtainManHWVersion(uint16_t CANid, std::shared_ptr<TPCANRdMsg> m)
01461 {
01462 canopen::uploadSDO(CANid, canopen::MANUFACTURERHWVERSION);
01463 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01464
01465 std::vector<char> manufacturer_hw_version;
01466
01467 canopen::processSingleSDO(CANid, m);
01468
01469 int size = m->Msg.DATA[4];
01470
01471 canopen::requestDataBlock1(CANid);
01472 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01473
01474 canopen::processSingleSDO(CANid, m);
01475
01476
01477 for (auto it : m->Msg.DATA)
01478 {
01479 if(manufacturer_hw_version.size() <= size)
01480 manufacturer_hw_version.push_back(it);
01481 }
01482
01483
01484 canopen::requestDataBlock2(CANid);
01485 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01486
01487 canopen::processSingleSDO(CANid, m);
01488
01489
01490 for (auto it : m->Msg.DATA)
01491 {
01492 if(manufacturer_hw_version.size() <= size)
01493 manufacturer_hw_version.push_back(it);
01494 }
01495
01496 return manufacturer_hw_version;
01497 }
01498
01499 std::vector<char> obtainManSWVersion(uint16_t CANid, std::shared_ptr<TPCANRdMsg> m)
01500 {
01501 std::vector<char> manufacturer_sw_version;
01502
01503 canopen::uploadSDO(CANid, canopen::MANUFACTURERSOFTWAREVERSION);
01504 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01505
01506 canopen::processSingleSDO(CANid, m);
01507
01508 int size = (uint8_t)m->Msg.DATA[4];
01509
01510 canopen::requestDataBlock1(CANid);
01511 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01512
01513 canopen::processSingleSDO(CANid, m);
01514
01515
01516 for (auto it : m->Msg.DATA)
01517 {
01518 if(manufacturer_sw_version.size() <= size)
01519 manufacturer_sw_version.push_back(it);
01520 }
01521
01522
01523 canopen::requestDataBlock2(CANid);
01524 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01525
01526 canopen::processSingleSDO(CANid, m);
01527
01528
01529 for (auto it : m->Msg.DATA)
01530 {
01531 if(manufacturer_sw_version.size() <= size)
01532 manufacturer_sw_version.push_back(it);
01533 }
01534
01535 canopen::requestDataBlock1(CANid);
01536 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01537
01538 canopen::processSingleSDO(CANid, m);
01539
01540
01541 for (auto it : m->Msg.DATA)
01542 {
01543 if(manufacturer_sw_version.size() <= size)
01544 manufacturer_sw_version.push_back(it);
01545 }
01546
01547 canopen::requestDataBlock2(CANid);
01548 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01549
01550 canopen::processSingleSDO(CANid, m);
01551
01552
01553 for (auto it : m->Msg.DATA)
01554 {
01555 if(manufacturer_sw_version.size() <= size)
01556 manufacturer_sw_version.push_back(it);
01557 }
01558
01559 return manufacturer_sw_version;
01560
01561 }
01562
01563
01564
01565 void sdo_incoming(uint8_t CANid, BYTE data[8])
01566 {
01567 uint16_t SDOid = data[1]+(data[2]<<8);
01568
01569 if(SDOid == STATUSWORD.index)
01570 {
01571 uint16_t mydata_low = data[4];
01572 uint16_t mydata_high = data[5];
01573
01574 bool ready_switch_on = mydata_low & 0x01;
01575 bool switched_on = mydata_low & 0x02;
01576 bool op_enable = mydata_low & 0x04;
01577 bool fault = mydata_low & 0x08;
01578 bool volt_enable = mydata_low & 0x10;
01579 bool quick_stop = mydata_low & 0x20;
01580 bool switch_on_disabled = mydata_low & 0x40;
01581 bool warning = mydata_low & 0x80;
01582
01583 bool mode_specific = mydata_high & 0x01;
01584 bool remote = mydata_high & 0x02;
01585 bool target_reached = mydata_high & 0x04;
01586 bool internal_limit = mydata_high & 0x08;
01587 bool op_specific = mydata_high & 0x10;
01588 bool op_specific1 = mydata_high & 0x20;
01589 bool man_specific1 = mydata_high & 0x40;
01590 bool man_specific2 = mydata_high & 0x80;
01591
01592 if(!ready_switch_on)
01593 {
01594 if(fault)
01595 {
01596 devices[CANid].setMotorState(canopen::MS_FAULT);
01597 }
01598 else if(switch_on_disabled)
01599 {
01600 devices[CANid].setMotorState(canopen::MS_SWITCHED_ON_DISABLED);
01601 }
01602 else
01603 devices[CANid].setMotorState(canopen::MS_NOT_READY_TO_SWITCH_ON);
01604 }
01605
01606 else
01607 {
01608 if(switched_on)
01609 {
01610 if(op_enable)
01611 {
01612
01613
01614
01615 devices[CANid].setMotorState(canopen::MS_OPERATION_ENABLED);
01616
01617
01618 }
01619 else
01620 devices[CANid].setMotorState(canopen::MS_SWITCHED_ON);
01621 }
01622 else if(!quick_stop)
01623 devices[CANid].setMotorState(canopen::MS_QUICK_STOP_ACTIVE);
01624
01625 else
01626 devices[CANid].setMotorState(canopen::MS_READY_TO_SWITCH_ON);
01627
01628 }
01629
01630 if(fault & op_enable & switched_on & ready_switch_on)
01631 devices[CANid].setMotorState(canopen::MS_FAULT_REACTION_ACTIVE);
01632
01633
01634
01635 devices[CANid].setFault(fault);
01636 devices[CANid].setHoming(op_specific);
01637 devices[CANid].setOpSpec0(op_specific);
01638 devices[CANid].setOpSpec1(op_specific1);
01639 devices[CANid].setManSpec1(man_specific1);
01640 devices[CANid].setManSpec2(man_specific2);
01641 devices[CANid].setInternalLimits(internal_limit);
01642 devices[CANid].setTargetReached(target_reached);
01643 devices[CANid].setRemote(remote);
01644 devices[CANid].setModeSpec(mode_specific);
01645 devices[CANid].setWarning(warning);
01646 devices[CANid].setSwitchOnDisable(switch_on_disabled);
01647 devices[CANid].setQuickStop(quick_stop);
01648 devices[CANid].setOpEnable(op_enable);
01649 devices[CANid].setVoltageEnabled(volt_enable);
01650 devices[CANid].setReadySwitchON(ready_switch_on);
01651 devices[CANid].setSwitchON(switched_on);
01652
01653
01654 }
01655 else if(SDOid == DRIVERTEMPERATURE.index)
01656 {
01657 devices[CANid].setDriverTemperature(data[4]);
01658 }
01659 else if(SDOid == MODES_OF_OPERATION_DISPLAY.index)
01660 {
01661 devices[CANid].setCurrentModeofOperation(data[4]);
01662 }
01663 }
01664
01665 void processSingleSDO(uint8_t CANid, std::shared_ptr<TPCANRdMsg> message)
01666 {
01667 message->Msg.ID = 0x00;
01668
01669 while (message->Msg.ID != (0x580+CANid))
01670 {
01671 LINUX_CAN_Read(canopen::h, message.get());
01672 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01673 }
01674 }
01675
01676 void pdoChanged(std::string chainName)
01677 {
01678 for (auto id : canopen::deviceGroups[chainName].getCANids())
01679 {
01680 TPCANMsg* mes;
01682 mes->ID =id + 0x600;
01683 mes->MSGTYPE = 0x00;
01684 mes->LEN = 8;
01685 mes->DATA[0] = 0x2F;
01686 mes->DATA[1] = 0x20;
01687 mes->DATA[2] = 0x2F;
01688 mes->DATA[3] = 0x04;
01689 mes->DATA[4] = 0x00;
01690 mes->DATA[5] = 0x00;
01691 mes->DATA[6] = 0x00;
01692 mes->DATA[7] = 0x01;
01693 CAN_Write(canopen::h, mes);
01694
01695 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01696 }
01697 }
01698
01699 void disableRPDO(std::string chainName, int object)
01700 {
01701 for (auto id : canopen::deviceGroups[chainName].getCANids())
01702 {
01703 if(object == 0)
01704 {
01705 int32_t data = (canopen::RPDO1_msg + id) + (0x00 << 16) + (0x80 << 24);
01706 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01707 }
01708 else if(object == 1)
01709 {
01710 int32_t data = (canopen::RPDO2_msg + id) + (0x00 << 16) + (0x80 << 24);
01711 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01712
01713 }
01714
01715 else if(object == 2)
01716 {
01717 int32_t data = (canopen::RPDO3_msg + id) + (0x00 << 16) + (0x80 << 24);
01718 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01719 }
01720
01721 else if(object == 3)
01722
01723 {
01724 int32_t data = (canopen::RPDO4_msg + id) + (0x00 << 16) + (0x80 << 24);
01725 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01726 }
01727
01728 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01729
01731
01732 }
01733 }
01734
01735 void setObjects(std::string chainName)
01736 {
01737 for (auto id : canopen::deviceGroups[chainName].getCANids())
01738 {
01739 int32_t data = 0x1388 + (0x00 << 16) + (0x00 << 24);
01740 sendSDO_unknown(id, SDOkey(0x6081,0x00), data);
01741 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01742
01743 data = 0x1388 + (0x00 << 16) + (0x00 << 24);
01744 sendSDO_unknown(id, SDOkey(0x607f,0x00), data);
01745 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01746
01747 data = 0x1388 + (0x00 << 16) + (0x00 << 24);
01748 sendSDO_unknown(id, SDOkey(0x6083,0x00), data);
01749 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01750
01751 data = 0x1388 + (0x00 << 16) + (0x00 << 24);
01752 sendSDO_unknown(id, SDOkey(0x60c5,0x00), data);
01753 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01754
01755 data = 0x1388 + (0x00 << 16) + (0x00 << 24);
01756 sendSDO_unknown(id, SDOkey(0x60c6,0x00), data);
01757 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01758
01759 data = 0x1388 + (0x00 << 16) + (0x00 << 24);
01760 sendSDO_unknown(id, SDOkey(0x6082,0x00), data);
01761 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01762
01763 }
01764 }
01765
01766 void clearRPDOMapping(std::string chainName, int object)
01767 {
01768 for (auto id : canopen::deviceGroups[chainName].getCANids())
01769 {
01770 int32_t data = (0x00 << 16) + (0x80 << 24);
01771
01772 sendSDO_unknown(id, SDOkey(RPDO_map.index+object,0x00), data);
01773
01774 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01775 }
01776 }
01777
01778 void makeRPDOMapping(std::string chainName, int object, std::vector<std::string> registers, std::vector<int> sizes , u_int8_t sync_type)
01779 {
01780 for (auto id : canopen::deviceGroups[chainName].getCANids())
01781 {
01782 int ext_counter=0;
01783 for(int counter=0; counter < registers.size();counter++)
01784 {
01786 int index_data;
01787
01788 std::stringstream str_stream;
01789 str_stream << registers[counter];
01790 str_stream >> std::hex >> index_data;
01791
01792 str_stream.str( std::string() );
01793 str_stream.clear();
01794
01798 int32_t data = (sizes[counter]) + (index_data << 8);
01799
01800 sendSDO(id, SDOkey(RPDO_map.index+object,counter+1), data);
01801
01802 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01803
01804 ext_counter++;
01805 }
01808
01809 sendSDO(id, SDOkey(RPDO.index+object,0x02), u_int8_t(sync_type));
01810
01811 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01816 sendSDO(id, SDOkey(RPDO_map.index+object,0x00), u_int8_t(ext_counter));
01817
01818 }
01819 }
01820
01821 void enableRPDO(std::string chainName, int object)
01822 {
01823 for (auto id : canopen::deviceGroups[chainName].getCANids())
01824 {
01825 if(object ==0)
01826 {
01827 int32_t data = (canopen::RPDO1_msg + id) + (0x00 << 16) + (0x00 << 24);
01828
01829 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01830 }
01831 else if(object == 1)
01832 {
01833 int32_t data = (canopen::RPDO2_msg + id) + (0x00 << 16) + (0x00 << 24);
01834
01835 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01836 }
01837 else if(object == 2)
01838 {
01839 int32_t data = (canopen::RPDO3_msg + id) + (0x00 << 16) + (0x00 << 24);
01840
01841 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01842 }
01843 else if(object == 3)
01844 {
01845 int32_t data = (canopen::RPDO4_msg + id) + (0x00 << 16) + (0x00 << 24);
01846
01847 sendSDO(id, SDOkey(RPDO.index+object,0x01), data);
01848 }
01849
01850 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01851
01853 }
01854 }
01855
01856
01857
01858
01859
01860
01861
01862 void disableTPDO(std::string chainName,int object)
01863 {
01864
01865 for(auto id : canopen::deviceGroups[chainName].getCANids())
01866 {
01867
01869
01870 if(object == 0)
01871 {
01872 int32_t data = (canopen::TPDO1_msg + id) + (0x00 << 16) + (0x80 << 24);
01873 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01874 }
01875 else if(object == 1)
01876 {
01877 int32_t data = (canopen::TPDO2_msg + id) + (0x00 << 16) + (0x80 << 24);
01878 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01879
01880 }
01881
01882 else if(object == 2)
01883 {
01884 int32_t data = (canopen::TPDO3_msg + id) + (0x00 << 16) + (0x80 << 24);
01885 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01886 }
01887
01888 else if(object == 3)
01889
01890 {
01891 int32_t data = (canopen::TPDO4_msg + id) + (0x00 << 16) + (0x80 << 24);
01892 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01893 }
01894
01895 else
01896 std::cout << "Incorrect object for mapping" << std::endl;
01897
01898
01899
01900 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01901
01903 }
01904
01905
01906 }
01907
01908 void clearTPDOMapping(std::string chainName, int object)
01909 {
01910 for (auto id : canopen::deviceGroups[chainName].getCANids())
01911 {
01914
01915 sendSDO(id, SDOkey(TPDO_map.index+object,0x00), u_int8_t(0x00));
01916
01917 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01918 }
01919 }
01920
01921 void makeTPDOMapping(std::string chainName, int object, std::vector<std::string> registers, std::vector<int> sizes, u_int8_t sync_type)
01922 {
01923 for (auto id : canopen::deviceGroups[chainName].getCANids())
01924 {
01929 int ext_counter=0;
01930 for(int counter=0; counter < registers.size();counter++)
01931 {
01933 int index_data;
01934
01935 std::stringstream str_stream;
01936 str_stream << registers[counter];
01937 str_stream >> std::hex >> index_data;
01938
01939 str_stream.str( std::string() );
01940 str_stream.clear();
01941
01945 int32_t data = (sizes[counter]) + (index_data << 8);
01946
01947 sendSDO(id, SDOkey(TPDO_map.index+object,counter+1), data);
01948
01949 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01950
01951 ext_counter++;
01952 }
01955
01956 sendSDO(id, SDOkey(TPDO.index+object,0x02), u_int8_t(sync_type));
01957
01958 std::this_thread::sleep_for(std::chrono::milliseconds(10));
01963 sendSDO(id, SDOkey(TPDO_map.index+object,0x00), u_int8_t(ext_counter));
01964 }
01965
01966 }
01967
01968 void enableTPDO(std::string chainName, int object)
01969 {
01970 for (auto id : canopen::deviceGroups[chainName].getCANids())
01971 {
01975 if(object ==0)
01976 {
01977 int32_t data = (canopen::TPDO1_msg + id) + (0x00 << 16) + (0x00 << 24);
01978
01979 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01980 }
01981 else if(object == 1)
01982 {
01983 int32_t data = (canopen::TPDO2_msg + id) + (0x00 << 16) + (0x00 << 24);
01984
01985 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01986 }
01987 else if(object == 2)
01988 {
01989 int32_t data = (canopen::TPDO3_msg + id) + (0x00 << 16) + (0x00 << 24);
01990
01991 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01992 }
01993 else if(object == 3)
01994 {
01995 int32_t data = (canopen::TPDO4_msg + id) + (0x00 << 16) + (0x00 << 24);
01996
01997 sendSDO(id, SDOkey(TPDO.index+object,0x01), data);
01998 }
01999
02000 std::this_thread::sleep_for(std::chrono::milliseconds(10));
02001
02002 }
02004 }
02005
02006
02007
02008
02009 }
02010