PowerRecordingExample.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  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 in compliance
  4. with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2014
  6. All rights reserved.
  7. */
  8. #include "PowerRecordingExample.h"
  9. #include "types.h"
  10. #include "dsi_framer_ant.hpp"
  11. #include "dsi_thread.h"
  12. #include "dsi_serial_generic.hpp"
  13. #include "dsi_debug.hpp"
  14. extern "C" {
  15. #include "PowerDecoder.h"
  16. }
  17. #include <stdio.h>
  18. #include <assert.h>
  19. #include <string.h>
  20. #include <time.h>
  21. #define ENABLE_EXTENDED_MESSAGES
  22. #define USER_BAUDRATE (50000) // For AT3/AP2, use 57600
  23. #define USER_RADIOFREQ (57)
  24. #define USER_ANTCHANNEL (0)
  25. #define USER_DEVICETYPE (11)
  26. #define USER_TRANSTYPE (0)
  27. #define USER_NETWORK_KEY {0xB9, 0xA5, 0x21, 0xFB, 0xBD, 0x72, 0xC3, 0x45} //ANT+ Network Key
  28. #define USER_NETWORK_NUM (0) // The network key is assigned to this network number
  29. #define MESSAGE_TIMEOUT (1000)
  30. // Indexes into message recieved from ANT
  31. #define MESSAGE_BUFFER_DATA1_INDEX ((UCHAR) 0)
  32. #define MESSAGE_BUFFER_DATA2_INDEX ((UCHAR) 1)
  33. #define MESSAGE_BUFFER_DATA3_INDEX ((UCHAR) 2)
  34. #define MESSAGE_BUFFER_DATA4_INDEX ((UCHAR) 3)
  35. #define MESSAGE_BUFFER_DATA5_INDEX ((UCHAR) 4)
  36. #define MESSAGE_BUFFER_DATA6_INDEX ((UCHAR) 5)
  37. #define MESSAGE_BUFFER_DATA7_INDEX ((UCHAR) 6)
  38. #define MESSAGE_BUFFER_DATA8_INDEX ((UCHAR) 7)
  39. #define MESSAGE_BUFFER_DATA9_INDEX ((UCHAR) 8)
  40. #define MESSAGE_BUFFER_DATA10_INDEX ((UCHAR) 9)
  41. #define MESSAGE_BUFFER_DATA11_INDEX ((UCHAR) 10)
  42. #define MESSAGE_BUFFER_DATA12_INDEX ((UCHAR) 11)
  43. #define MESSAGE_BUFFER_DATA13_INDEX ((UCHAR) 12)
  44. #define MESSAGE_BUFFER_DATA14_INDEX ((UCHAR) 13)
  45. #define MESSAGE_BUFFER_DATA15_INDEX ((UCHAR) 14)
  46. #define MESSAGE_BUFFER_DATA16_INDEX ((UCHAR) 15)
  47. FILE *fp1; // output file
  48. ////////////////////////////////////////////////////////////////////////////////
  49. // main
  50. //
  51. // Usage:
  52. //
  53. // c:\PowerRecordingExample.exe [device_no]
  54. //
  55. // ... where
  56. //
  57. // device_no: USB Device port, starting at 0
  58. //
  59. // ... example
  60. //
  61. // c:\PowerRecordingExample.exe 0 0 1.0 0
  62. //
  63. // Comment to USB port 0, wild card device number, record at 1.0s intervals, from an event based power meter
  64. //
  65. // If the optional arguments are not supplied, the user will
  66. // be prompted to enter them after the program starts.
  67. //
  68. ////////////////////////////////////////////////////////////////////////////////
  69. int main(int argc, char **argv)
  70. {
  71. Example* pclExample = new Example();
  72. UCHAR ucDeviceNumber = 0xFF;
  73. UCHAR ucChannelType = CHANNEL_TYPE_SLAVE;
  74. USHORT usAntDeviceNumber = 0xFFFF;
  75. DOUBLE dRecordInterval = 0;
  76. DOUBLE dTimeBase = 0xFF;
  77. UCHAR ucPowerMeterType = 254;
  78. DOUBLE dReSyncInterval = 0;
  79. if (argc == 6)
  80. {
  81. ucDeviceNumber = (UCHAR)atoi(argv[1]);
  82. usAntDeviceNumber = (UCHAR)atoi(argv[2]);
  83. dRecordInterval = (DOUBLE)atoi(argv[3]);
  84. dTimeBase = (DOUBLE)atoi(argv[4]);
  85. dReSyncInterval = (DOUBLE)atoi(argv[4]);
  86. }
  87. if (argc > 6)
  88. {
  89. ucDeviceNumber = (UCHAR)atoi(argv[1]);
  90. usAntDeviceNumber = (UCHAR)atoi(argv[2]);
  91. dRecordInterval = (DOUBLE)atoi(argv[3]);
  92. dTimeBase = (DOUBLE)atoi(argv[4]);
  93. ucPowerMeterType = (UCHAR)atoi(argv[5]);
  94. dReSyncInterval = (DOUBLE)atoi(argv[4]);
  95. }
  96. if (pclExample->Init(ucDeviceNumber, ucChannelType, usAntDeviceNumber, dRecordInterval, dTimeBase, ucPowerMeterType, dReSyncInterval))
  97. pclExample->Start();
  98. else
  99. delete pclExample;
  100. return 0;
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////
  103. // Example
  104. //
  105. // Constructor, intializes Example class
  106. //
  107. ////////////////////////////////////////////////////////////////////////////////
  108. Example::Example()
  109. {
  110. ucChannelType = CHANNEL_TYPE_INVALID;
  111. pclSerialObject = (DSISerialGeneric*)NULL;
  112. pclMessageObject = (DSIFramerANT*)NULL;
  113. uiDSIThread = (DSI_THREAD_ID)NULL;
  114. bMyDone = FALSE;
  115. bDone = FALSE;
  116. bDisplay = TRUE;
  117. bBroadcasting = FALSE;
  118. bPowerDecoderInitialized = FALSE;
  119. ulNewEventTime = 0;
  120. usPreviousEventTime = 0;
  121. previousRxTime = time(NULL);
  122. ucPowerOnlyUpdateEventCount = 0;
  123. dRxTimeTePs = 0;
  124. memset(aucTransmitBuffer, 0, ANT_STANDARD_DATA_PAYLOAD_SIZE);
  125. }
  126. ////////////////////////////////////////////////////////////////////////////////
  127. // ~Example
  128. //
  129. // Destructor, clean up and free memory
  130. //
  131. ////////////////////////////////////////////////////////////////////////////////
  132. Example::~Example()
  133. {
  134. if (pclMessageObject)
  135. delete pclMessageObject;
  136. if (pclSerialObject)
  137. delete pclSerialObject;
  138. }
  139. ////////////////////////////////////////////////////////////////////////////////
  140. // Init
  141. //
  142. // Initialize the Example and ANT Library.
  143. //
  144. // ucDeviceNumber_: USB Device Number (0 for first USB stick plugged and so on)
  145. // If not specified on command line, 0xFF is passed in as invalid.
  146. // ucChannelType_: ANT Channel Type. 0 = Master, 1 = Slave
  147. // If not specified, 2 is passed in as invalid.
  148. // usAntDeviceNumber_: The device number of the channel
  149. //
  150. // dRecordInterval_: The time in seconds between records generated by the Power Decoder
  151. //
  152. // dTimeBase_: The time in seconds at which power/torque pages are updated. Set to 0 if the power meter is event based.
  153. //
  154. // ucPowerMeterType_: The type of power meter. Knowing this ahead of time helps deal with a corner case
  155. // where power only messages may be decoded before torque pages at initialization.
  156. //
  157. // dResyncInterval_: The maximum time allowed for a dropout (no power messages to be received) before resetting the decoder's internal values.
  158. //
  159. ////////////////////////////////////////////////////////////////////////////////
  160. BOOL Example::Init(UCHAR ucDeviceNumber_, UCHAR ucChannelType_, USHORT usAntDeviceNumber_, DOUBLE dRecordInterval_, DOUBLE dTimeBase_, UCHAR ucPowerMeterType_, DOUBLE dReSyncInterval_)
  161. {
  162. BOOL bStatus;
  163. // Initialize condition var and mutex
  164. UCHAR ucCondInit = DSIThread_CondInit(&condTestDone);
  165. assert(ucCondInit == DSI_THREAD_ENONE);
  166. UCHAR ucMutexInit = DSIThread_MutexInit(&mutexTestDone);
  167. assert(ucMutexInit == DSI_THREAD_ENONE);
  168. #if defined(DEBUG_FILE)
  169. // Enable logging
  170. DSIDebug::Init();
  171. DSIDebug::SetDebug(TRUE);
  172. #endif
  173. // Create Serial object.
  174. pclSerialObject = new DSISerialGeneric();
  175. assert(pclSerialObject);
  176. // NOTE: Will fail if the module is not available.
  177. // If no device number was specified on the command line,
  178. // prompt the user for input.
  179. if (ucDeviceNumber_ == 255)
  180. {
  181. printf("USB Device number?\n"); fflush(stdout);
  182. char st[1024];
  183. fgets(st, sizeof(st), stdin);
  184. sscanf(st, "%u", &ucDeviceNumber_);
  185. // Set USB device number to 0 by default
  186. if (ucDeviceNumber_ == 255)
  187. ucDeviceNumber_ = 0;
  188. }
  189. if (usAntDeviceNumber_ == 65535)
  190. {
  191. printf("Power Meter Device Number? (0 to wildcard)\n"); fflush(stdout);
  192. char st[1024];
  193. fgets(st, sizeof(st), stdin);
  194. sscanf(st, "%u", &usAntDeviceNumber_);
  195. // Set ANT Device Number to 0 by default
  196. if (usAntDeviceNumber_ == 65535)
  197. usAntDeviceNumber_ = 0;
  198. }
  199. if (dRecordInterval_ > -0.001 && dRecordInterval_ < 0.001)
  200. {
  201. printf("Power Record Interval? (1.0s standard)\n"); fflush(stdout);
  202. char st[1024];
  203. fgets(st, sizeof(st), stdin);
  204. dRecordInterval_ = atof(st);
  205. // Set Record Interval to 1 second by default
  206. if (dRecordInterval_ > -0.001 && dRecordInterval_ < 0.001)
  207. dRecordInterval_ = 1;
  208. }
  209. if (dTimeBase_ >= (255-0.001))
  210. {
  211. printf("Power Meter Timebase? (0.0s for Event Based Power Meters)\n"); fflush(stdout);
  212. char st[1024];
  213. fgets(st, sizeof(st), stdin);
  214. dTimeBase_ = atof(st);
  215. // Set timebase to 0 by default
  216. if (dTimeBase_ >= (255 - 0.001))
  217. dTimeBase_ = 0;
  218. }
  219. // Prior knowledge of the power meter type prevents a corner case where the decoder may begin decoding power only messages before only decoding torque pages
  220. if (ucPowerMeterType_ == 254)
  221. {
  222. printf("Power Meter Type? (16-Power Only,17-Wheel Torque,18-CrankTorque,32-CTF,255-Unknown)\n"); fflush(stdout);
  223. char st[1024];
  224. fgets(st, sizeof(st), stdin);
  225. sscanf(st, "%u", &ucPowerMeterType_);
  226. // Set power meter type to unknown by default
  227. if (ucPowerMeterType_ == 254)
  228. ucPowerMeterType_ = 255;
  229. }
  230. if (dReSyncInterval_ > -0.001 && dReSyncInterval_ < 0.001)
  231. {
  232. printf("Re-Sync Interval? (10s default) \n"); fflush(stdout);
  233. char st[1024];
  234. fgets(st, sizeof(st), stdin);
  235. dReSyncInterval_ = atof(st);
  236. // Set Re-Sync Interval to 10 seconds by default
  237. if (dReSyncInterval_ > -0.001 && dReSyncInterval_ < 0.001)
  238. dReSyncInterval_ = 10;
  239. }
  240. ucChannelType = ucChannelType_;
  241. usAntDeviceNumber = usAntDeviceNumber_;
  242. dRecordInterval = dRecordInterval_;
  243. dTimeBase = dTimeBase_;
  244. dReSyncInterval = dReSyncInterval_;
  245. SetPowerMeterType(ucPowerMeterType_);
  246. // Initialize Serial object.
  247. // The device number depends on how many USB sticks have been
  248. // plugged into the PC. The first USB stick plugged will be 0
  249. // the next 1 and so on.
  250. //
  251. // The Baud Rate depends on the ANT solution being used. AP1
  252. // is 50000, all others are 57600
  253. bStatus = pclSerialObject->Init(USER_BAUDRATE, ucDeviceNumber_);
  254. assert(bStatus);
  255. // Create Framer object.
  256. pclMessageObject = new DSIFramerANT(pclSerialObject);
  257. assert(pclMessageObject);
  258. // Initialize Framer object.
  259. bStatus = pclMessageObject->Init();
  260. assert(bStatus);
  261. // Let Serial know about Framer.
  262. pclSerialObject->SetCallback(pclMessageObject);
  263. // Open Serial.
  264. bStatus = pclSerialObject->Open();
  265. // If the Open function failed, most likely the device
  266. // we are trying to access does not exist, or it is connected
  267. // to another program
  268. if (!bStatus)
  269. {
  270. printf("Failed to connect to device at USB port %d\n", ucDeviceNumber_);
  271. return FALSE;
  272. }
  273. // Create message thread.
  274. uiDSIThread = DSIThread_CreateThread(&Example::RunMessageThread, this);
  275. assert(uiDSIThread);
  276. printf("Initialization was successful!\n"); fflush(stdout);
  277. fopen_s(&fp1, "Output.csv", "w");
  278. fprintf(fp1, "Record Time, Rotations, Energy, Avg Cadence, Avg Power\n");
  279. return TRUE;
  280. }
  281. ////////////////////////////////////////////////////////////////////////////////
  282. // Close
  283. //
  284. // Close connection to USB stick.
  285. //
  286. ////////////////////////////////////////////////////////////////////////////////
  287. void Example::Close()
  288. {
  289. //Wait for test to be done
  290. DSIThread_MutexLock(&mutexTestDone);
  291. bDone = TRUE;
  292. UCHAR ucWaitResult = DSIThread_CondTimedWait(&condTestDone, &mutexTestDone, DSI_THREAD_INFINITE);
  293. assert(ucWaitResult == DSI_THREAD_ENONE);
  294. DSIThread_MutexUnlock(&mutexTestDone);
  295. //Destroy mutex and condition var
  296. DSIThread_MutexDestroy(&mutexTestDone);
  297. DSIThread_CondDestroy(&condTestDone);
  298. //Close all stuff
  299. if (pclSerialObject)
  300. pclSerialObject->Close();
  301. #if defined(DEBUG_FILE)
  302. DSIDebug::Close();
  303. #endif
  304. }
  305. ////////////////////////////////////////////////////////////////////////////////
  306. // Start
  307. //
  308. // Starts the Example
  309. //
  310. ////////////////////////////////////////////////////////////////////////////////
  311. void Example::Start()
  312. {
  313. BOOL bStatus;
  314. // Print out the menu to start
  315. PrintMenu();
  316. // Start ANT channel setup
  317. bStatus = InitANT();
  318. while (!bMyDone)
  319. {
  320. UCHAR ucChar;
  321. char st[1024];
  322. fgets(st, sizeof(st), stdin);
  323. sscanf(st, "%c", &ucChar);
  324. switch (ucChar)
  325. {
  326. case 'M':
  327. case 'm':
  328. {
  329. // Printout options
  330. PrintMenu();
  331. break;
  332. }
  333. case 'Q':
  334. case 'q':
  335. {
  336. // Quit
  337. fclose(fp1);
  338. printf("Closing channel...\n");
  339. bBroadcasting = FALSE;
  340. pclMessageObject->CloseChannel(USER_ANTCHANNEL, MESSAGE_TIMEOUT);
  341. break;
  342. }
  343. case 'r':
  344. case 'R':
  345. {
  346. // Reset the system and start over the test
  347. bStatus = InitANT();
  348. break;
  349. }
  350. case 'c':
  351. case 'C':
  352. {
  353. // Request capabilites.
  354. ANT_MESSAGE_ITEM stResponse;
  355. pclMessageObject->SendRequest(MESG_CAPABILITIES_ID, USER_ANTCHANNEL, &stResponse, 0);
  356. break;
  357. }
  358. case 'v':
  359. case 'V':
  360. {
  361. // Request version
  362. ANT_MESSAGE_ITEM stResponse;
  363. pclMessageObject->SendRequest(MESG_VERSION_ID, USER_ANTCHANNEL, &stResponse, 0);
  364. break;
  365. }
  366. case 'S':
  367. case 's':
  368. {
  369. // Request channel status
  370. ANT_MESSAGE_ITEM stResponse;
  371. pclMessageObject->SendRequest(MESG_CHANNEL_STATUS_ID, USER_ANTCHANNEL, &stResponse, 0);
  372. break;
  373. }
  374. case 'I':
  375. case 'i':
  376. {
  377. // Request channel ID
  378. ANT_MESSAGE_ITEM stResponse;
  379. pclMessageObject->SendRequest(MESG_CHANNEL_ID_ID, USER_ANTCHANNEL, &stResponse, 0);
  380. break;
  381. }
  382. case 'd':
  383. case 'D':
  384. {
  385. // Toggle display of data messages
  386. bDisplay = !bDisplay;
  387. break;
  388. }
  389. case 'u':
  390. case 'U':
  391. {
  392. // Print out information about the device we are connected to
  393. printf("USB Device Description\n");
  394. USHORT usDevicePID;
  395. USHORT usDeviceVID;
  396. UCHAR aucDeviceDescription[USB_MAX_STRLEN];
  397. UCHAR aucDeviceSerial[USB_MAX_STRLEN];
  398. // Retrieve info
  399. if (pclMessageObject->GetDeviceUSBVID(usDeviceVID))
  400. {
  401. printf(" VID: 0x%X\n", usDeviceVID);
  402. }
  403. if (pclMessageObject->GetDeviceUSBPID(usDevicePID))
  404. {
  405. printf(" PID: 0x%X\n", usDevicePID);
  406. }
  407. if (pclMessageObject->GetDeviceUSBInfo(pclSerialObject->GetDeviceNumber(), aucDeviceDescription, aucDeviceSerial, USB_MAX_STRLEN))
  408. {
  409. printf(" Product Description: %s\n", aucDeviceDescription);
  410. printf(" Serial String: %s\n", aucDeviceSerial);
  411. }
  412. break;
  413. }
  414. default:
  415. {
  416. break;
  417. }
  418. }
  419. DSIThread_Sleep(0);
  420. }
  421. //Disconnecting from module
  422. printf("Disconnecting module...\n");
  423. this->Close();
  424. printf("Example has completed successfully!\n");
  425. return;
  426. }
  427. ////////////////////////////////////////////////////////////////////////////////
  428. // InitANT
  429. //
  430. // Resets the system and starts the test
  431. //
  432. ////////////////////////////////////////////////////////////////////////////////
  433. BOOL Example::InitANT(void)
  434. {
  435. BOOL bStatus;
  436. // Reset system
  437. printf("Resetting module...\n");
  438. bStatus = pclMessageObject->ResetSystem();
  439. DSIThread_Sleep(1000);
  440. // Start the test by setting network key
  441. printf("Setting network key...\n");
  442. UCHAR ucNetKey[8] = USER_NETWORK_KEY;
  443. bStatus = pclMessageObject->SetNetworkKey(USER_NETWORK_NUM, ucNetKey, MESSAGE_TIMEOUT);
  444. return bStatus;
  445. }
  446. ////////////////////////////////////////////////////////////////////////////////
  447. // RunMessageThread
  448. //
  449. // Callback function that is used to create the thread. This is a static
  450. // function.
  451. //
  452. ////////////////////////////////////////////////////////////////////////////////
  453. DSI_THREAD_RETURN Example::RunMessageThread(void *pvParameter_)
  454. {
  455. ((Example*)pvParameter_)->MessageThread();
  456. return NULL;
  457. }
  458. ////////////////////////////////////////////////////////////////////////////////
  459. // MessageThread
  460. //
  461. // Run message thread
  462. ////////////////////////////////////////////////////////////////////////////////
  463. void Example::MessageThread()
  464. {
  465. ANT_MESSAGE stMessage;
  466. USHORT usSize;
  467. bDone = FALSE;
  468. while (!bDone)
  469. {
  470. if (pclMessageObject->WaitForMessage(1000))
  471. {
  472. usSize = pclMessageObject->GetMessage(&stMessage);
  473. if (bDone)
  474. break;
  475. if (usSize == DSI_FRAMER_ERROR)
  476. {
  477. // Get the message to clear the error
  478. usSize = pclMessageObject->GetMessage(&stMessage, MESG_MAX_SIZE_VALUE);
  479. continue;
  480. }
  481. if (usSize != DSI_FRAMER_ERROR && usSize != DSI_FRAMER_TIMEDOUT && usSize != 0)
  482. {
  483. ProcessMessage(stMessage, usSize);
  484. }
  485. }
  486. }
  487. DSIThread_MutexLock(&mutexTestDone);
  488. UCHAR ucCondResult = DSIThread_CondSignal(&condTestDone);
  489. assert(ucCondResult == DSI_THREAD_ENONE);
  490. DSIThread_MutexUnlock(&mutexTestDone);
  491. }
  492. ////////////////////////////////////////////////////////////////////////////////
  493. // ProcessMessage
  494. //
  495. // Process ALL messages that come from ANT, including event messages.
  496. //
  497. // stMessage: Message struct containing message recieved from ANT
  498. // usSize_:
  499. ////////////////////////////////////////////////////////////////////////////////
  500. void Example::ProcessMessage(ANT_MESSAGE stMessage, USHORT usSize_)
  501. {
  502. BOOL bStatus;
  503. BOOL bPrintBuffer = FALSE;
  504. UCHAR ucDataOffset = MESSAGE_BUFFER_DATA2_INDEX; // For most data messages
  505. switch (stMessage.ucMessageID)
  506. {
  507. //RESPONSE MESG
  508. case MESG_RESPONSE_EVENT_ID:
  509. {
  510. //RESPONSE TYPE
  511. switch (stMessage.aucData[1])
  512. {
  513. case MESG_NETWORK_KEY_ID:
  514. {
  515. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  516. {
  517. printf("Error configuring network key: Code 0%d\n", stMessage.aucData[2]);
  518. break;
  519. }
  520. printf("Network key set.\n");
  521. printf("Assigning channel...\n");
  522. if (ucChannelType == CHANNEL_TYPE_MASTER)
  523. {
  524. bStatus = pclMessageObject->AssignChannel(USER_ANTCHANNEL, PARAMETER_TX_NOT_RX, 0, MESSAGE_TIMEOUT);
  525. }
  526. else if (ucChannelType == CHANNEL_TYPE_SLAVE)
  527. {
  528. bStatus = pclMessageObject->AssignChannel(USER_ANTCHANNEL, 0, 0, MESSAGE_TIMEOUT);
  529. }
  530. break;
  531. }
  532. case MESG_ASSIGN_CHANNEL_ID:
  533. {
  534. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  535. {
  536. printf("Error assigning channel: Code 0%d\n", stMessage.aucData[2]);
  537. break;
  538. }
  539. printf("Channel assigned\n");
  540. printf("Setting Channel ID...\n");
  541. bStatus = pclMessageObject->SetChannelID(USER_ANTCHANNEL, usAntDeviceNumber, USER_DEVICETYPE, USER_TRANSTYPE, MESSAGE_TIMEOUT);
  542. break;
  543. }
  544. case MESG_CHANNEL_ID_ID:
  545. {
  546. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  547. {
  548. printf("Error configuring Channel ID: Code 0%d\n", stMessage.aucData[2]);
  549. break;
  550. }
  551. printf("Channel ID set\n");
  552. printf("Setting Radio Frequency...\n");
  553. bStatus = pclMessageObject->SetChannelRFFrequency(USER_ANTCHANNEL, USER_RADIOFREQ, MESSAGE_TIMEOUT);
  554. break;
  555. }
  556. case MESG_CHANNEL_RADIO_FREQ_ID:
  557. {
  558. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  559. {
  560. printf("Error configuring Radio Frequency: Code 0%d\n", stMessage.aucData[2]);
  561. break;
  562. }
  563. printf("Radio Frequency set\n");
  564. printf("Setting Channel Period...\n");
  565. bStatus = pclMessageObject->SetChannelPeriod(USER_ANTCHANNEL, 8182, MESSAGE_TIMEOUT);
  566. break;
  567. }
  568. case MESG_CHANNEL_MESG_PERIOD_ID:
  569. {
  570. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  571. {
  572. printf("Error configuring Channel Period: Code 0%d\n", stMessage.aucData[2]);
  573. break;
  574. }
  575. printf("Channel Period set\n");
  576. printf("Opening channel...\n");
  577. bBroadcasting = TRUE;
  578. bStatus = pclMessageObject->OpenChannel(USER_ANTCHANNEL, MESSAGE_TIMEOUT);
  579. break;
  580. }
  581. case MESG_OPEN_CHANNEL_ID:
  582. {
  583. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  584. {
  585. printf("Error opening channel: Code 0%d\n", stMessage.aucData[2]);
  586. bBroadcasting = FALSE;
  587. break;
  588. }
  589. printf("Channel opened\n");
  590. // We register the power record receiver and initialize the bike power decoders after the channel has opened
  591. InitPowerDecoder(dRecordInterval, dTimeBase, dReSyncInterval, RecordReceiver);
  592. bPowerDecoderInitialized = TRUE;
  593. printf("Power record decode library initialized\n");
  594. #if defined (ENABLE_EXTENDED_MESSAGES)
  595. printf("Enabling extended messages...\n");
  596. pclMessageObject->SetLibConfig(ANT_LIB_CONFIG_MESG_OUT_INC_TIME_STAMP | ANT_LIB_CONFIG_MESG_OUT_INC_DEVICE_ID, MESSAGE_TIMEOUT);
  597. #endif
  598. break;
  599. }
  600. case MESG_ANTLIB_CONFIG_ID:
  601. {
  602. if (stMessage.aucData[2] == INVALID_MESSAGE)
  603. {
  604. printf("Extended messages not supported in this ANT product\n");
  605. break;
  606. }
  607. else if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  608. {
  609. printf("Error enabling extended messages: Code 0%d\n", stMessage.aucData[2]);
  610. break;
  611. }
  612. printf("Extended messages enabled\n");
  613. break;
  614. }
  615. case MESG_UNASSIGN_CHANNEL_ID:
  616. {
  617. if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  618. {
  619. printf("Error unassigning channel: Code 0%d\n", stMessage.aucData[2]);
  620. break;
  621. }
  622. printf("Channel unassigned\n");
  623. printf("Press enter to exit\n");
  624. bMyDone = TRUE;
  625. break;
  626. }
  627. case MESG_CLOSE_CHANNEL_ID:
  628. {
  629. if (stMessage.aucData[2] == CHANNEL_IN_WRONG_STATE)
  630. {
  631. // We get here if we tried to close the channel after the search timeout (slave)
  632. printf("Channel is already closed\n");
  633. printf("Unassigning channel...\n");
  634. bStatus = pclMessageObject->UnAssignChannel(USER_ANTCHANNEL, MESSAGE_TIMEOUT);
  635. break;
  636. }
  637. else if (stMessage.aucData[2] != RESPONSE_NO_ERROR)
  638. {
  639. printf("Error closing channel: Code 0%d\n", stMessage.aucData[2]);
  640. break;
  641. }
  642. // If this message was successful, wait for EVENT_CHANNEL_CLOSED to confirm channel is closed
  643. break;
  644. }
  645. case MESG_REQUEST_ID:
  646. {
  647. if (stMessage.aucData[2] == INVALID_MESSAGE)
  648. {
  649. printf("Requested message not supported in this ANT product\n");
  650. }
  651. break;
  652. }
  653. case MESG_EVENT_ID:
  654. {
  655. switch (stMessage.aucData[2])
  656. {
  657. case EVENT_CHANNEL_CLOSED:
  658. {
  659. printf("Channel Closed\n");
  660. printf("Unassigning channel...\n");
  661. bStatus = pclMessageObject->UnAssignChannel(USER_ANTCHANNEL, MESSAGE_TIMEOUT);
  662. break;
  663. }
  664. case EVENT_TX:
  665. {
  666. // This event indicates that a message has just been
  667. // sent over the air. We take advantage of this event to set
  668. // up the data for the next message period.
  669. static UCHAR ucIncrement = 0; // Increment the first byte of the buffer
  670. aucTransmitBuffer[0] = ucIncrement++;
  671. // Broadcast data will be sent over the air on
  672. // the next message period.
  673. if (bBroadcasting)
  674. {
  675. pclMessageObject->SendBroadcastData(USER_ANTCHANNEL, aucTransmitBuffer);
  676. // Echo what the data will be over the air on the next message period.
  677. if (bDisplay)
  678. {
  679. printf("Tx:(%d): [%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x]\n",
  680. USER_ANTCHANNEL,
  681. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX],
  682. aucTransmitBuffer[MESSAGE_BUFFER_DATA2_INDEX],
  683. aucTransmitBuffer[MESSAGE_BUFFER_DATA3_INDEX],
  684. aucTransmitBuffer[MESSAGE_BUFFER_DATA4_INDEX],
  685. aucTransmitBuffer[MESSAGE_BUFFER_DATA5_INDEX],
  686. aucTransmitBuffer[MESSAGE_BUFFER_DATA6_INDEX],
  687. aucTransmitBuffer[MESSAGE_BUFFER_DATA7_INDEX],
  688. aucTransmitBuffer[MESSAGE_BUFFER_DATA8_INDEX]);
  689. }
  690. else
  691. {
  692. static int iIndex = 0;
  693. static char ac[] = { '|', '/', '-', '\\' };
  694. printf("Tx: %c\r", ac[iIndex++]); fflush(stdout);
  695. iIndex &= 3;
  696. }
  697. }
  698. break;
  699. }
  700. case EVENT_RX_SEARCH_TIMEOUT:
  701. {
  702. printf("Search Timeout\n");
  703. break;
  704. }
  705. case EVENT_RX_FAIL:
  706. {
  707. printf("Rx Fail\n");
  708. break;
  709. }
  710. case EVENT_TRANSFER_RX_FAILED:
  711. {
  712. printf("Burst receive has failed\n");
  713. break;
  714. }
  715. case EVENT_TRANSFER_TX_COMPLETED:
  716. {
  717. printf("Tranfer Completed\n");
  718. break;
  719. }
  720. case EVENT_TRANSFER_TX_FAILED:
  721. {
  722. printf("Tranfer Failed\n");
  723. break;
  724. }
  725. case EVENT_RX_FAIL_GO_TO_SEARCH:
  726. {
  727. printf("Go to Search\n");
  728. break;
  729. }
  730. case EVENT_CHANNEL_COLLISION:
  731. {
  732. printf("Channel Collision\n");
  733. break;
  734. }
  735. case EVENT_TRANSFER_TX_START:
  736. {
  737. printf("Burst Started\n");
  738. break;
  739. }
  740. default:
  741. {
  742. printf("Unhandled channel event: 0x%X\n", stMessage.aucData[2]);
  743. break;
  744. }
  745. }
  746. break;
  747. }
  748. default:
  749. {
  750. printf("Unhandled response 0%d to message 0x%X\n", stMessage.aucData[2], stMessage.aucData[1]);
  751. break;
  752. }
  753. }
  754. break;
  755. }
  756. case MESG_STARTUP_MESG_ID:
  757. {
  758. printf("RESET Complete, reason: ");
  759. UCHAR ucReason = stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX];
  760. if (ucReason == RESET_POR)
  761. printf("RESET_POR");
  762. if (ucReason & RESET_SUSPEND)
  763. printf("RESET_SUSPEND ");
  764. if (ucReason & RESET_SYNC)
  765. printf("RESET_SYNC ");
  766. if (ucReason & RESET_CMD)
  767. printf("RESET_CMD ");
  768. if (ucReason & RESET_WDT)
  769. printf("RESET_WDT ");
  770. if (ucReason & RESET_RST)
  771. printf("RESET_RST ");
  772. printf("\n");
  773. break;
  774. }
  775. case MESG_CAPABILITIES_ID:
  776. {
  777. printf("CAPABILITIES:\n");
  778. printf(" Max ANT Channels: %d\n", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  779. printf(" Max ANT Networks: %d\n", stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX]);
  780. UCHAR ucStandardOptions = stMessage.aucData[MESSAGE_BUFFER_DATA3_INDEX];
  781. UCHAR ucAdvanced = stMessage.aucData[MESSAGE_BUFFER_DATA4_INDEX];
  782. UCHAR ucAdvanced2 = stMessage.aucData[MESSAGE_BUFFER_DATA5_INDEX];
  783. printf("Standard Options:\n");
  784. if (ucStandardOptions & CAPABILITIES_NO_RX_CHANNELS)
  785. printf("CAPABILITIES_NO_RX_CHANNELS\n");
  786. if (ucStandardOptions & CAPABILITIES_NO_TX_CHANNELS)
  787. printf("CAPABILITIES_NO_TX_CHANNELS\n");
  788. if (ucStandardOptions & CAPABILITIES_NO_RX_MESSAGES)
  789. printf("CAPABILITIES_NO_RX_MESSAGES\n");
  790. if (ucStandardOptions & CAPABILITIES_NO_TX_MESSAGES)
  791. printf("CAPABILITIES_NO_TX_MESSAGES\n");
  792. if (ucStandardOptions & CAPABILITIES_NO_ACKD_MESSAGES)
  793. printf("CAPABILITIES_NO_ACKD_MESSAGES\n");
  794. if (ucStandardOptions & CAPABILITIES_NO_BURST_TRANSFER)
  795. printf("CAPABILITIES_NO_BURST_TRANSFER\n");
  796. printf("Advanced Options:\n");
  797. if (ucAdvanced & CAPABILITIES_OVERUN_UNDERRUN)
  798. printf("CAPABILITIES_OVERUN_UNDERRUN\n");
  799. if (ucAdvanced & CAPABILITIES_NETWORK_ENABLED)
  800. printf("CAPABILITIES_NETWORK_ENABLED\n");
  801. if (ucAdvanced & CAPABILITIES_AP1_VERSION_2)
  802. printf("CAPABILITIES_AP1_VERSION_2\n");
  803. if (ucAdvanced & CAPABILITIES_SERIAL_NUMBER_ENABLED)
  804. printf("CAPABILITIES_SERIAL_NUMBER_ENABLED\n");
  805. if (ucAdvanced & CAPABILITIES_PER_CHANNEL_TX_POWER_ENABLED)
  806. printf("CAPABILITIES_PER_CHANNEL_TX_POWER_ENABLED\n");
  807. if (ucAdvanced & CAPABILITIES_LOW_PRIORITY_SEARCH_ENABLED)
  808. printf("CAPABILITIES_LOW_PRIORITY_SEARCH_ENABLED\n");
  809. if (ucAdvanced & CAPABILITIES_SCRIPT_ENABLED)
  810. printf("CAPABILITIES_SCRIPT_ENABLED\n");
  811. if (ucAdvanced & CAPABILITIES_SEARCH_LIST_ENABLED)
  812. printf("CAPABILITIES_SEARCH_LIST_ENABLED\n");
  813. if (usSize_ > 4)
  814. {
  815. printf("Advanced 2 Options 1:\n");
  816. if (ucAdvanced2 & CAPABILITIES_LED_ENABLED)
  817. printf("CAPABILITIES_LED_ENABLED\n");
  818. if (ucAdvanced2 & CAPABILITIES_EXT_MESSAGE_ENABLED)
  819. printf("CAPABILITIES_EXT_MESSAGE_ENABLED\n");
  820. if (ucAdvanced2 & CAPABILITIES_SCAN_MODE_ENABLED)
  821. printf("CAPABILITIES_SCAN_MODE_ENABLED\n");
  822. if (ucAdvanced2 & CAPABILITIES_RESERVED)
  823. printf("CAPABILITIES_RESERVED\n");
  824. if (ucAdvanced2 & CAPABILITIES_PROX_SEARCH_ENABLED)
  825. printf("CAPABILITIES_PROX_SEARCH_ENABLED\n");
  826. if (ucAdvanced2 & CAPABILITIES_EXT_ASSIGN_ENABLED)
  827. printf("CAPABILITIES_EXT_ASSIGN_ENABLED\n");
  828. if (ucAdvanced2 & CAPABILITIES_FS_ANTFS_ENABLED)
  829. printf("CAPABILITIES_FREE_1\n");
  830. if (ucAdvanced2 & CAPABILITIES_FIT1_ENABLED)
  831. printf("CAPABILITIES_FIT1_ENABLED\n");
  832. }
  833. break;
  834. }
  835. case MESG_CHANNEL_STATUS_ID:
  836. {
  837. printf("Got Status\n");
  838. char astrStatus[][32] = { "STATUS_UNASSIGNED_CHANNEL",
  839. "STATUS_ASSIGNED_CHANNEL",
  840. "STATUS_SEARCHING_CHANNEL",
  841. "STATUS_TRACKING_CHANNEL" };
  842. UCHAR ucStatusByte = stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX] & STATUS_CHANNEL_STATE_MASK; // MUST MASK OFF THE RESERVED BITS
  843. printf("STATUS: %s\n", astrStatus[ucStatusByte]);
  844. break;
  845. }
  846. case MESG_CHANNEL_ID_ID:
  847. {
  848. // Channel ID of the device that we just recieved a message from.
  849. USHORT usDeviceNumber = stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA3_INDEX] << 8);
  850. UCHAR ucDeviceType = stMessage.aucData[MESSAGE_BUFFER_DATA4_INDEX];
  851. UCHAR ucTransmissionType = stMessage.aucData[MESSAGE_BUFFER_DATA5_INDEX];
  852. printf("CHANNEL ID: (%d/%d/%d)\n", usDeviceNumber, ucDeviceType, ucTransmissionType);
  853. break;
  854. }
  855. case MESG_VERSION_ID:
  856. {
  857. printf("VERSION: %s\n", (char*)&stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  858. break;
  859. }
  860. case MESG_ACKNOWLEDGED_DATA_ID:
  861. case MESG_BURST_DATA_ID:
  862. case MESG_BROADCAST_DATA_ID:
  863. {
  864. // The flagged and unflagged data messages have the same
  865. // message ID. Therefore, we need to check the size to
  866. // verify of a flag is present at the end of a message.
  867. // To enable flagged messages, must call ANT_RxExtMesgsEnable first.
  868. if (usSize_ > MESG_DATA_SIZE)
  869. {
  870. UCHAR ucFlag = stMessage.aucData[MESSAGE_BUFFER_DATA10_INDEX];
  871. if (ucFlag & ANT_LIB_CONFIG_MESG_OUT_INC_TIME_STAMP && ucFlag & ANT_EXT_MESG_BITFIELD_DEVICE_ID)
  872. {
  873. // In case we miss messages for 2 seconds or longer, we use the system time from the standard C time library to calculate rollovers
  874. time_t currentRxTime = time(NULL);
  875. if (currentRxTime - previousRxTime >= 2)
  876. {
  877. ulNewEventTime += (currentRxTime - previousRxTime) / 2 * 32768;
  878. }
  879. previousRxTime = currentRxTime;
  880. unsigned short usCurrentEventTime = stMessage.aucData[MESSAGE_BUFFER_DATA15_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA16_INDEX] << 8);
  881. unsigned short usDeltaEventTime = usCurrentEventTime - usPreviousEventTime;
  882. ulNewEventTime += usDeltaEventTime;
  883. usPreviousEventTime = usCurrentEventTime;
  884. printf("%f-", (double)ulNewEventTime / 32768);
  885. // NOTE: In this example we use the incoming message timestamp as it typically has the most accuracy
  886. // NOTE: The library will handle the received time discrepancy caused by power only event count linked messages
  887. if (bPowerDecoderInitialized)
  888. {
  889. DecodePowerMessage((double)ulNewEventTime / 32768, &stMessage.aucData[ucDataOffset]);
  890. }
  891. // NOTE: We must compensate for the power only event count/rx time discrepance here, because the library does not decode Te/Ps
  892. // The torque effectiveness/pedal smoothness page is tied to the power only page and vice versa,
  893. // so both pages share the same "received time" depending on which page was received first and if the event count updated.
  894. if (stMessage.aucData[ucDataOffset] == ANT_TEPS || stMessage.aucData[ucDataOffset] == ANT_POWERONLY)
  895. {
  896. UCHAR ucNewPowerOnlyUpdateEventCount = stMessage.aucData[ucDataOffset + 1];
  897. if (ucNewPowerOnlyUpdateEventCount != ucPowerOnlyUpdateEventCount)
  898. {
  899. ucPowerOnlyUpdateEventCount = ucNewPowerOnlyUpdateEventCount;
  900. dRxTimeTePs = (double)ulNewEventTime / 32768;
  901. }
  902. if (stMessage.aucData[ucDataOffset] == ANT_TEPS)
  903. {
  904. // NOTE: Any value greater than 200 or 100% should be considered "INVALID"
  905. FLOAT fLeftTorqueEffectiveness = (float)stMessage.aucData[ucDataOffset + 2] / 2;
  906. FLOAT fRightTorqueEffectiveness = (float)stMessage.aucData[ucDataOffset + 3] / 2;
  907. FLOAT fLeftOrCombPedalSmoothness = (float)stMessage.aucData[ucDataOffset + 4] / 2;
  908. FLOAT fRightPedalSmoothness = (float)stMessage.aucData[ucDataOffset + 4] / 2;
  909. TePsReceiver(dRxTimeTePs, fLeftTorqueEffectiveness, fRightTorqueEffectiveness, fLeftOrCombPedalSmoothness, fRightPedalSmoothness);
  910. }
  911. else
  912. {
  913. // NOTE: Power only is a separate data stream containing similar power data compared to torque data pages but containing pedal power balance
  914. // On power only sensors, it would be valuable to average power balance between generated records
  915. FLOAT fPowerBalance = (float)(0x7F & stMessage.aucData[ucDataOffset + 2]);
  916. BOOL bPowerBalanceRightPedalIndicator = 0x80 & stMessage.aucData[ucDataOffset + 2] != 0;
  917. PowerBalanceReceiver(dRxTimeTePs, fPowerBalance, bPowerBalanceRightPedalIndicator);
  918. }
  919. }
  920. }
  921. if (bDisplay && ucFlag & ANT_EXT_MESG_BITFIELD_DEVICE_ID)
  922. {
  923. // Channel ID of the device that we just recieved a message from.
  924. USHORT usDeviceNumber = stMessage.aucData[MESSAGE_BUFFER_DATA11_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA12_INDEX] << 8);
  925. UCHAR ucDeviceType = stMessage.aucData[MESSAGE_BUFFER_DATA13_INDEX];
  926. UCHAR ucTransmissionType = stMessage.aucData[MESSAGE_BUFFER_DATA14_INDEX];
  927. printf("Chan ID(%d/%d/%d) - ", usDeviceNumber, ucDeviceType, ucTransmissionType);
  928. }
  929. }
  930. // Display recieved message
  931. bPrintBuffer = TRUE;
  932. ucDataOffset = MESSAGE_BUFFER_DATA2_INDEX; // For most data messages
  933. if (bDisplay)
  934. {
  935. if (stMessage.ucMessageID == MESG_ACKNOWLEDGED_DATA_ID)
  936. printf("Acked Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  937. else if (stMessage.ucMessageID == MESG_BURST_DATA_ID)
  938. printf("Burst(0x%02x) Rx:(%d): ", ((stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX] & 0xE0) >> 5), stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX] & 0x1F);
  939. else
  940. printf("Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  941. }
  942. break;
  943. }
  944. case MESG_EXT_BROADCAST_DATA_ID:
  945. case MESG_EXT_ACKNOWLEDGED_DATA_ID:
  946. case MESG_EXT_BURST_DATA_ID:
  947. {
  948. // The "extended" part of this message is the 4-byte channel
  949. // id of the device that we recieved this message from. This message
  950. // is only available on the AT3. The AP2 uses flagged versions of the
  951. // data messages as shown above.
  952. // Channel ID of the device that we just recieved a message from.
  953. USHORT usDeviceNumber = stMessage.aucData[MESSAGE_BUFFER_DATA2_INDEX] | (stMessage.aucData[MESSAGE_BUFFER_DATA3_INDEX] << 8);
  954. UCHAR ucDeviceType = stMessage.aucData[MESSAGE_BUFFER_DATA4_INDEX];
  955. UCHAR ucTransmissionType = stMessage.aucData[MESSAGE_BUFFER_DATA5_INDEX];
  956. bPrintBuffer = TRUE;
  957. ucDataOffset = MESSAGE_BUFFER_DATA6_INDEX; // For most data messages
  958. if (bDisplay)
  959. {
  960. // Display the channel id
  961. printf("Chan ID(%d/%d/%d) ", usDeviceNumber, ucDeviceType, ucTransmissionType);
  962. if (stMessage.ucMessageID == MESG_EXT_ACKNOWLEDGED_DATA_ID)
  963. printf("- Acked Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  964. else if (stMessage.ucMessageID == MESG_EXT_BURST_DATA_ID)
  965. printf("- Burst(0x%02x) Rx:(%d): ", ((stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX] & 0xE0) >> 5), stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX] & 0x1F);
  966. else
  967. printf("- Rx:(%d): ", stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX]);
  968. }
  969. // NOTE: A different source of sub-second timing is required if the device does not support received time extended messages.
  970. break;
  971. }
  972. default:
  973. {
  974. break;
  975. }
  976. }
  977. // If we recieved a data message, diplay its contents here.
  978. if (bPrintBuffer)
  979. {
  980. if (bDisplay)
  981. {
  982. printf("[%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x]\n",
  983. stMessage.aucData[ucDataOffset + 0],
  984. stMessage.aucData[ucDataOffset + 1],
  985. stMessage.aucData[ucDataOffset + 2],
  986. stMessage.aucData[ucDataOffset + 3],
  987. stMessage.aucData[ucDataOffset + 4],
  988. stMessage.aucData[ucDataOffset + 5],
  989. stMessage.aucData[ucDataOffset + 6],
  990. stMessage.aucData[ucDataOffset + 7]);
  991. }
  992. else
  993. {
  994. static int iIndex = 0;
  995. static char ac[] = { '|', '/', '-', '\\' };
  996. printf("Rx: %c\r", ac[iIndex++]); fflush(stdout);
  997. iIndex &= 3;
  998. }
  999. }
  1000. return;
  1001. }
  1002. ////////////////////////////////////////////////////////////////////////////////
  1003. // RecordReceiver
  1004. //
  1005. // Handle new records from power recording library.
  1006. //
  1007. ////////////////////////////////////////////////////////////////////////////////
  1008. void Example::RecordReceiver(double dLastRecordTime_, double dTotalRotation_, double dTotalEnergy_, float fAverageCadence_, float fAveragePower_)
  1009. {
  1010. fprintf(fp1, "%lf, %lf, %lf, %f, %f\n",
  1011. dLastRecordTime_, dTotalRotation_, dTotalEnergy_, fAverageCadence_, fAveragePower_);
  1012. }
  1013. ////////////////////////////////////////////////////////////////////////////////
  1014. // TePsReceiver
  1015. //
  1016. // Handle new torque effectiveness and pedal smoothness data page.
  1017. //
  1018. ////////////////////////////////////////////////////////////////////////////////
  1019. void Example::TePsReceiver(double dRxTime_, float fLeftTorqEff_, float fRightTorqEff_, float fLeftOrCPedSmth_, float fRightPedSmth_)
  1020. {
  1021. fprintf(fp1, "RxTime,LTE,RTE,LCPS,RPS,%f, %f, %f, %f, %f\n",
  1022. dRxTime_, fLeftTorqEff_, fRightTorqEff_, fLeftOrCPedSmth_, fRightPedSmth_);
  1023. }
  1024. ////////////////////////////////////////////////////////////////////////////////
  1025. // PowerBalanceReceiver
  1026. //
  1027. // Handle power balance from power only data page.
  1028. // NOTE: This should be handled by the library for power only sensors using the same integrated power into energy technique.
  1029. //
  1030. ////////////////////////////////////////////////////////////////////////////////
  1031. void Example::PowerBalanceReceiver(double dRxTime_, float fPowerBalance_, bool bPowerBalanceRightPedalIndicator_)
  1032. {
  1033. fprintf(fp1, "RxTime,PwrBal,RightPedal,%f, %f, %d\n",
  1034. dRxTime_, fPowerBalance_, bPowerBalanceRightPedalIndicator_);
  1035. }
  1036. ////////////////////////////////////////////////////////////////////////////////
  1037. // PrintMenu
  1038. //
  1039. // Start the Test program.
  1040. //
  1041. ////////////////////////////////////////////////////////////////////////////////
  1042. void Example::PrintMenu()
  1043. {
  1044. // Printout options
  1045. printf("\n");
  1046. printf("M - Print this menu\n");
  1047. printf("R - Reset\n");
  1048. printf("C - Request Capabilites\n");
  1049. printf("V - Request Version\n");
  1050. printf("I - Request Channel ID\n");
  1051. printf("S - Request Status\n");
  1052. printf("U - Request USB Descriptor\n");
  1053. printf("D - Toggle Display\n");
  1054. printf("Q - Quit\n");
  1055. printf("\n");
  1056. fflush(stdout);
  1057. }