BikeCadenceSensor.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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. 2012
  6. All rights reserved.
  7. */
  8. #include "StdAfx.h"
  9. #include "BikeCadenceSensor.h"
  10. /**************************************************************************
  11. * BikeCadenceSensor::ANT_eventNotification
  12. *
  13. * Process ANT channel event
  14. *
  15. * ucEventCode_: code of ANT channel event
  16. * pucEventBuffer_: pointer to buffer containing data received from ANT,
  17. * or a pointer to the transmit buffer in the case of an EVENT_TX
  18. *
  19. * returns: N/A
  20. *
  21. **************************************************************************/
  22. void BikeCadenceSensor::ANT_eventNotification(UCHAR ucEventCode_, UCHAR* pucEventBuffer_)
  23. {
  24. switch(ucEventCode_)
  25. {
  26. case EVENT_TX:
  27. HandleTransmit((UCHAR*) pucEventBuffer_);
  28. break;
  29. default:
  30. break;
  31. }
  32. }
  33. /**************************************************************************
  34. * BikeCadenceSensor::InitializeSim
  35. *
  36. * Initializes simulator variables
  37. *
  38. * returns: N/A
  39. *
  40. **************************************************************************/
  41. void BikeCadenceSensor::InitializeSim()
  42. {
  43. // Simulation timer
  44. ulTimerInterval = 667; //90rpm
  45. // Initialization of simulator variables
  46. ulRunTime = 0;
  47. ulRunTime16000 = 0;
  48. ucReserved = BC_RESERVED;
  49. usEventCount = 0;
  50. ucMinCadence = (UCHAR)this->numericUpDown_Sim_MinCadence->Value; // Default minimum cadence is set on UI
  51. ucCurCadence = (UCHAR)this->numericUpDown_Sim_CurrentCadence->Value; // Default current cadence is set on UI
  52. ucMaxCadence = (UCHAR)this->numericUpDown_Sim_MaxCadence->Value; // Default maximum cadence is set on UI
  53. ulElapsedTime2 = 0;
  54. usTime1024 = 0;
  55. // Common Pages (set on UI)
  56. ucMfgID = System::Convert::ToByte(this->textBox_ManfIDChange->Text);
  57. ucHwVersion = System::Convert::ToByte(this->textBox_HardwareVerChange->Text);
  58. ucSwVersion = System::Convert::ToByte(this->textBox_SoftwareVerChange->Text);
  59. ucModelNum = System::Convert::ToByte(this->textBox_ModelNumChange->Text);
  60. usSerialNum = System::Convert::ToUInt16(this->textBox_SerialNumChange->Text);
  61. // Status
  62. ucSimDataType = SIM_FIXED; // Generate single fixed heart rate value by default
  63. bLegacy = FALSE; // Disable legacy mode by default
  64. bTxMinimum = FALSE; // Transmit full data set by default
  65. bSweepAscending = TRUE; // If sweeping, start with ascending values by default
  66. ucBackgroundCount = 0;
  67. ucNextBackgroundPage = BC_PAGE1; // By default, support all defined pages
  68. }
  69. /**************************************************************************
  70. * BikeCadenceSensor::HandleTransmit
  71. *
  72. * Encode data generated by simulator for transmission
  73. *
  74. * pucTxBuffer_: pointer to the transmit buffer
  75. *
  76. * returns: N/A
  77. *
  78. **************************************************************************/
  79. void BikeCadenceSensor::HandleTransmit(UCHAR* pucTxBuffer_)
  80. {
  81. static UCHAR ucMessageNum = 0; // Message count
  82. static UCHAR ucPageToggle = 0; // Page toggle tracker
  83. UCHAR ucPageNum = BC_PAGE0; // Page number
  84. // Send global pages every 65th message (not available in legacy sensors)
  85. if(!bLegacy)
  86. {
  87. if(ucMessageNum++ == BC_BACKGROUND_INTERVAL-1)
  88. {
  89. ucMessageNum = 0;
  90. switch(ucNextBackgroundPage)
  91. {
  92. case 1:
  93. ucPageNum = BC_PAGE1;
  94. ucNextBackgroundPage++;
  95. break;
  96. case 2:
  97. ucPageNum = BC_PAGE2;
  98. if(bTxMinimum)
  99. {
  100. // If using minimum data set, background pages are sent three times to ensure they are received by displays with lower message rate
  101. if(++ucBackgroundCount > 2)
  102. {
  103. ucBackgroundCount = 0;
  104. ucNextBackgroundPage ++;
  105. }
  106. }
  107. else
  108. {
  109. // Otherwise, send only once
  110. ucNextBackgroundPage++;
  111. }
  112. break;
  113. case 3:
  114. ucPageNum = BC_PAGE3;
  115. if(bTxMinimum)
  116. {
  117. // If using minimum data set, background pages are sent three times to ensure they are received by displays with lower message rate
  118. if(++ucBackgroundCount > 2)
  119. {
  120. ucBackgroundCount = 0;
  121. ucNextBackgroundPage = BC_PAGE2;
  122. }
  123. }
  124. else
  125. {
  126. // Otherwise, send only once
  127. ucNextBackgroundPage = BC_PAGE1;
  128. }
  129. break;
  130. default:
  131. break;
  132. }
  133. }
  134. }
  135. // Fill in common info
  136. if(!bLegacy)
  137. pucTxBuffer_[0] = ucPageNum;
  138. else
  139. pucTxBuffer_[0] = ucReserved; // Legacy sensors only, do not interpret at receiver, do not use as reference for new sensor designs
  140. pucTxBuffer_[4] = (UCHAR) (usTime1024 & 0xFF);
  141. pucTxBuffer_[5] = (UCHAR) (usTime1024 >> 8) & 0xFF;
  142. pucTxBuffer_[6] = (UCHAR) (usEventCount & 0xFF);
  143. pucTxBuffer_[7] = (UCHAR) (usEventCount >> 8) & 0xFF;
  144. // Page specific info
  145. switch(ucPageNum)
  146. {
  147. case BC_PAGE0:
  148. pucTxBuffer_[1] = ucReserved; // Reserved, do not interpret at the receiver
  149. pucTxBuffer_[2] = ucReserved; // Reserved, do not interpret at the receiver
  150. pucTxBuffer_[3] = ucReserved; // Reserved, do not interpret at the receiver
  151. break;
  152. case BC_PAGE1:
  153. pucTxBuffer_[1] = (ulElapsedTime2 & 0xFF); // Cumulative operating time, bits 0-7 (intervals of 2s)
  154. pucTxBuffer_[2] = (ulElapsedTime2 >> 8) & 0xFF; // Cumulative operating time, bits 8-15 (intervals of 2s)
  155. pucTxBuffer_[3] = (ulElapsedTime2 >> 16) & 0xFF; // Cumulative operating time, bits 16-23 (intervals of 2s)
  156. break;
  157. case BC_PAGE2:
  158. pucTxBuffer_[1] = ucMfgID; // Manufacturing ID
  159. pucTxBuffer_[2] = usSerialNum & 0x00FF; // Low byte of serial number
  160. pucTxBuffer_[3] = (usSerialNum & 0xFF00) >>8; // High byte of serial number
  161. break;
  162. case BC_PAGE3:
  163. pucTxBuffer_[1] = ucHwVersion; // Hardware version
  164. pucTxBuffer_[2] = ucSwVersion; // Software version
  165. pucTxBuffer_[3] = ucModelNum; // Model number
  166. break;
  167. default:
  168. break;
  169. }
  170. // Handle page toggle bit: toggle every four messages
  171. if(!bLegacy)
  172. {
  173. ucPageToggle += 0x20;
  174. pucTxBuffer_[0] += (ucPageToggle & BC_TOGGLE_MASK);
  175. }
  176. }
  177. /**************************************************************************
  178. * BikeCadenceSensor::onTimerTock
  179. *
  180. * Simulates a device event, updating simulator data based on this event
  181. * Modifications to the timer interval are applied immediately after this
  182. * at ANTChannel
  183. *
  184. * usEventTime_: current time (ms)
  185. *
  186. * returns: N/A
  187. *
  188. **************************************************************************/
  189. void BikeCadenceSensor::onTimerTock(USHORT eventTime)
  190. {
  191. UCHAR tempOffset = 0; // Temporary variable to calculate sweeping intervals
  192. // Update event count
  193. ++usEventCount;
  194. // Update event time
  195. ulRunTime16000 += (ulTimerInterval << 4); // Multiply by 16 to convert from ms to 1/16000s
  196. usTime1024 = (USHORT) ((ulRunTime16000 << 3) / 125); // Convert to 1/1024s - multiply by 1024/16000
  197. ulRunTime += ulTimerInterval;
  198. while(ulRunTime/2000) // 2000 ms
  199. {
  200. ++ulElapsedTime2; // elapsed time is updated every 2 seconds
  201. ulRunTime -=2000;
  202. }
  203. switch(ucSimDataType)
  204. {
  205. case SIM_FIXED:
  206. // Cadence value does not change
  207. break;
  208. case SIM_SWEEP:
  209. // Cadence sweeps between min and max
  210. // The jump offset is calculated versus position against the max so it won't get stuck on low values for a long time and won't speed through high values too fast
  211. tempOffset = ucMaxCadence-ucCurCadence;
  212. tempOffset = ((tempOffset & 0xC0) >> 6) + ((tempOffset & 0x20) >>5) + ((tempOffset & 0x10) >>4)+1;
  213. if(bSweepAscending)
  214. ucCurCadence += tempOffset;
  215. else
  216. ucCurCadence -= tempOffset;
  217. // Ensure value is not larger than max or smaller than min
  218. if(ucCurCadence >= ucMaxCadence)
  219. {
  220. ucCurCadence = ucMaxCadence;
  221. bSweepAscending = FALSE;
  222. }
  223. if(ucCurCadence <= ucMinCadence)
  224. {
  225. ucCurCadence = ucMinCadence;
  226. bSweepAscending = TRUE;
  227. }
  228. break;
  229. default:
  230. break;
  231. }
  232. // Update timer interval (in ms)
  233. if(ucCurCadence)
  234. ulTimerInterval = (ULONG) 60000/ucCurCadence; // 60 seconds/revolutions per minute
  235. else
  236. ulTimerInterval = 600000; // Coasting, set interval to a very large value
  237. // Update display
  238. UpdateDisplay();
  239. }
  240. /***************************************************************************
  241. * BikeCadenceSensor::UpdateDisplay
  242. *
  243. * Updates displayed simulator data on GUI
  244. *
  245. * returns: N/A
  246. *
  247. **************************************************************************/
  248. void BikeCadenceSensor::UpdateDisplay()
  249. {
  250. this->label_Trn_EventCountDisplay->Text = usEventCount.ToString(); // Event count
  251. this->label_ElapsedSecsDisplay->Text = ((ulElapsedTime2 & 0x00FFFFFF) << 1).ToString(); // Operating time (s)
  252. if(ucSimDataType == SIM_SWEEP) // Update only if it is changing
  253. this->numericUpDown_Sim_CurrentCadence->Value = ucCurCadence; // Current cadence generated by simulator (rpm)
  254. this->label_Trn_TimeDisplay->Text = usTime1024.ToString(); // Time of last event (1/1024s)
  255. }
  256. /**************************************************************************
  257. * BikeCadenceSensor::radioButton_SimTypeChanged
  258. *
  259. * Select method to generate simulator data, from user input (GUI)
  260. *
  261. * returns: N/A
  262. *
  263. **************************************************************************/
  264. void BikeCadenceSensor::radioButton_SimTypeChanged (System::Object^ sender, System::EventArgs^ e)
  265. {
  266. this->numericUpDown_Sim_CurrentCadence->Enabled = !this->numericUpDown_Sim_CurrentCadence->Enabled;
  267. this->numericUpDown_Sim_MaxCadence->Enabled = !this->numericUpDown_Sim_MaxCadence->Enabled;
  268. this->numericUpDown_Sim_MinCadence->Enabled = !this->numericUpDown_Sim_MinCadence->Enabled;
  269. if(this->radioButton_Sim_Fixed->Checked)
  270. {
  271. ucSimDataType = SIM_FIXED;
  272. }
  273. else if(this->radioButton_Sim_Sweep->Checked)
  274. {
  275. bSweepAscending = TRUE;
  276. ucSimDataType = SIM_SWEEP;
  277. }
  278. }
  279. /**************************************************************************
  280. * BikeCadenceSensor::button_AdvancedUpdate_Click
  281. *
  282. * Validates and updates product information, from user input (GUI)
  283. *
  284. * returns: N/A
  285. *
  286. **************************************************************************/
  287. System::Void BikeCadenceSensor::button_AdvancedUpdate_Click(System::Object^ sender, System::EventArgs^ e)
  288. {
  289. label_AdvancedError->Visible = false;
  290. label_AdvancedError->Text = "Error: ";
  291. //convert and catch failed conversions
  292. try{
  293. ucMfgID = System::Convert::ToByte(this->textBox_ManfIDChange->Text);
  294. }
  295. catch(...){
  296. label_AdvancedError->Text = System::String::Concat(label_AdvancedError->Text, " MFID");
  297. label_AdvancedError->Visible = true;
  298. }
  299. try{
  300. usSerialNum = System::Convert::ToUInt16(this->textBox_SerialNumChange->Text);
  301. }
  302. catch(...){
  303. label_AdvancedError->Text = System::String::Concat(label_AdvancedError->Text, " Ser#");
  304. label_AdvancedError->Visible = true;
  305. }
  306. try{
  307. ucHwVersion = System::Convert::ToByte(this->textBox_HardwareVerChange->Text);
  308. }
  309. catch(...){
  310. label_AdvancedError->Text = System::String::Concat(label_AdvancedError->Text, " HWVr");
  311. label_AdvancedError->Visible = true;
  312. }
  313. try{
  314. ucSwVersion = System::Convert::ToByte(this->textBox_SoftwareVerChange->Text);
  315. }
  316. catch(...){
  317. label_AdvancedError->Text = System::String::Concat(label_AdvancedError->Text, " SWVr");
  318. label_AdvancedError->Visible = true;
  319. }
  320. try{
  321. ucModelNum = System::Convert::ToByte(this->textBox_ModelNumChange->Text);
  322. }
  323. catch(...){
  324. label_AdvancedError->Text = System::String::Concat(label_AdvancedError->Text, " Mdl#");
  325. label_AdvancedError->Visible = true;
  326. }
  327. }
  328. /**************************************************************************
  329. * BikeCadenceSensor::button_UpdateTime_Click
  330. *
  331. * Validates and updates cumulative operating time, from user input (GUI)
  332. *
  333. * returns: N/A
  334. *
  335. **************************************************************************/
  336. System::Void BikeCadenceSensor::button_UpdateTime_Click(System::Object^ sender, System::EventArgs^ e)
  337. {
  338. ULONG ulCumulativeTime = 0;
  339. label_AdvancedError->Visible = false;
  340. try
  341. {
  342. ulCumulativeTime = System::Convert::ToUInt32(this->textBox_ElpTimeChange->Text);
  343. if(ulCumulativeTime > 33554430) // Cumulative Operating Time rollover: 2 * 0xFFFFFF = 33554430 seconds
  344. throw "Cumulative operating time exceeds rollover value";
  345. ulElapsedTime2 = ulCumulativeTime >> 1; // Cumulative time is stored in intervals of 2 seconds
  346. // Update display (in seconds)
  347. label_ElapsedSecsDisplay->Text = ((ulElapsedTime2 & 0x00FFFFFF) << 1).ToString();
  348. }
  349. catch(...)
  350. {
  351. label_AdvancedError->Text = "Error: Time";
  352. label_AdvancedError->Visible = true;
  353. }
  354. }
  355. /**************************************************************************
  356. * BikeCadenceSensor::numericUpDown_Sim_CurCadence_ValueChanged
  357. *
  358. * Validates and updates the current cadence, from user input (GUI)
  359. *
  360. * returns: N/A
  361. *
  362. **************************************************************************/
  363. System::Void BikeCadenceSensor::numericUpDown_Sim_CurCadence_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  364. {
  365. // This value is raised whenever the value changes, even if internally
  366. // Only update the current pulse if set by the user
  367. if(this->numericUpDown_Sim_CurrentCadence->Enabled)
  368. {
  369. ucCurCadence = (UCHAR)this->numericUpDown_Sim_CurrentCadence->Value;
  370. ForceUpdate();
  371. }
  372. }
  373. /**************************************************************************
  374. * BikeCadenceSensor::numericUpDown_Sim_MinMaxCadence_ValueChanged
  375. *
  376. * If the user has changed the min or max cadence, validate that
  377. * minimum < current < maximum
  378. *
  379. * returns: N/A
  380. *
  381. **************************************************************************/
  382. System::Void BikeCadenceSensor::numericUpDown_Sim_MinMaxCadence_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  383. {
  384. UCHAR ucPrevCadence = ucCurCadence;
  385. // This event is raised whenever the min and max value change, even if internally
  386. // Check min<max if in min/max mode, and force min<cur<max
  387. if(this->numericUpDown_Sim_MinCadence->Value < this->numericUpDown_Sim_MaxCadence->Value)
  388. {
  389. ucMinCadence = (UCHAR)this->numericUpDown_Sim_MinCadence->Value;
  390. ucMaxCadence = (UCHAR)this->numericUpDown_Sim_MaxCadence->Value;
  391. if(ucCurCadence > ucMaxCadence)
  392. ucCurCadence = ucMaxCadence;
  393. else if(ucCurCadence < ucMinCadence)
  394. ucCurCadence = ucMinCadence;
  395. if(ucCurCadence != ucPrevCadence)
  396. {
  397. this->numericUpDown_Sim_CurrentCadence->Value = ucCurCadence;
  398. ForceUpdate();
  399. }
  400. }
  401. else
  402. {
  403. // If the values were invalid, set numeric values to last valid values
  404. this->numericUpDown_Sim_MinCadence->Value = ucMinCadence;
  405. this->numericUpDown_Sim_MaxCadence->Value = ucMaxCadence;
  406. }
  407. }
  408. /**************************************************************************
  409. * BikeCadenceSensor::checkBox_Legacy_CheckedChanged
  410. *
  411. * Enable simulation of legacy sensors for testing backward compatibility of receivers
  412. *
  413. * returns: N/A
  414. *
  415. **************************************************************************/
  416. System::Void BikeCadenceSensor::checkBox_Legacy_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  417. {
  418. // Enable simulation of legacy sensors for testing backward compatibility of receivers
  419. if(checkBox_Legacy->Checked)
  420. {
  421. System::Windows::Forms::DialogResult result = MessageBox::Show(L"This option is available for backward compatibility testing.\nIt should not be used as a reference in the development of new sensors.", L"Warning", MessageBoxButtons::OKCancel);
  422. if( result == ::DialogResult::OK )
  423. {
  424. bLegacy = TRUE;
  425. // Generate random data for reserved field to simulate legacy receivers
  426. // This should not be interpreted by the receiver, and by no means should be used as a reference for new designs
  427. // This feature is avaialable only for testing backwards compatibility
  428. srand(ulElapsedTime2);
  429. ucReserved = (UCHAR) ((rand() % 240) + 16); // Generate a random number between 16 and 255
  430. checkBox_SendBasicPage->Checked = FALSE;
  431. checkBox_SendBasicPage->Enabled = FALSE;
  432. }
  433. else
  434. {
  435. bLegacy = FALSE;
  436. ucReserved = BC_RESERVED;
  437. checkBox_Legacy->Checked = FALSE;
  438. checkBox_SendBasicPage->Enabled = TRUE;
  439. }
  440. }
  441. else
  442. {
  443. bLegacy = FALSE;
  444. ucReserved = BC_RESERVED;
  445. checkBox_SendBasicPage->Enabled = TRUE;
  446. }
  447. }
  448. /**************************************************************************
  449. * BikeCadenceSensor::checkBox_SendBasicPage_CheckedChanged
  450. *
  451. * Selects transmission of minimum data set
  452. * Minimum data set does not include Page 1
  453. *
  454. * returns: N/A
  455. *
  456. **************************************************************************/
  457. System::Void BikeCadenceSensor::checkBox_SendBasicPage_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  458. {
  459. if(checkBox_SendBasicPage->Checked)
  460. {
  461. bTxMinimum = TRUE;
  462. ucNextBackgroundPage = BC_PAGE2; // Page 1 is disabled
  463. ucBackgroundCount = 0; // Reset background page count
  464. }
  465. else
  466. {
  467. bTxMinimum = FALSE;
  468. ucNextBackgroundPage = BC_PAGE1; // Enable Page 1
  469. ucBackgroundCount = 0; // Reset background page count
  470. }
  471. }
  472. /**************************************************************************
  473. * BikeCadenceSensor::ForceUpdate
  474. *
  475. * Causes a timer event, to force the simulator to update all calculations
  476. *
  477. * returns: N/A
  478. *
  479. **************************************************************************/
  480. void BikeCadenceSensor::ForceUpdate()
  481. {
  482. timerHandle->Interval = 250;
  483. }