BikeSpeedSensor.cpp 18 KB

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