demo_hr_transmitter.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  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 <windows.h>
  9. #include "demo_hr_transmitter.h"
  10. #include "types.h"
  11. #include "dsi_framer_ant.hpp"
  12. #include "dsi_thread.h"
  13. #include "dsi_serial_generic.hpp"
  14. #include "dsi_debug.hpp"
  15. #include <stdio.h>
  16. #include <assert.h>
  17. #include <string.h>
  18. //#define ENABLE_EXTENDED_MESSAGES
  19. #define USER_BAUDRATE (57600) // For AT3/AP2, use 57600
  20. #define USER_RADIOFREQ (57) // HRM Profile specified
  21. #define USER_ANTCHANNEL (0)
  22. #define USER_DEVICENUM (49)
  23. #define USER_DEVICETYPE 0x78 // HRM Profile specified
  24. #define USER_TRANSTYPE (1) // HRM Profile specified
  25. #define USER_CHANNELTYPE (0) // 0 for master
  26. #define USER_NETWORK_KEY {0xB9, 0xA5, 0x21, 0xFB, 0xBD, 0x72, 0xC3, 0x45} //ANT+ Key
  27. #define USER_NETWORK_NUM (0) // The network key is assigned to this network number
  28. #define USER_PERIOD (8070) // HRM Profile specified
  29. #define MESSAGE_TIMEOUT (1000)
  30. //Simulated device information - would be set by manufacturer for specific devices
  31. #define HRM_MANUFACTURER_ID (0x01)
  32. #define HRM_UPPER_SERIAL_NUMBER (0x3412)
  33. #define HRM_HARDWARE_VERSION (0x02)
  34. #define HRM_SOFTWARE_VERSION (0x42)
  35. #define HRM_MODEL_NUMBER (0x02)
  36. #define HRM_DATA_PAGE_0 (0x00)
  37. #define HRM_DATA_PAGE_1 (0x01)
  38. #define HRM_DATA_PAGE_2 (0x02)
  39. #define HRM_DATA_PAGE_3 (0x03)
  40. #define HRM_RESERVED (0xFF)
  41. #define MASK_TOGGLE_BIT (0x80)
  42. #define MASK_HEARTBEAT_EVENT_TIME_LSB (0x00FF)
  43. #define MASK_SERIAL_NUMBER_LSB (0xFF)
  44. // Indexes into message recieved from ANT
  45. #define MESSAGE_BUFFER_DATA1_INDEX ((UCHAR) 0)
  46. #define MESSAGE_BUFFER_DATA2_INDEX ((UCHAR) 1)
  47. #define MESSAGE_BUFFER_DATA3_INDEX ((UCHAR) 2)
  48. #define MESSAGE_BUFFER_DATA4_INDEX ((UCHAR) 3)
  49. #define MESSAGE_BUFFER_DATA5_INDEX ((UCHAR) 4)
  50. #define MESSAGE_BUFFER_DATA6_INDEX ((UCHAR) 5)
  51. #define MESSAGE_BUFFER_DATA7_INDEX ((UCHAR) 6)
  52. #define MESSAGE_BUFFER_DATA8_INDEX ((UCHAR) 7)
  53. #define MESSAGE_BUFFER_DATA9_INDEX ((UCHAR) 8)
  54. #define MESSAGE_BUFFER_DATA10_INDEX ((UCHAR) 9)
  55. #define MESSAGE_BUFFER_DATA11_INDEX ((UCHAR) 10)
  56. #define MESSAGE_BUFFER_DATA12_INDEX ((UCHAR) 11)
  57. #define MESSAGE_BUFFER_DATA13_INDEX ((UCHAR) 12)
  58. #define MESSAGE_BUFFER_DATA14_INDEX ((UCHAR) 13)
  59. ////////////////////////////////////////////////////////////////////////////////
  60. // main
  61. //
  62. // Usage:
  63. //
  64. // c:\heartrateTxDemo.exe [device_no]
  65. //
  66. // ... where
  67. //
  68. // device_no: USB Device port, starting at 0
  69. //
  70. // ... example
  71. //
  72. // c:\heartrateTxDemo.exe 0
  73. //
  74. // Comment to USB port 0
  75. //
  76. // If optional arguements are not supplied, user will
  77. // be prompted to enter these after the program starts.
  78. //
  79. ////////////////////////////////////////////////////////////////////////////////
  80. int main(int argc, char **argv)
  81. {
  82. Demo* pclDemo = new Demo();
  83. UCHAR ucDeviceNumberUSB = 0xFF;
  84. if(argc > 1)
  85. {
  86. ucDeviceNumberUSB = (UCHAR) atoi(argv[0]);
  87. }
  88. if(pclDemo->Init(ucDeviceNumberUSB))
  89. {
  90. pclDemo->Start();
  91. }
  92. else
  93. delete pclDemo;
  94. return 0;
  95. }
  96. ////////////////////////////////////////////////////////////////////////////////
  97. // Demo
  98. //
  99. // Constructor, intializes Demo class
  100. //
  101. ////////////////////////////////////////////////////////////////////////////////
  102. Demo::Demo()
  103. {
  104. ucChannelType = USER_CHANNELTYPE;
  105. pclSerialObject = (DSISerialGeneric*)NULL;
  106. pclMessageObject = (DSIFramerANT*)NULL;
  107. uiDSIThread = (DSI_THREAD_ID)NULL;
  108. bMyDone = FALSE;
  109. bPrintAllMessages = TRUE;
  110. bDone = FALSE;
  111. bBroadcasting = FALSE;
  112. memset(aucTransmitBuffer,0,ANT_STANDARD_DATA_PAYLOAD_SIZE);
  113. }
  114. ////////////////////////////////////////////////////////////////////////////////
  115. // ~Demo
  116. //
  117. // Destructor, clean up and loose memory
  118. //
  119. ////////////////////////////////////////////////////////////////////////////////
  120. Demo::~Demo()
  121. {
  122. if(pclMessageObject)
  123. delete pclMessageObject;
  124. if(pclSerialObject)
  125. delete pclSerialObject;
  126. }
  127. ////////////////////////////////////////////////////////////////////////////////
  128. // Init
  129. //
  130. // Init the Demo and ANT Library.
  131. //
  132. // ucDeviceNumberUSB_: USB Device Number (0 for first USB stick plugged and so on)
  133. // If not specified on command line, 0xFF is passed in as invalid.
  134. //
  135. ////////////////////////////////////////////////////////////////////////////////
  136. BOOL Demo::Init(UCHAR ucDeviceNumberUSB_)
  137. {
  138. BOOL bStatus;
  139. //Initialize HRM variables
  140. ucHeartBeatCount = 0;
  141. usHeartBeatEventTime = 0;
  142. // Initialize condition var and mutex
  143. UCHAR ucCondInit = DSIThread_CondInit(&condTestDone);
  144. assert(ucCondInit == DSI_THREAD_ENONE);
  145. UCHAR ucMutexInit = DSIThread_MutexInit(&mutexTestDone);
  146. assert(ucMutexInit == DSI_THREAD_ENONE);
  147. #if defined(DEBUG_FILE)
  148. // Enable logging
  149. DSIDebug::Init();
  150. DSIDebug::SetDebug(TRUE);
  151. #endif
  152. // Create Serial object.
  153. pclSerialObject = new DSISerialGeneric();
  154. assert(pclSerialObject); // NOTE: Will fail if the module is not available.
  155. //Print greeting
  156. printf("*****************************************\n* Heart Rate Monitior Transmitter Demo *\n");
  157. printf("* *\n");
  158. printf("* Press Ctrl-c to exit *\n");
  159. printf("*****************************************\n");
  160. // If no device number was specified on the command line,
  161. // prompt the user for input.
  162. if(ucDeviceNumberUSB_ == 0xFF)
  163. {
  164. printf("Enter a USB Device number: "); fflush(stdout);
  165. char st[1024];
  166. fgets(st, sizeof(st), stdin);
  167. sscanf(st, "%u", &ucDeviceNumberUSB_);
  168. }
  169. // Initialize Serial object
  170. // The device number depends on how many USB sticks have been
  171. // plugged into the PC. The first USB stick plugged will be 0
  172. // the next 1 and so on.
  173. //
  174. // The Baud Rate depends on the ANT solution being used. AP1
  175. // is 50000, all others are 57600
  176. bStatus = pclSerialObject->Init(USER_BAUDRATE, ucDeviceNumberUSB_);
  177. assert(bStatus);
  178. // Create Framer object.
  179. pclMessageObject = new DSIFramerANT(pclSerialObject);
  180. assert(pclMessageObject);
  181. // Initialize Framer object.
  182. bStatus = pclMessageObject->Init();
  183. assert(bStatus);
  184. // Let Serial know about Framer.
  185. pclSerialObject->SetCallback(pclMessageObject);
  186. // Open Serial.
  187. bStatus = pclSerialObject->Open();
  188. // If the Open function failed, most likely the device
  189. // we are trying to access does not exist, or it is connected
  190. // to another program
  191. if(!bStatus)
  192. {
  193. printf("Failed to connect to device at USB port %d\n", ucDeviceNumberUSB_);
  194. return FALSE;
  195. }
  196. // Create message thread.
  197. uiDSIThread = DSIThread_CreateThread(&Demo::RunMessageThread, this);
  198. assert(uiDSIThread);
  199. printf("Initialization was successful!\n"); fflush(stdout);
  200. //Get the device configuration information and simulated HR from user
  201. GetUserInfo();
  202. return TRUE;
  203. }
  204. ////////////////////////////////////////////////////////////////////////////////
  205. // GetUserInfo
  206. //
  207. // Get a configuration information from the user
  208. //
  209. ////////////////////////////////////////////////////////////////////////////////
  210. BOOL Demo::GetUserInfo()
  211. {
  212. //get a HRM device number (in reality this would be have to be selected to minimize confilicts of device numbers
  213. do
  214. {
  215. printf("HRM device number (range 0 - 65535): "); fflush(stdout);
  216. char st[1024];
  217. fgets(st, sizeof(st), stdin);
  218. sscanf(st, "%i", &siDeviceNumberANT);
  219. fflush(stdin);
  220. if((siDeviceNumberANT >=65535) || (siDeviceNumberANT < 1))
  221. printf("Invalid device number...\n"); fflush(stdout);
  222. }while ((siDeviceNumberANT > 6553) || (siDeviceNumberANT < 1));
  223. //Get a simulated test heartrate
  224. INT siTempHeartRate;
  225. BOOL bSuccess;
  226. do{
  227. printf("Enter a heartrate (range 1-255 BPM): "); fflush(stdout);
  228. char st[1024];
  229. fgets(st, sizeof(st), stdin); fflush(stdin);
  230. bSuccess = sscanf(st, "%i", &siTempHeartRate);
  231. if((siTempHeartRate > 255) || (siTempHeartRate <= 0))
  232. printf("Invalid heartrate...\n");
  233. }while ( !bSuccess || (siTempHeartRate > 255) || (siTempHeartRate <= 0) );
  234. ucHeartRate = (UCHAR)siTempHeartRate;
  235. return (TRUE);
  236. }
  237. ////////////////////////////////////////////////////////////////////////////////
  238. // Close
  239. //
  240. // Close connection to USB stick.
  241. //
  242. ////////////////////////////////////////////////////////////////////////////////
  243. void Demo::Close()
  244. {
  245. //Wait for test to be done
  246. DSIThread_MutexLock(&mutexTestDone);
  247. bDone = TRUE;
  248. UCHAR ucWaitResult = DSIThread_CondTimedWait(&condTestDone, &mutexTestDone, DSI_THREAD_INFINITE);
  249. assert(ucWaitResult == DSI_THREAD_ENONE);
  250. DSIThread_MutexUnlock(&mutexTestDone);
  251. //Destroy mutex and condition var
  252. DSIThread_MutexDestroy(&mutexTestDone);
  253. DSIThread_CondDestroy(&condTestDone);
  254. //Close all stuff
  255. if(pclSerialObject)
  256. pclSerialObject->Close();
  257. #if defined(DEBUG_FILE)
  258. DSIDebug::Close();
  259. #endif
  260. }
  261. ////////////////////////////////////////////////////////////////////////////////
  262. // Start
  263. //
  264. // Starts the Demo
  265. //
  266. ////////////////////////////////////////////////////////////////////////////////
  267. void Demo::Start()
  268. {
  269. BOOL bStatus;
  270. // Start ANT channel setup
  271. bStatus = InitANT();
  272. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE );
  273. while(!bMyDone)
  274. {
  275. if( bCaughtSig == TRUE )
  276. bMyDone = TRUE;
  277. HeartBeat();
  278. DSIThread_Sleep(0);
  279. }
  280. //Disconnecting from module
  281. printf("Disconnecting module...\n");
  282. this->Close();
  283. printf("Demo has completed successfully!\n");
  284. system("PAUSE");
  285. return;
  286. }
  287. ////////////////////////////////////////////////////////////////////////////////
  288. // CtrlHandler
  289. //
  290. // Allows the user to exit by using ctrl-c
  291. // Closes the usb device properly.
  292. //
  293. ////////////////////////////////////////////////////////////////////////////////
  294. BOOL Demo::CtrlHandler( DWORD fdwCtrlType )
  295. {
  296. if(fdwCtrlType == CTRL_C_EVENT)
  297. {
  298. bCaughtSig = TRUE;
  299. }
  300. return TRUE;
  301. }
  302. ////////////////////////////////////////////////////////////////////////////////
  303. // InitANT
  304. //
  305. // Resets the system and starts the test
  306. //
  307. ////////////////////////////////////////////////////////////////////////////////
  308. BOOL Demo::InitANT(void)
  309. {
  310. BOOL bStatus;
  311. // Reset system
  312. printf("Resetting module...\n");
  313. bStatus = pclMessageObject->ResetSystem();
  314. DSIThread_Sleep(1000);
  315. // Start the test by setting network key
  316. printf("Setting network key...\n");
  317. UCHAR ucNetKey[8] = USER_NETWORK_KEY;
  318. bStatus = pclMessageObject->SetNetworkKey(USER_NETWORK_NUM, ucNetKey, MESSAGE_TIMEOUT);
  319. return bStatus;
  320. }
  321. ////////////////////////////////////////////////////////////////////////////////
  322. // RunMessageThread
  323. //
  324. // Callback function that is used to create the thread. This is a static
  325. // function.
  326. ////////////////////////////////////////////////////////////////////////////////
  327. DSI_THREAD_RETURN Demo::RunMessageThread(void *pvParameter_)
  328. {
  329. ((Demo*) pvParameter_)->MessageThread();
  330. return NULL;
  331. }
  332. ////////////////////////////////////////////////////////////////////////////////
  333. // MessageThread
  334. //
  335. // Run message thread
  336. ////////////////////////////////////////////////////////////////////////////////
  337. void Demo::MessageThread()
  338. {
  339. ANT_MESSAGE stMessage;
  340. USHORT usSize;
  341. bDone = FALSE;
  342. while(!bDone)
  343. {
  344. if(pclMessageObject->WaitForMessage(1000))
  345. {
  346. usSize = pclMessageObject->GetMessage(&stMessage);
  347. if(bDone)
  348. break;
  349. if(usSize == DSI_FRAMER_ERROR)
  350. {
  351. // Get the message to clear the error
  352. usSize = pclMessageObject->GetMessage(&stMessage, MESG_MAX_SIZE_VALUE);
  353. continue;
  354. }
  355. if(usSize != DSI_FRAMER_ERROR && usSize != DSI_FRAMER_TIMEDOUT && usSize != 0)
  356. {
  357. ProcessMessage(stMessage, usSize);
  358. }
  359. }
  360. }
  361. DSIThread_MutexLock(&mutexTestDone);
  362. UCHAR ucCondResult = DSIThread_CondSignal(&condTestDone);
  363. assert(ucCondResult == DSI_THREAD_ENONE);
  364. DSIThread_MutexUnlock(&mutexTestDone);
  365. }
  366. ////////////////////////////////////////////////////////////////////////////////
  367. // HeartBeat
  368. //
  369. // Check if it is time for another heartbeat (based on user heartrate) and if it is, simulate one
  370. ////////////////////////////////////////////////////////////////////////////////
  371. void Demo::HeartBeat()
  372. {
  373. static ULONGLONG ullCurrentTime = ullStartupTime;
  374. static ULONGLONG ullLastTime = 0;
  375. ULONGLONG ullTempTime = GetTickCount64();
  376. if( ucHeartRate*(ullTempTime - ullLastTime) > 60000 )
  377. {
  378. usHeartBeatEventTime = ((ullTempTime - ullStartupTime)*1024)/1000 ; //Calculate when the heartbeat happened and convert to 1/1024 instead of ms from the system clock
  379. //printf("!! %llu ms in 1/1024 is %hu !! \n", ullTempTime - ullStartTime, usHeartBeatEventTime);
  380. ucHeartBeatCount++; //Count total number of heartbeats
  381. ullLastTime = ullTempTime; //reset for next beat
  382. }
  383. }
  384. ////////////////////////////////////////////////////////////////////////////////
  385. // ProcessMessage
  386. //
  387. // Process ALL messages that come from ANT, including event messages.
  388. //
  389. // stMessage: Message struct containing message recieved from ANT
  390. // usSize_:
  391. ////////////////////////////////////////////////////////////////////////////////
  392. void Demo::ProcessMessage(ANT_MESSAGE stMessage, USHORT usSize_)
  393. {
  394. BOOL bStatus;
  395. BOOL bPrintBuffer = FALSE;
  396. UCHAR ucDataOffset = MESSAGE_BUFFER_DATA2_INDEX; // For most data messages
  397. static ULONGLONG ullStartTime = GetTickCount64();
  398. switch(stMessage.ucMessageID)
  399. {
  400. //RESPONSE MESG
  401. case MESG_RESPONSE_EVENT_ID:
  402. {
  403. //RESPONSE TYPE
  404. switch(stMessage.aucData[1])
  405. {
  406. case MESG_NETWORK_KEY_ID:
  407. {
  408. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  409. {
  410. printf("Error configuring network key: Code 0%d\n", stMessage.aucData[2]);
  411. break;
  412. }
  413. printf("Network key set.\n");
  414. printf("Assigning channel...\n");
  415. bStatus = pclMessageObject->AssignChannel(USER_ANTCHANNEL, PARAMETER_TX_NOT_RX, 0, MESSAGE_TIMEOUT);
  416. break;
  417. }
  418. case MESG_RX_EXT_MESGS_ENABLE_ID:
  419. printf("Extended messeges enabled.\n");
  420. break;
  421. case MESG_ASSIGN_CHANNEL_ID:
  422. {
  423. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  424. {
  425. printf("Error assigning channel: Code 0%d\n", stMessage.aucData[2]);
  426. break;
  427. }
  428. printf("Channel assigned\n");
  429. printf("Setting Channel ID for ");
  430. bStatus = pclMessageObject->SetChannelID(USER_ANTCHANNEL, (USHORT)siDeviceNumberANT, USER_DEVICETYPE, USER_TRANSTYPE, MESSAGE_TIMEOUT);
  431. printf("device number: %hu\n",(USHORT)siDeviceNumberANT);
  432. break;
  433. }
  434. case MESG_CHANNEL_ID_ID:
  435. {
  436. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  437. {
  438. printf("Error configuring Channel ID: Code 0%d\n", stMessage.aucData[2]);
  439. break;
  440. }
  441. printf("Channel ID set\n");
  442. printf("Setting period to %d... \n", USER_PERIOD);
  443. bStatus = pclMessageObject->SetChannelPeriod(USER_ANTCHANNEL, USER_PERIOD, MESSAGE_TIMEOUT);
  444. break;
  445. }
  446. case MESG_CHANNEL_MESG_PERIOD_ID:
  447. {
  448. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  449. {
  450. printf("Error setting period: Code 0%d\n", stMessage.aucData[2]);
  451. break;
  452. }
  453. printf("Set period to %d. \n", USER_PERIOD);
  454. printf("Setting Radio Frequency...\n");
  455. bStatus = pclMessageObject->SetChannelRFFrequency(USER_ANTCHANNEL, USER_RADIOFREQ, MESSAGE_TIMEOUT);
  456. break;
  457. }
  458. case MESG_CHANNEL_RADIO_FREQ_ID:
  459. {
  460. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  461. {
  462. printf("Error configuring Radio Frequency: Code 0%d\n", stMessage.aucData[2]);
  463. break;
  464. }
  465. printf("Radio Frequency set\n");
  466. printf("Opening channel...\n");
  467. bBroadcasting = TRUE;
  468. bStatus = pclMessageObject->OpenChannel(USER_ANTCHANNEL, MESSAGE_TIMEOUT);
  469. break;
  470. }
  471. case MESG_OPEN_CHANNEL_ID:
  472. {
  473. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  474. {
  475. printf("Error opening channel: Code 0%d\n", stMessage.aucData[2]);
  476. bBroadcasting = FALSE;
  477. break;
  478. }
  479. printf("Channel opened\n");
  480. #if defined (ENABLE_EXTENDED_MESSAGES)
  481. printf("Enabling extended messages...\n");
  482. pclMessageObject->RxExtMesgsEnable(TRUE);
  483. #endif
  484. break;
  485. }
  486. case MESG_UNASSIGN_CHANNEL_ID:
  487. {
  488. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  489. {
  490. printf("Error unassigning channel: Code 0%d\n", stMessage.aucData[2]);
  491. break;
  492. }
  493. printf("Channel unassigned\n");
  494. printf("Press enter to exit\n");
  495. bMyDone = TRUE;
  496. break;
  497. }
  498. case MESG_CLOSE_CHANNEL_ID:
  499. {
  500. if(stMessage.aucData[2] != RESPONSE_NO_ERROR)
  501. {
  502. printf("Error closing channel: Code 0%d\n", stMessage.aucData[2]);
  503. break;
  504. }
  505. // If this message was successful, wait for EVENT_CHANNEL_CLOSED to confirm channel is closed
  506. break;
  507. }
  508. case MESG_REQUEST_ID:
  509. {
  510. if(stMessage.aucData[2] == INVALID_MESSAGE)
  511. {
  512. printf("Requested message not supported in this ANT product\n");
  513. }
  514. break;
  515. }
  516. case MESG_EVENT_ID:
  517. {
  518. switch(stMessage.aucData[2])
  519. {
  520. case EVENT_CHANNEL_CLOSED:
  521. {
  522. printf("Channel Closed\n");
  523. printf("Unassigning channel...\n");
  524. bStatus = pclMessageObject->UnAssignChannel(USER_ANTCHANNEL, MESSAGE_TIMEOUT);
  525. break;
  526. }
  527. case EVENT_TX:
  528. {
  529. // This event indicates that a message has just been
  530. // sent over the air. We take advantage of this event to set
  531. // up the data for the next message period.
  532. static USHORT usTxCounter = 0; //Counts number of messages sent
  533. static UCHAR ucbackgroundDataPageToSend = HRM_DATA_PAGE_1;
  534. //Messages which always go out regardless of the data page
  535. aucTransmitBuffer[MESSAGE_BUFFER_DATA8_INDEX] = ucHeartRate; //Byte 7 (big endian)
  536. aucTransmitBuffer[MESSAGE_BUFFER_DATA7_INDEX] = ucHeartBeatCount;
  537. aucTransmitBuffer[MESSAGE_BUFFER_DATA6_INDEX] = (UCHAR)(usHeartBeatEventTime >> 8); //msb
  538. aucTransmitBuffer[MESSAGE_BUFFER_DATA5_INDEX] = (UCHAR)(usHeartBeatEventTime & MASK_HEARTBEAT_EVENT_TIME_LSB) ; //lsb
  539. if ( (usTxCounter >= 0) && usTxCounter < 4 ) //Time to send a background page ( must send 4 background pages in a row to accomadate 2 and 1hz receivers
  540. {
  541. ULONGLONG ullTimeRightNow = GetTickCount64();
  542. switch(ucbackgroundDataPageToSend){
  543. case HRM_DATA_PAGE_1: //send data page 1
  544. ullTimeSinceStart = (ullTimeRightNow - ullStartupTime)/1000/2;
  545. //Page Number
  546. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] = HRM_DATA_PAGE_1;
  547. //Cumulative Operating Time
  548. aucTransmitBuffer[MESSAGE_BUFFER_DATA2_INDEX] = ullTimeSinceStart & 0xFF;
  549. aucTransmitBuffer[MESSAGE_BUFFER_DATA3_INDEX] = (ullTimeSinceStart>>8) & 0xFF;
  550. aucTransmitBuffer[MESSAGE_BUFFER_DATA4_INDEX] = (ullTimeSinceStart>>16) & 0xFF;
  551. if(usTxCounter == 3)
  552. ucbackgroundDataPageToSend = HRM_DATA_PAGE_2;
  553. break;
  554. case HRM_DATA_PAGE_2:
  555. //Page Number
  556. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] = HRM_DATA_PAGE_2;
  557. //Manufacture ID
  558. aucTransmitBuffer[MESSAGE_BUFFER_DATA2_INDEX] = HRM_MANUFACTURER_ID;
  559. //Serial Number
  560. aucTransmitBuffer[MESSAGE_BUFFER_DATA3_INDEX] = HRM_UPPER_SERIAL_NUMBER & MASK_SERIAL_NUMBER_LSB;
  561. aucTransmitBuffer[MESSAGE_BUFFER_DATA4_INDEX] = (HRM_UPPER_SERIAL_NUMBER>>8) & MASK_SERIAL_NUMBER_LSB;
  562. if(usTxCounter == 3)
  563. ucbackgroundDataPageToSend = HRM_DATA_PAGE_3;
  564. break;
  565. case HRM_DATA_PAGE_3:
  566. //Page number
  567. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] = HRM_DATA_PAGE_3;
  568. //Hardware Version
  569. aucTransmitBuffer[MESSAGE_BUFFER_DATA2_INDEX] = HRM_HARDWARE_VERSION;
  570. //Software Version
  571. aucTransmitBuffer[MESSAGE_BUFFER_DATA3_INDEX] = HRM_SOFTWARE_VERSION;
  572. //Model Number
  573. aucTransmitBuffer[MESSAGE_BUFFER_DATA4_INDEX] = HRM_MODEL_NUMBER;
  574. if(usTxCounter == 3)
  575. ucbackgroundDataPageToSend = HRM_DATA_PAGE_1;
  576. break;
  577. }
  578. }
  579. else //Time to send a regular page (Page 0)
  580. {
  581. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] = HRM_DATA_PAGE_0;
  582. for(UCHAR i = MESSAGE_BUFFER_DATA2_INDEX; i <= MESSAGE_BUFFER_DATA4_INDEX; i++){
  583. aucTransmitBuffer[i] = HRM_RESERVED;
  584. }
  585. }
  586. //Handle the toggle bit
  587. static UCHAR ucTogglePattern = MASK_TOGGLE_BIT;
  588. if(usTxCounter%4 == 0)
  589. ucTogglePattern = ~ucTogglePattern;
  590. if(ucTogglePattern == MASK_TOGGLE_BIT)
  591. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] = aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] | ucTogglePattern;
  592. else
  593. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] = aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX] & ucTogglePattern;
  594. if(++usTxCounter == 68)// reset broadcast counter (NOTE: not 65 because we still want to send 64 main pages before 4 background pages
  595. usTxCounter = 0;
  596. // Broadcast data will be sent over the air on
  597. // the next message period.
  598. if(bBroadcasting)
  599. {
  600. pclMessageObject->SendBroadcastData(USER_ANTCHANNEL, aucTransmitBuffer);
  601. // Echo what the data will be over the air on the next message period.
  602. if(bPrintAllMessages == TRUE)
  603. printf("Tx:(%d): [%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x],[%02x]\n",
  604. USER_ANTCHANNEL,
  605. aucTransmitBuffer[MESSAGE_BUFFER_DATA1_INDEX],
  606. aucTransmitBuffer[MESSAGE_BUFFER_DATA2_INDEX],
  607. aucTransmitBuffer[MESSAGE_BUFFER_DATA3_INDEX],
  608. aucTransmitBuffer[MESSAGE_BUFFER_DATA4_INDEX],
  609. aucTransmitBuffer[MESSAGE_BUFFER_DATA5_INDEX],
  610. aucTransmitBuffer[MESSAGE_BUFFER_DATA6_INDEX],
  611. aucTransmitBuffer[MESSAGE_BUFFER_DATA7_INDEX],
  612. aucTransmitBuffer[MESSAGE_BUFFER_DATA8_INDEX]);
  613. }
  614. break;
  615. }
  616. case EVENT_TRANSFER_TX_COMPLETED:
  617. {
  618. printf("Tranfer Completed\n");
  619. break;
  620. }
  621. case EVENT_TRANSFER_TX_FAILED:
  622. {
  623. printf("Tranfer Failed\n");
  624. break;
  625. }
  626. case EVENT_QUE_OVERFLOW:
  627. case EVENT_SERIAL_QUE_OVERFLOW:
  628. break;
  629. case EVENT_CHANNEL_COLLISION:
  630. {
  631. printf("Channel Collision\n");
  632. break;
  633. }
  634. default:
  635. {
  636. printf("Unhandled channel event: 0x%X\n", stMessage.aucData[2]);
  637. break;
  638. }
  639. }
  640. break;
  641. }
  642. default:
  643. {
  644. printf("Unhandled response 0%d to message 0x%X\n", stMessage.aucData[2], stMessage.aucData[1]);
  645. break;
  646. }
  647. }
  648. break;
  649. }
  650. case MESG_RX_EXT_MESGS_ENABLE_ID:
  651. break;
  652. case MESG_STARTUP_MESG_ID:
  653. {
  654. printf("RESET Complete, reason: ");
  655. UCHAR ucReason = stMessage.aucData[MESSAGE_BUFFER_DATA1_INDEX];
  656. if(ucReason == RESET_POR)
  657. printf("RESET_POR");
  658. if(ucReason & RESET_SUSPEND)
  659. printf("RESET_SUSPEND ");
  660. if(ucReason & RESET_SYNC)
  661. printf("RESET_SYNC ");
  662. if(ucReason & RESET_CMD)
  663. printf("RESET_CMD ");
  664. if(ucReason & RESET_WDT)
  665. printf("RESET_WDT ");
  666. if(ucReason & RESET_RST)
  667. printf("RESET_RST ");
  668. printf("\n");
  669. ullStartupTime = GetTickCount64(); //On reset, the device should start counting uptime again
  670. break;
  671. }
  672. default:
  673. {
  674. break;
  675. }
  676. }
  677. return;
  678. }