demo_hr_receiver.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  1. /*
  2. This software is subject to the license described in the License.txt file
  3. included with this software distribution. You may not use this file except
  4. in compliance with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2016
  6. All rights reserved.
  7. */
  8. #include "demo_hr_receiver.h"
  9. ////////////////////////////////////////////////////////////////////////////////
  10. // The Demo ANT+ HRM Receiver PC app.
  11. //
  12. // For preventing dependency issues, please launch the ANT_Libraries.sln file in
  13. // Visual Studio 2008 instead of accessing the project on its own.
  14. //
  15. // A simple command line HRM Receiver app built on top of the ANT library that
  16. // demonstrates how to comply with the required ANT+ specifications.
  17. // Please note that other additions can be made while designing an HRM Receiver;
  18. // this is just for demonstration purposes. For details regarding the ANT+ HRM
  19. // specs, please visit www.thisisant.com/developer
  20. ////////////////////////////////////////////////////////////////////////////////
  21. int main(int argc, char **argv)
  22. {
  23. printf("********************************************************\n");
  24. printf("Demo ANT+ Heart Rate Monitor (HRM) Receiver application\n");
  25. printf("********************************************************\n");
  26. HRMReceiver* Receiver = new HRMReceiver();
  27. // Initialising with invalid device.
  28. // User will be prompted later if it wasn't passed in.
  29. // ucDeviceNumber = USB device to which the ANT device is connected
  30. UCHAR ucDeviceNumber = 0xFF;
  31. if(argc > 1)
  32. {
  33. ucDeviceNumber = (UCHAR) atoi(argv[1]);
  34. }
  35. if(Receiver->Init(ucDeviceNumber))
  36. Receiver->Start();
  37. else
  38. delete Receiver;
  39. return 0;
  40. }
  41. ////////////////////////////////////////////////////////////////////////////////
  42. // HRMReceiver (Heart Rate Receiver)
  43. //
  44. // Constructor, intializes HRMReceiver class
  45. //
  46. ////////////////////////////////////////////////////////////////////////////////
  47. HRMReceiver::HRMReceiver()
  48. {
  49. ucChannelType = CHANNEL_TYPE_SLAVE; // HRM Receiver is a slave
  50. pclSerialObject = (DSISerialGeneric*)NULL;
  51. pclMessageObject = (DSIFramerANT*)NULL;
  52. uiDSIThread = (DSI_THREAD_ID)NULL;
  53. bMyDone = FALSE;
  54. bDone = FALSE;
  55. bDisplay = TRUE;
  56. bProcessedData = TRUE;
  57. bBroadcasting = FALSE;
  58. }
  59. ////////////////////////////////////////////////////////////////////////////////
  60. // ~HRMReceiver
  61. //
  62. // Destructor, clean up and loose memory
  63. //
  64. ////////////////////////////////////////////////////////////////////////////////
  65. HRMReceiver::~HRMReceiver()
  66. {
  67. if(pclMessageObject)
  68. delete pclMessageObject;
  69. if(pclSerialObject)
  70. delete pclSerialObject;
  71. }
  72. ////////////////////////////////////////////////////////////////////////////////
  73. // Init
  74. //
  75. // Initize the HRMReceiver and ANT Library.
  76. //
  77. // ucDeviceNumber_: USB Device Number (0 for first USB stick plugged and so on)
  78. // If not specified on command line, 0xFF is passed in as invalid.
  79. ////////////////////////////////////////////////////////////////////////////////
  80. BOOL HRMReceiver::Init(UCHAR ucDeviceNumber_)
  81. {
  82. BOOL bStatus;
  83. // Initialize condition var and mutex
  84. UCHAR ucCondInit = DSIThread_CondInit(&condTestDone);
  85. assert(ucCondInit == DSI_THREAD_ENONE);
  86. UCHAR ucMutexInit = DSIThread_MutexInit(&mutexTestDone);
  87. assert(ucMutexInit == DSI_THREAD_ENONE);
  88. #if defined(DEBUG_FILE)
  89. // Enable logging
  90. DSIDebug::Init();
  91. DSIDebug::SetDebug(TRUE);
  92. #endif
  93. // Create Serial object.
  94. pclSerialObject = new DSISerialGeneric();
  95. assert(pclSerialObject);
  96. // NOTE: Will fail if the module is not available.
  97. // If no device number was specified on the command line,
  98. // prompt the user for input.
  99. if(ucDeviceNumber_ == 0xFF)
  100. {
  101. printf("USB Device number?\n"); fflush(stdout);
  102. char st[1024];
  103. fgets(st, sizeof(st), stdin);
  104. sscanf(st, "%u", &ucDeviceNumber_);
  105. }
  106. printf("USB Number: %d\n", ucDeviceNumber_);
  107. // Prompting user for network parameters
  108. // Channel Number
  109. printf("ANT Channel number? (Press Enter for default: 0)\n"); fflush(stdout);
  110. char st[1024];
  111. fgets(st, sizeof(st), stdin);
  112. ucAntChannel = (UCHAR)atoi(st);
  113. printf("Ant Channel number: %d\n", ucAntChannel);
  114. // Transmission type
  115. printf("ANT Transmission type? (Press Enter for wildcarding)\n"); fflush(stdout);
  116. char st1[1024];
  117. fgets(st1, sizeof(st1), stdin);
  118. ucTransType = (UCHAR)atoi(st1);
  119. if (ucTransType == (UCHAR)0)
  120. {
  121. printf("ANT Transmission type wildcarded\n");
  122. }
  123. else
  124. {
  125. printf("ANT Transmission type: %d\n", ucTransType);
  126. }
  127. // Device Number
  128. printf("Transmitter Device number? (Press Enter for wildcarding)\n"); fflush(stdout);
  129. char st2[1024];
  130. fgets(st2, sizeof(st2), stdin);
  131. usDeviceNum = (USHORT)atoi(st2);
  132. if (usDeviceNum == (USHORT)0)
  133. {
  134. printf("Transmitter Device Number wildcarded\n");
  135. }
  136. else
  137. {
  138. printf("Transmitter Device Number: %d\n", usDeviceNum);
  139. }
  140. // Network Number
  141. printf("Network number? (Press Enter for default: 0)\n"); fflush(stdout);
  142. char st3[1024];
  143. fgets(st3, sizeof(st3), stdin);
  144. ucNetworkNum = (UCHAR)atoi(st3);
  145. printf("Network Number: %d\n", ucNetworkNum);
  146. // Message Period
  147. int period_option;
  148. char st4[10];
  149. USHORT usMessagePeriods[] = USER_MESSAGE_PERIODS;
  150. int len_usMessagePeriods = sizeof(usMessagePeriods)/sizeof(USHORT);
  151. while(1)
  152. {
  153. printf("Message Period (in counts)? ");
  154. for (int i = 0; i < len_usMessagePeriods; i++)
  155. {
  156. printf("%d: %d", i, usMessagePeriods[i]);
  157. if (i != len_usMessagePeriods - 1)
  158. {
  159. printf(" , ");
  160. }
  161. }
  162. printf("\n");
  163. fflush(stdout);
  164. fgets(st4, sizeof(st4), stdin);
  165. period_option = atoi(st4);
  166. if (period_option >= len_usMessagePeriods)
  167. {
  168. printf("Invalid Period. Try again\n");
  169. }
  170. else
  171. {
  172. printf("Message Period: %d\n", usMessagePeriods[period_option]);
  173. break;
  174. }
  175. }
  176. usMessagePeriod = usMessagePeriods[period_option];
  177. // Initialize Serial object.
  178. // The device number depends on how many USB sticks have been
  179. // plugged into the PC. The first USB stick plugged will be 0
  180. // the next 1 and so on.
  181. //
  182. // The Baud Rate depends on the ANT solution being used. AP1
  183. // is 50000, all others are 57600
  184. bStatus = pclSerialObject->Init(USER_BAUDRATE, ucDeviceNumber_);
  185. assert(bStatus);
  186. // Create Framer object.
  187. pclMessageObject = new DSIFramerANT(pclSerialObject);
  188. assert(pclMessageObject);
  189. // Initialize Framer object.
  190. bStatus = pclMessageObject->Init();
  191. assert(bStatus);
  192. // Let Serial know about Framer.
  193. pclSerialObject->SetCallback(pclMessageObject);
  194. // Open Serial.
  195. bStatus = pclSerialObject->Open();
  196. // If the Open function failed, most likely the device
  197. // we are trying to access does not exist, or it is connected
  198. // to another program
  199. if(!bStatus)
  200. {
  201. printf("Failed to connect to device at USB port %d\n", ucDeviceNumber_);
  202. printf("Press any key to continue.\n"); fflush(stdout);
  203. char st[1024];
  204. fgets(st, sizeof(st), stdin);
  205. return FALSE;
  206. }
  207. // Create message thread.
  208. uiDSIThread = DSIThread_CreateThread(&HRMReceiver::RunMessageThread, this);
  209. assert(uiDSIThread);
  210. printf("USB device initialisation was successful!\n"); fflush(stdout);
  211. return TRUE;
  212. }
  213. ////////////////////////////////////////////////////////////////////////////////
  214. // Close
  215. //
  216. // Close connection to USB stick.
  217. //
  218. ////////////////////////////////////////////////////////////////////////////////
  219. void HRMReceiver::Close()
  220. {
  221. //Wait for test to be done
  222. DSIThread_MutexLock(&mutexTestDone);
  223. bDone = TRUE;
  224. UCHAR ucWaitResult = DSIThread_CondTimedWait(&condTestDone, &mutexTestDone, DSI_THREAD_INFINITE);
  225. assert(ucWaitResult == DSI_THREAD_ENONE);
  226. DSIThread_MutexUnlock(&mutexTestDone);
  227. //Destroy mutex and condition var
  228. DSIThread_MutexDestroy(&mutexTestDone);
  229. DSIThread_CondDestroy(&condTestDone);
  230. //Close all stuff
  231. if(pclSerialObject)
  232. pclSerialObject->Close();
  233. #if defined(DEBUG_FILE)
  234. DSIDebug::Close();
  235. #endif
  236. }
  237. ////////////////////////////////////////////////////////////////////////////////
  238. // Start
  239. //
  240. // Starts the Demo
  241. //
  242. ////////////////////////////////////////////////////////////////////////////////
  243. void HRMReceiver::Start()
  244. {
  245. BOOL bStatus;
  246. // Print out the menu to start
  247. PrintMenu();
  248. // Start ANT channel setup
  249. bStatus = InitANT();
  250. if (bStatus)
  251. {
  252. printf("ANT initialisation was successful!\n"); fflush(stdout);
  253. while(!bMyDone)
  254. {
  255. //printf("Press Q to exit.\n");
  256. UCHAR ucChar;
  257. char st[1024];
  258. fgets(st, sizeof(st), stdin);
  259. sscanf(st, "%c", &ucChar);
  260. switch(ucChar)
  261. {
  262. case 'M':
  263. case 'm':
  264. {
  265. PrintMenu();
  266. break;
  267. }
  268. case 'Q':
  269. case 'q':
  270. {
  271. // Quit
  272. printf("Closing channel...\n");
  273. bBroadcasting = FALSE;
  274. pclMessageObject->CloseChannel(ucAntChannel, MESSAGE_TIMEOUT);
  275. break;
  276. }
  277. case 'r':
  278. case 'R':
  279. {
  280. // Reset the system and start over the test
  281. bStatus = InitANT();
  282. break;
  283. }
  284. case 'c':
  285. case 'C':
  286. {
  287. // Request capabilites.
  288. ANT_MESSAGE_ITEM stResponse;
  289. pclMessageObject->SendRequest(MESG_CAPABILITIES_ID, ucAntChannel, &stResponse, 0);
  290. break;
  291. }
  292. case 'v':
  293. case 'V':
  294. {
  295. // Request version
  296. ANT_MESSAGE_ITEM stResponse;
  297. pclMessageObject->SendRequest(MESG_VERSION_ID, ucAntChannel, &stResponse, 0);
  298. break;
  299. }
  300. case 'S':
  301. case 's':
  302. {
  303. // Request channel status
  304. ANT_MESSAGE_ITEM stResponse;
  305. pclMessageObject->SendRequest(MESG_CHANNEL_STATUS_ID, ucAntChannel, &stResponse, 0);
  306. break;
  307. }
  308. case 'I':
  309. case 'i':
  310. {
  311. // Request channel ID
  312. ANT_MESSAGE_ITEM stResponse;
  313. pclMessageObject->SendRequest(MESG_CHANNEL_ID_ID, ucAntChannel, &stResponse, 0);
  314. break;
  315. }
  316. case 'd':
  317. case 'D':
  318. {
  319. // Toggle display of data messages
  320. bDisplay = !bDisplay;
  321. break;
  322. }
  323. case 'p':
  324. case 'P':
  325. {
  326. // Toggle raw-processed HRM data
  327. bProcessedData = !bProcessedData;
  328. break;
  329. }
  330. case 'u':
  331. case 'U':
  332. {
  333. // Print out information about the device we are connected to
  334. printf("USB Device Description\n");
  335. USHORT usDevicePID;
  336. USHORT usDeviceVID;
  337. UCHAR aucDeviceDescription[USB_MAX_STRLEN];
  338. UCHAR aucDeviceSerial[USB_MAX_STRLEN];
  339. // Retrieve info
  340. if(pclMessageObject->GetDeviceUSBVID(usDeviceVID))
  341. {
  342. printf(" VID: 0x%X\n", usDeviceVID);
  343. }
  344. if(pclMessageObject->GetDeviceUSBPID(usDevicePID))
  345. {
  346. printf(" PID: 0x%X\n", usDevicePID);
  347. }
  348. if(pclMessageObject->GetDeviceUSBInfo(pclSerialObject->GetDeviceNumber(), aucDeviceDescription, aucDeviceSerial, USB_MAX_STRLEN))
  349. {
  350. printf(" Product Description: %s\n", aucDeviceDescription);
  351. printf(" Serial String: %s\n", aucDeviceSerial);
  352. }
  353. break;
  354. }
  355. default:
  356. {
  357. break;
  358. }
  359. }
  360. DSIThread_Sleep(0);
  361. }
  362. }
  363. else
  364. {
  365. printf("ANT initialisation failed!\n"); fflush(stdout);
  366. }
  367. //Disconnecting from module
  368. printf("Disconnecting module...\n");
  369. this->Close();
  370. printf("Closing the Heart Rate Monitor Receiver!\n");
  371. return;
  372. }
  373. ////////////////////////////////////////////////////////////////////////////////
  374. // InitANT
  375. //
  376. // Resets the system and starts the test
  377. //
  378. ////////////////////////////////////////////////////////////////////////////////
  379. BOOL HRMReceiver::InitANT(void)
  380. {
  381. BOOL bStatus; // ANT initialisation status
  382. // Reset system
  383. printf("Resetting module...\n");
  384. bStatus = pclMessageObject->ResetSystem();
  385. DSIThread_Sleep(1000);
  386. // Start the test by setting network key
  387. printf("Setting network key...\n");
  388. UCHAR ucNetKey[8] = USER_NETWORK_KEY;
  389. bStatus &= pclMessageObject->SetNetworkKey(ucNetworkNum, ucNetKey, MESSAGE_TIMEOUT);
  390. return bStatus;
  391. }
  392. ////////////////////////////////////////////////////////////////////////////////
  393. // RunMessageThread
  394. //
  395. // Callback function that is used to create the thread. This is a static
  396. // function.
  397. //
  398. ////////////////////////////////////////////////////////////////////////////////
  399. DSI_THREAD_RETURN HRMReceiver::RunMessageThread(void *pvParameter_)
  400. {
  401. ((HRMReceiver*) pvParameter_)->MessageThread();
  402. return NULL;
  403. }
  404. ////////////////////////////////////////////////////////////////////////////////
  405. // MessageThread
  406. //
  407. // Run message thread
  408. ////////////////////////////////////////////////////////////////////////////////
  409. void HRMReceiver::MessageThread()
  410. {
  411. ANT_MESSAGE stMessage;
  412. USHORT usSize;
  413. bDone = FALSE;
  414. while(!bDone)
  415. {
  416. if(pclMessageObject->WaitForMessage(1000))
  417. {
  418. usSize = pclMessageObject->GetMessage(&stMessage);
  419. if(bDone)
  420. break;
  421. if(usSize == DSI_FRAMER_ERROR)
  422. {
  423. // Get the message to clear the error
  424. usSize = pclMessageObject->GetMessage(&stMessage, MESG_MAX_SIZE_VALUE);
  425. continue;
  426. }
  427. if(usSize != DSI_FRAMER_ERROR && usSize != DSI_FRAMER_TIMEDOUT && usSize != 0)
  428. {
  429. ProcessMessage(stMessage, usSize);
  430. }
  431. }
  432. }
  433. DSIThread_MutexLock(&mutexTestDone);
  434. UCHAR ucCondResult = DSIThread_CondSignal(&condTestDone);
  435. assert(ucCondResult == DSI_THREAD_ENONE);
  436. DSIThread_MutexUnlock(&mutexTestDone);
  437. }
  438. ////////////////////////////////////////////////////////////////////////////////
  439. // ProcessMessage
  440. //
  441. // Process ALL messages that come from ANT, including event messages.
  442. //
  443. // stMessage: Message struct containing message recieved from ANT
  444. // usSize_:
  445. ////////////////////////////////////////////////////////////////////////////////
  446. void HRMReceiver::ProcessMessage(ANT_MESSAGE stMessage, USHORT usSize_)
  447. {
  448. BOOL bStatus;
  449. BOOL bPrintBuffer = FALSE;
  450. UCHAR ucDataOffset = MESSAGE_BUFFER_DATA2_INDEX; // For most data messages
  451. // For decoding device type -- legacy or current
  452. static UCHAR ucDeviceType = INVALID_DEVICE;
  453. switch(stMessage.ucMessageID)
  454. {
  455. //RESPONSE MESG
  456. case MESG_RESPONSE_EVENT_ID:
  457. {
  458. //RESPONSE TYPE
  459. switch(stMessage.aucData[1])
  460. {
  461. case MESG_NETWORK_KEY_ID:
  462. {
  463. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  464. {
  465. printf("Error configuring network key: Code 0%d\n", stMessage.aucData[2]);
  466. break;
  467. }
  468. printf("Network key set.\n");
  469. printf("Assigning channel...\n");
  470. bStatus = pclMessageObject->AssignChannel(ucAntChannel, PARAMETER_RX_NOT_TX, 0, MESSAGE_TIMEOUT);
  471. break;
  472. }
  473. case MESG_ASSIGN_CHANNEL_ID:
  474. {
  475. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  476. {
  477. printf("Error assigning channel: Code 0%d\n", stMessage.aucData[2]);
  478. break;
  479. }
  480. printf("Channel assigned\n");
  481. printf("Setting Channel ID...\n");
  482. bStatus = pclMessageObject->SetChannelID(ucAntChannel, usDeviceNum, USER_DEVICETYPE, ucTransType, MESSAGE_TIMEOUT);
  483. break;
  484. }
  485. case MESG_CHANNEL_ID_ID:
  486. {
  487. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  488. {
  489. printf("Error configuring Channel ID: Code 0%d\n", stMessage.aucData[2]);
  490. break;
  491. }
  492. printf("Channel ID set\n");
  493. printf("Setting Radio Frequency...\n");
  494. bStatus = pclMessageObject->SetChannelRFFrequency(ucAntChannel, USER_RADIOFREQ, MESSAGE_TIMEOUT);
  495. break;
  496. }
  497. case MESG_CHANNEL_RADIO_FREQ_ID:
  498. {
  499. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  500. {
  501. printf("Error configuring Radio Frequency: Code 0%d\n", stMessage.aucData[2]);
  502. break;
  503. }
  504. printf("Radio Frequency set\n");
  505. printf("Setting Message Period...\n");
  506. bStatus = pclMessageObject->SetChannelPeriod(ucAntChannel, usMessagePeriod, MESSAGE_TIMEOUT);
  507. break;
  508. }
  509. case MESG_CHANNEL_MESG_PERIOD_ID:
  510. {
  511. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  512. {
  513. printf("Error assigning Message Period: Code 0%d\n", stMessage.aucData[2]);
  514. break;
  515. }
  516. printf("Message period assigned\n");
  517. printf("Opening channel...\n");
  518. bBroadcasting = TRUE;
  519. bStatus = pclMessageObject->OpenChannel(ucAntChannel, MESSAGE_TIMEOUT);
  520. break;
  521. }
  522. case MESG_OPEN_CHANNEL_ID:
  523. {
  524. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  525. {
  526. printf("Error opening channel: Code 0%d\n", stMessage.aucData[2]);
  527. bBroadcasting = FALSE;
  528. break;
  529. }
  530. printf("Chanel opened\n");
  531. #if defined (ENABLE_EXTENDED_MESSAGES)
  532. printf("Enabling extended messages...\n");
  533. pclMessageObject->RxExtMesgsEnable(TRUE);
  534. #endif
  535. break;
  536. }
  537. case MESG_RX_EXT_MESGS_ENABLE_ID:
  538. {
  539. if(stMessage.aucData[2] == INVALID_MESSAGE)
  540. {
  541. printf("Extended messages not supported in this ANT product\n");
  542. break;
  543. }
  544. else if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  545. {
  546. printf("Error enabling extended messages: Code 0%d\n", stMessage.aucData[2]);
  547. break;
  548. }
  549. printf("Extended messages enabled\n");
  550. break;
  551. }
  552. case MESG_UNASSIGN_CHANNEL_ID:
  553. {
  554. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  555. {
  556. printf("Error unassigning channel: Code 0%d\n", stMessage.aucData[2]);
  557. break;
  558. }
  559. printf("Channel unassigned\n");
  560. printf("Press enter to exit\n");
  561. bMyDone = TRUE;
  562. break;
  563. }
  564. case MESG_CLOSE_CHANNEL_ID:
  565. {
  566. if(stMessage.aucData[2] == CHANNEL_IN_WRONG_STATE)
  567. {
  568. // We get here if we tried to close the channel after the search timeout (slave)
  569. printf("Channel is already closed\n");
  570. printf("Unassigning channel...\n");
  571. bStatus = pclMessageObject->UnAssignChannel(ucAntChannel, MESSAGE_TIMEOUT);
  572. break;
  573. }
  574. else if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  575. {
  576. printf("Error closing channel: Code 0%d\n", stMessage.aucData[2]);
  577. break;
  578. }
  579. // If this message was successful, wait for EVENT_CHANNEL_CLOSED to confirm channel is closed
  580. break;
  581. }
  582. case MESG_REQUEST_ID:
  583. {
  584. if(stMessage.aucData[2] == INVALID_MESSAGE)
  585. {
  586. printf("Requested message not supported in this ANT product\n");
  587. }
  588. break;
  589. }
  590. case MESG_EVENT_ID:
  591. {
  592. switch(stMessage.aucData[2])
  593. {
  594. case EVENT_CHANNEL_CLOSED:
  595. {
  596. printf("Channel Closed\n");
  597. printf("Unassigning channel...\n");
  598. bStatus = pclMessageObject->UnAssignChannel(ucAntChannel, MESSAGE_TIMEOUT);
  599. break;
  600. }
  601. case EVENT_RX_SEARCH_TIMEOUT:
  602. {
  603. printf("Search Timeout\n");
  604. break;
  605. }
  606. case EVENT_RX_FAIL:
  607. {
  608. printf("Rx Fail\n");
  609. break;
  610. }
  611. case EVENT_RX_FAIL_GO_TO_SEARCH:
  612. {
  613. printf("Go to Search\n");
  614. break;
  615. }
  616. case EVENT_CHANNEL_COLLISION:
  617. {
  618. printf("Channel Collision\n");
  619. break;
  620. }
  621. default:
  622. {
  623. printf("Unhandled channel event: 0x%X\n", stMessage.aucData[2]);
  624. break;
  625. }
  626. }
  627. break;
  628. }
  629. default:
  630. {
  631. printf("Unhandled response 0%d to message 0x%X\n", stMessage.aucData[2], stMessage.aucData[1]);
  632. break;
  633. }
  634. }
  635. break;
  636. }
  637. case MESG_STARTUP_MESG_ID:
  638. {
  639. printf("RESET Complete, reason: ");
  640. UCHAR ucReason = stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX];
  641. if(ucReason == RESET_POR)
  642. printf("RESET_POR");
  643. if(ucReason & RESET_SUSPEND)
  644. printf("RESET_SUSPEND ");
  645. if(ucReason & RESET_SYNC)
  646. printf("RESET_SYNC ");
  647. if(ucReason & RESET_CMD)
  648. printf("RESET_CMD ");
  649. if(ucReason & RESET_WDT)
  650. printf("RESET_WDT ");
  651. if(ucReason & RESET_RST)
  652. printf("RESET_RST ");
  653. printf("\n");
  654. break;
  655. }
  656. case MESG_CAPABILITIES_ID:
  657. {
  658. printf("CAPABILITIES:\n");
  659. printf(" Max ANT Channels: %d\n",stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  660. printf(" Max ANT Networks: %d\n",stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX]);
  661. UCHAR ucStandardOptions = stMessage.aucData[MESSAGE_BUFFER_DATA3_INDEX];
  662. UCHAR ucAdvanced = stMessage.aucData[MESSAGE_BUFFER_DATA4_INDEX];
  663. UCHAR ucAdvanced2 = stMessage.aucData[MESSAGE_BUFFER_DATA5_INDEX];
  664. printf("Standard Options:\n");
  665. if( ucStandardOptions & CAPABILITIES_NO_RX_CHANNELS )
  666. printf("CAPABILITIES_NO_RX_CHANNELS\n");
  667. if( ucStandardOptions & CAPABILITIES_NO_TX_CHANNELS )
  668. printf("CAPABILITIES_NO_TX_CHANNELS\n");
  669. if( ucStandardOptions & CAPABILITIES_NO_RX_MESSAGES )
  670. printf("CAPABILITIES_NO_RX_MESSAGES\n");
  671. if( ucStandardOptions & CAPABILITIES_NO_TX_MESSAGES )
  672. printf("CAPABILITIES_NO_TX_MESSAGES\n");
  673. if( ucStandardOptions & CAPABILITIES_NO_ACKD_MESSAGES )
  674. printf("CAPABILITIES_NO_ACKD_MESSAGES\n");
  675. if( ucStandardOptions & CAPABILITIES_NO_BURST_TRANSFER )
  676. printf("CAPABILITIES_NO_BURST_TRANSFER\n");
  677. printf("Advanced Options:\n");
  678. if( ucAdvanced & CAPABILITIES_OVERUN_UNDERRUN )
  679. printf("CAPABILITIES_OVERUN_UNDERRUN\n");
  680. if( ucAdvanced & CAPABILITIES_NETWORK_ENABLED )
  681. printf("CAPABILITIES_NETWORK_ENABLED\n");
  682. if( ucAdvanced & CAPABILITIES_AP1_VERSION_2 )
  683. printf("CAPABILITIES_AP1_VERSION_2\n");
  684. if( ucAdvanced & CAPABILITIES_SERIAL_NUMBER_ENABLED )
  685. printf("CAPABILITIES_SERIAL_NUMBER_ENABLED\n");
  686. if( ucAdvanced & CAPABILITIES_PER_CHANNEL_TX_POWER_ENABLED )
  687. printf("CAPABILITIES_PER_CHANNEL_TX_POWER_ENABLED\n");
  688. if( ucAdvanced & CAPABILITIES_LOW_PRIORITY_SEARCH_ENABLED )
  689. printf("CAPABILITIES_LOW_PRIORITY_SEARCH_ENABLED\n");
  690. if( ucAdvanced & CAPABILITIES_SCRIPT_ENABLED )
  691. printf("CAPABILITIES_SCRIPT_ENABLED\n");
  692. if( ucAdvanced & CAPABILITIES_SEARCH_LIST_ENABLED )
  693. printf("CAPABILITIES_SEARCH_LIST_ENABLED\n");
  694. if(usSize_ > 4)
  695. {
  696. printf("Advanced 2 Options 1:\n");
  697. if( ucAdvanced2 & CAPABILITIES_LED_ENABLED )
  698. printf("CAPABILITIES_LED_ENABLED\n");
  699. if( ucAdvanced2 & CAPABILITIES_EXT_MESSAGE_ENABLED )
  700. printf("CAPABILITIES_EXT_MESSAGE_ENABLED\n");
  701. if( ucAdvanced2 & CAPABILITIES_SCAN_MODE_ENABLED )
  702. printf("CAPABILITIES_SCAN_MODE_ENABLED\n");
  703. if( ucAdvanced2 & CAPABILITIES_RESERVED )
  704. printf("CAPABILITIES_RESERVED\n");
  705. if( ucAdvanced2 & CAPABILITIES_PROX_SEARCH_ENABLED )
  706. printf("CAPABILITIES_PROX_SEARCH_ENABLED\n");
  707. if( ucAdvanced2 & CAPABILITIES_EXT_ASSIGN_ENABLED )
  708. printf("CAPABILITIES_EXT_ASSIGN_ENABLED\n");
  709. if( ucAdvanced2 & CAPABILITIES_FS_ANTFS_ENABLED)
  710. printf("CAPABILITIES_FREE_1\n");
  711. if( ucAdvanced2 & CAPABILITIES_FIT1_ENABLED )
  712. printf("CAPABILITIES_FIT1_ENABLED\n");
  713. }
  714. break;
  715. }
  716. case MESG_CHANNEL_STATUS_ID:
  717. {
  718. printf("Got Status\n");
  719. char astrStatus[][32] = { "STATUS_UNASSIGNED_CHANNEL",
  720. "STATUS_ASSIGNED_CHANNEL",
  721. "STATUS_SEARCHING_CHANNEL",
  722. "STATUS_TRACKING_CHANNEL" };
  723. UCHAR ucStatusByte = stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX] & STATUS_CHANNEL_STATE_MASK; // MUST MASK OFF THE RESERVED BITS
  724. printf("STATUS: %s\n",astrStatus[ucStatusByte]);
  725. break;
  726. }
  727. case MESG_CHANNEL_ID_ID:
  728. {
  729. // Channel ID of the device that we just recieved a message from.
  730. USHORT usDeviceNumber = stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA3_INDEX] << 8);
  731. UCHAR ucDeviceType = stMessage.aucData[MESSAGE_BUFFER_DATA4_INDEX];
  732. UCHAR ucTransmissionType = stMessage.aucData[MESSAGE_BUFFER_DATA5_INDEX];
  733. printf("CHANNEL ID: (%d/%d/%d)\n", usDeviceNumber, ucDeviceType, ucTransmissionType);
  734. break;
  735. }
  736. case MESG_VERSION_ID:
  737. {
  738. printf("VERSION: %s\n", (char*) &stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  739. break;
  740. }
  741. case MESG_ACKNOWLEDGED_DATA_ID:
  742. case MESG_BROADCAST_DATA_ID:
  743. // Burst not supported by ANT+ HRM
  744. {
  745. if (ucDeviceType == INVALID_DEVICE)
  746. {
  747. // Detecting current vs. legacy transmitter, only if not detected yet
  748. static BOOL bOldToggleBit = INVALID_TOGGLE_BIT;
  749. static UCHAR ucToggleAttempts = 0; // The number of attempts made so far
  750. BOOL bToggleBit = stMessage.aucData[ucDataOffset + 0] >> 7;
  751. DetectDevice(ucDeviceType, bOldToggleBit, ucToggleAttempts, bToggleBit);
  752. }
  753. if ((bProcessedData) && (ucDeviceType == INVALID_DEVICE))
  754. {
  755. // The user wants to see processed data, but device type is not detected yet
  756. break;
  757. }
  758. // The flagged and unflagged data messages have the same
  759. // message ID. Therefore, we need to check the size to
  760. // verify if a flag is present at the end of a message.
  761. // To enable flagged messages, must call ANT_RxExtMesgsEnable first.
  762. if(usSize_ > MESG_DATA_SIZE)
  763. {
  764. UCHAR ucFlag = stMessage.aucData[MESSAGE_BUFFER_DATA10_INDEX];
  765. if(bDisplay && ucFlag & ANT_EXT_MESG_BITFIELD_DEVICE_ID)
  766. {
  767. // Channel ID of the device that we just recieved a message from.
  768. USHORT usDeviceNumber = stMessage.aucData[MESSAGE_BUFFER_DATA11_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA12_INDEX] << 8);
  769. UCHAR ucDeviceType = stMessage.aucData[MESSAGE_BUFFER_DATA13_INDEX];
  770. UCHAR ucTransmissionType = stMessage.aucData[MESSAGE_BUFFER_DATA14_INDEX];
  771. printf("Chan ID(%d/%d/%d) - ", usDeviceNumber, ucDeviceType, ucTransmissionType);
  772. }
  773. }
  774. // Display recieved message
  775. bPrintBuffer = TRUE;
  776. ucDataOffset = MESSAGE_BUFFER_DATA2_INDEX; // For most data messages
  777. if(bDisplay)
  778. {
  779. if(stMessage.ucMessageID == MESG_ACKNOWLEDGED_DATA_ID )
  780. printf("Acked Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  781. else if (stMessage.ucMessageID == MESG_BROADCAST_DATA_ID)
  782. printf("Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  783. // Burst is not supported by ANT+ HRM
  784. }
  785. break;
  786. }
  787. case MESG_EXT_BROADCAST_DATA_ID:
  788. case MESG_EXT_ACKNOWLEDGED_DATA_ID:
  789. {
  790. if (ucDeviceType == INVALID_DEVICE)
  791. {
  792. // Detecting current vs. legacy transmitter, only if not detected yet
  793. static BOOL bOldToggleBit = INVALID_TOGGLE_BIT;
  794. static UCHAR ucToggleAttempts = 0; // The number of attempts made so far
  795. BOOL bToggleBit = stMessage.aucData[ucDataOffset + 0] >> 7;
  796. DetectDevice(ucDeviceType, bOldToggleBit, ucToggleAttempts, bToggleBit);
  797. }
  798. if ((bProcessedData) && (ucDeviceType == INVALID_DEVICE))
  799. {
  800. // The user wants to see processed data, but device type is not detected yet
  801. break;
  802. }
  803. // The "extended" part of this message is the 4-byte channel
  804. // id of the device that we recieved this message from. This message
  805. // is only available on the AT3. The AP2 uses flagged versions of the
  806. // data messages as shown above.
  807. // Channel ID of the device that we just recieved a message from.
  808. USHORT usDeviceNumber = stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA3_INDEX] << 8);
  809. UCHAR ucDeviceType = stMessage.aucData[MESSAGE_BUFFER_DATA4_INDEX];
  810. UCHAR ucTransmissionType = stMessage.aucData[MESSAGE_BUFFER_DATA5_INDEX];
  811. bPrintBuffer = TRUE;
  812. ucDataOffset = MESSAGE_BUFFER_DATA6_INDEX; // For most data messages
  813. if(bDisplay)
  814. {
  815. // Display the channel id
  816. printf("Chan ID(%d/%d/%d) ", usDeviceNumber, ucDeviceType, ucTransmissionType );
  817. if(stMessage.ucMessageID == MESG_EXT_ACKNOWLEDGED_DATA_ID)
  818. printf("- Acked Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  819. else if(stMessage.ucMessageID == MESG_EXT_BROADCAST_DATA_ID)
  820. printf("- Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  821. // Burst not supported by ANT+ HRM
  822. }
  823. break;
  824. }
  825. default:
  826. {
  827. break;
  828. }
  829. }
  830. // If we recieved a data message, diplay its contents here.
  831. if(bPrintBuffer)
  832. {
  833. if(bDisplay)
  834. {
  835. // If the user wants to see the decoded information
  836. if (bProcessedData)
  837. {
  838. // HR data, common to all data pages and device types
  839. // Merge the 2 bytes to form the HRM event time
  840. USHORT usEventTime = ((USHORT)stMessage.aucData[ucDataOffset + 5] << 8) +
  841. (USHORT)stMessage.aucData[ucDataOffset + 4];
  842. UCHAR ucHR = stMessage.aucData[ucDataOffset + 7];
  843. UCHAR ucBeatCount = stMessage.aucData[ucDataOffset + 6];
  844. printf("HR: %d , Beat Count: %d , Beat Event Time: %d\n", ucHR, ucBeatCount, usEventTime);
  845. if (ucDeviceType == CURRENT_DEVICE)
  846. {
  847. // Current device => Page numbers are enabled
  848. UCHAR ucPageNum = stMessage.aucData[ucDataOffset + 0] & ~TOGGLE_MASK;
  849. // Page specific data
  850. switch(ucPageNum) // Removing the toggle bitc
  851. {
  852. case PAGE_0:
  853. {
  854. // Contains only common data
  855. break;
  856. }
  857. case PAGE_1:
  858. {
  859. // Decoding cumulative operating time
  860. ULONG ulOperatingTime = ((ULONG)stMessage.aucData[ucDataOffset + 3] << 16) +
  861. ((ULONG)stMessage.aucData[ucDataOffset + 2] << 8) +
  862. ((ULONG)stMessage.aucData[ucDataOffset + 1]);
  863. ulOperatingTime = 2*ulOperatingTime;
  864. printf("Transmitter operating Time: %d seconds\n", ulOperatingTime);
  865. break;
  866. }
  867. case PAGE_2:
  868. {
  869. // Decoding Manufacturer ID & serial number
  870. UCHAR ucManufacturerID = stMessage.aucData[ucDataOffset + 1];
  871. USHORT usSerialNum = ((USHORT)stMessage.aucData[ucDataOffset + 3] << 8) +
  872. (USHORT)stMessage.aucData[ucDataOffset + 2];
  873. printf("Transmitter manufacturer ID : %d , ", ucManufacturerID);
  874. printf("Ser. #: %d\n", usSerialNum);
  875. break;
  876. }
  877. case PAGE_3:
  878. {
  879. // Decoding Hardware, software version and model number
  880. UCHAR ucHWVer = stMessage.aucData[ucDataOffset + 1];
  881. UCHAR ucSWVer = stMessage.aucData[ucDataOffset + 2];
  882. UCHAR ucModelNum = stMessage.aucData[ucDataOffset + 3];
  883. printf("Transmitter HW ver: %d , ", ucHWVer);
  884. printf("SF ver: %d , ", ucSWVer);
  885. printf("Model #: %d\n", ucModelNum);
  886. break;
  887. }
  888. case PAGE_4:
  889. {
  890. // Decoding R-R Interval Measurements
  891. static UCHAR ucPreviousBeatCount;
  892. USHORT usPreviousEventTime = ((USHORT)stMessage.aucData[ucDataOffset + 3] << 8) +
  893. (USHORT)stMessage.aucData[ucDataOffset + 2];
  894. if (ucBeatCount - ucPreviousBeatCount == 1)// Ensure that there is only one beat between time intervals
  895. {
  896. USHORT usR_R_Interval = usEventTime - usPreviousEventTime; // Subracting the event times gives the R-R interval
  897. // Converting the timebase from 1/1024 of a second to milliseconds
  898. USHORT usR_R_Interval_ms = (((ULONG) usR_R_Interval) * (ULONG) 1000) / (ULONG) 1024;
  899. printf("R-R Interval: %d ms\n", usR_R_Interval_ms);
  900. }
  901. ucPreviousBeatCount = ucBeatCount;
  902. break;
  903. }
  904. default:
  905. {
  906. // This should never be the case for current ANT+ HRM transmitter
  907. // More pages may be implemented in future
  908. printf("Unable to recognise the page number. Please check for an updated version of this app.\n");
  909. }
  910. }
  911. }
  912. }
  913. // If the user wants to see the raw bytes received
  914. else
  915. {
  916. printf("[%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x]\n",
  917. stMessage.aucData[ucDataOffset + 0],
  918. stMessage.aucData[ucDataOffset + 1],
  919. stMessage.aucData[ucDataOffset + 2],
  920. stMessage.aucData[ucDataOffset + 3],
  921. stMessage.aucData[ucDataOffset + 4],
  922. stMessage.aucData[ucDataOffset + 5],
  923. stMessage.aucData[ucDataOffset + 6],
  924. stMessage.aucData[ucDataOffset + 7]);
  925. }
  926. }
  927. else
  928. {
  929. static int iIndex = 0;
  930. static char ac[] = {'|','/','-','\\'};
  931. printf("Rx: %c\r",ac[iIndex++]); fflush(stdout);
  932. iIndex &= 3;
  933. }
  934. }
  935. return;
  936. }
  937. ////////////////////////////////////////////////////////////////////////////////
  938. // PrintMenu
  939. //
  940. // Start the Test program.
  941. //
  942. ////////////////////////////////////////////////////////////////////////////////
  943. void HRMReceiver::PrintMenu()
  944. {
  945. // Printout options
  946. printf("\n");
  947. printf("M - Print this menu\n");
  948. printf("R - Reset\n");
  949. printf("C - Request Capabilites\n");
  950. printf("V - Request Version\n");
  951. printf("I - Request Channel ID\n");
  952. printf("S - Request Status\n");
  953. printf("U - Request USB Descriptor\n");
  954. printf("D - Toggle Display\n");
  955. printf("P - Toggle Processed-Raw Data\n");
  956. printf("Q - Quit\n");
  957. printf("\n");
  958. fflush(stdout);
  959. }
  960. ////////////////////////////////////////////////////////////////////////////////
  961. // DetectDevice
  962. //
  963. // Helper member for detecting the device (type) -- legacy or current.
  964. //
  965. ////////////////////////////////////////////////////////////////////////////////
  966. void HRMReceiver::DetectDevice(UCHAR &ucDeviceType_, BOOL &bOldToggleBit_, UCHAR &ucToggleAttempts_, BOOL bToggleBit)
  967. {
  968. if (ucToggleAttempts_ == 0)
  969. {
  970. printf("Detecting transmitter device type...\n");
  971. }
  972. if (ucToggleAttempts_ < MAX_TOGGLE_ATTEMPTS)
  973. {
  974. // Try to see if the ms bit of the ms byte toggles this time
  975. // Check MAX_TOGGLE_ATTEMPTS number of times
  976. if ((bToggleBit != bOldToggleBit_) && (bOldToggleBit_ != INVALID_TOGGLE_BIT))
  977. {
  978. ucDeviceType_ = CURRENT_DEVICE; // Toggle Bit toggled => Current device
  979. printf("Current Device detected\n");
  980. }
  981. else
  982. {
  983. bOldToggleBit_ = bToggleBit;
  984. ucToggleAttempts_++;
  985. }
  986. }
  987. if ((ucToggleAttempts_ >= MAX_TOGGLE_ATTEMPTS) && (ucDeviceType_ == INVALID_DEVICE))
  988. {
  989. // Toggle Bit didn't toggle for max # of attempts => Legacy device
  990. ucDeviceType_ = LEGACY_DEVICE;
  991. printf("Legacy Device detected\n");
  992. }
  993. }