BikeSpdCadSensor.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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 "BikeSpdCadSensor.h"
  10. /**************************************************************************
  11. * BikeSpdCadSensor::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 BikeSpdCadSensor::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. * BikeSpdCadSensor::InitializeSim
  35. *
  36. * Initializes simulator variables
  37. *
  38. * returns: N/A
  39. *
  40. **************************************************************************/
  41. void BikeSpdCadSensor::InitializeSim()
  42. {
  43. // Simulation Timer
  44. ulRunTime16000 = 0;
  45. ulTimerInterval = 247; // First event, before cadence/speed events, to initialize sim data
  46. ulNextCadInterval = 667; //90 rpm
  47. ulNextSpdInterval = 248; //30kph, 207cm wheel
  48. // Cadence
  49. usCadEventCount = 0;
  50. usCadTime1024 = 0;
  51. ucCurCadence = (UCHAR)this->numericUpDown_Sim_CadCurOutput->Value; // Default current cadence is set on UI
  52. ucMinCadence = (UCHAR)this->numericUpDown_Sim_CadMinOutput->Value; // Default minimum cadence is set on UI
  53. ucMaxCadence = (UCHAR)this->numericUpDown_Sim_CadMaxOutput->Value; // Default maximum cadence is set on UI
  54. ucCadSimDataType = SIM_FIXED;
  55. bCadSweepAscending = TRUE;
  56. // Speed
  57. usSpdEventCount = 0;
  58. usSpdTime1024 = 0;
  59. ulCurSpeed = (ULONG) (System::Convert::ToDouble(this->numericUpDown_Sim_SpdCurOutput->Value) * 1000); // Initial value set on UI (km/h -> meter/h)
  60. ulMinSpeed = (ULONG) (System::Convert::ToDouble(this->numericUpDown_Sim_SpdMinOutput->Value) * 1000); // Initial value set on UI (km/h -> meter/h)
  61. ulMaxSpeed = (ULONG) (System::Convert::ToDouble(this->numericUpDown_Sim_SpdMaxOutput->Value) * 1000); // Initial value set on UI (km/h -> meter/h)
  62. ucWheelCircumference = System::Convert::ToByte(this->numericUpDown_Sim_WheelCircumference->Value); // Initial value set on UI
  63. ucSpdSimDataType = SIM_FIXED;
  64. bSpdSweepAscending = TRUE;
  65. }
  66. /**************************************************************************
  67. * BikeSpdCadSensor::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 BikeSpdCadSensor::HandleTransmit(UCHAR* pucTxBuffer_)
  77. {
  78. // Transmission is always the same page
  79. pucTxBuffer_[0] = (UCHAR) (usCadTime1024 & 0xFF);
  80. pucTxBuffer_[1] = (UCHAR) (usCadTime1024 >> 8) & 0xFF;
  81. pucTxBuffer_[2] = (UCHAR) (usCadEventCount & 0xFF);
  82. pucTxBuffer_[3] = (UCHAR) (usCadEventCount >> 8) & 0xFF;
  83. pucTxBuffer_[4] = (UCHAR) (usSpdTime1024 & 0xFF);
  84. pucTxBuffer_[5] = (UCHAR) (usSpdTime1024 >> 8) & 0xFF;
  85. pucTxBuffer_[6] = (UCHAR) (usSpdEventCount & 0xFF);
  86. pucTxBuffer_[7] = (UCHAR) (usSpdEventCount >> 8) & 0xFF;
  87. }
  88. /**************************************************************************
  89. * BikeSpdCadSensor::onTimerTock
  90. *
  91. * Simulates a device event, updating simulator data based on this event
  92. * Modifications to the timer interval are applied immediately after this
  93. * at ANTChannel
  94. *
  95. * usEventTime_: current time (ms)
  96. *
  97. * returns: N/A
  98. *
  99. **************************************************************************/
  100. void BikeSpdCadSensor::onTimerTock(USHORT eventTime)
  101. {
  102. // Update master time
  103. ulRunTime16000 += (ulTimerInterval << 4); // Multiply by 16 to convert from ms to 1/16000s
  104. // Handle event and calculate time until next cadence/speed event
  105. if(ulNextCadInterval < ulNextSpdInterval) // Cadence event
  106. {
  107. // Update event count
  108. ++usCadEventCount;
  109. // Update event time
  110. usCadTime1024 = (USHORT) ((ulRunTime16000 << 3) / 125); // Convert to 1/1024s - multiply by 1024/16000
  111. switch(ucCadSimDataType)
  112. {
  113. case SIM_FIXED:
  114. // Value does not change
  115. break;
  116. case SIM_SWEEP:
  117. {
  118. // Cadence sweeps between min and max
  119. // 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
  120. ULONG tempOffset = ucMaxCadence-ucCurCadence;
  121. tempOffset = ((tempOffset & 0xC0) >> 6) + ((tempOffset & 0x20) >>5) + ((tempOffset & 0x10) >>4)+1;
  122. if(bCadSweepAscending)
  123. ucCurCadence += (UCHAR) tempOffset;
  124. else
  125. ucCurCadence -= (UCHAR) tempOffset;
  126. // Ensure next value is not less than min or more than max
  127. if(ucCurCadence >= ucMaxCadence)
  128. {
  129. ucCurCadence = ucMaxCadence;
  130. bCadSweepAscending = FALSE;
  131. }
  132. if(ucCurCadence <= ucMinCadence)
  133. {
  134. ucCurCadence = ucMinCadence;
  135. bCadSweepAscending = TRUE;
  136. }
  137. break;
  138. }
  139. default:
  140. break;
  141. }
  142. // Adjust speed interval with the time already elapsed in cadence event
  143. ulNextSpdInterval -= ulNextCadInterval;
  144. // Update cadence time interval (in ms)
  145. if(ucCurCadence)
  146. ulNextCadInterval = (ULONG) 60000/ucCurCadence; // 60 seconds/revolutions per minute
  147. else
  148. ulNextCadInterval = 600000; // coasting (no events, setting interval to a very large value)
  149. // Find out which event will occur next
  150. if(ulNextCadInterval < ulNextSpdInterval)
  151. ulTimerInterval = ulNextCadInterval;
  152. else
  153. ulTimerInterval = ulNextSpdInterval;
  154. }
  155. else // Speed event
  156. {
  157. // Update event count
  158. ++usSpdEventCount;
  159. // Update event time
  160. usSpdTime1024 = (USHORT) ((ulRunTime16000 << 3) / 125); // Convert to 1/1024s - multiply by 1024/16000
  161. switch(ucSpdSimDataType)
  162. {
  163. case SIM_FIXED:
  164. // Speed value does not change
  165. break;
  166. case SIM_SWEEP:
  167. {
  168. // Cadence sweeps between min and max
  169. // 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
  170. ULONG tempOffset = ulMaxSpeed-ulCurSpeed;
  171. tempOffset = ((tempOffset & 0x7000) >> 6) + ((tempOffset & 0xE00) >> 5) + ((tempOffset & 0x1C) >> 4)+0x7F;
  172. if(bSpdSweepAscending)
  173. ulCurSpeed += tempOffset;
  174. else
  175. ulCurSpeed -= tempOffset;
  176. // Ensure value is not less than min or more than max
  177. if(ulCurSpeed >= ulMaxSpeed)
  178. {
  179. ulCurSpeed = ulMaxSpeed;
  180. bSpdSweepAscending = FALSE;
  181. }
  182. if(ulCurSpeed <= ulMinSpeed)
  183. {
  184. ulCurSpeed = ulMinSpeed;
  185. bSpdSweepAscending = TRUE;
  186. }
  187. break;
  188. }
  189. default:
  190. break;
  191. }
  192. // Adjust cadence interval with the time already elapsed in speed event
  193. ulNextCadInterval -= ulNextSpdInterval;
  194. // Update speed time interval (in ms)
  195. if(ulCurSpeed)
  196. ulNextSpdInterval = (ULONG) 36000 * ucWheelCircumference/ulCurSpeed; // in ms (wheel circumference is in cm, speed in meter/h)
  197. else
  198. ulNextSpdInterval = 600000; // Stopping (no events, setting interval to a very large value)
  199. //Find out which event will occur next
  200. if(ulNextSpdInterval < ulNextCadInterval)
  201. ulTimerInterval = ulNextSpdInterval;
  202. else
  203. ulTimerInterval = ulNextCadInterval;
  204. }
  205. if(ulTimerInterval < 1) //this prevents timerInterval=0 if values are identical and could be used to prevent too short timer intervals
  206. ulTimerInterval = 1;
  207. UpdateDisplay();
  208. }
  209. /***************************************************************************
  210. * BikeSpdCadSensor::UpdateDisplay
  211. *
  212. * Updates displayed simulator data on GUI
  213. *
  214. * returns: N/A
  215. *
  216. **************************************************************************/
  217. void BikeSpdCadSensor::UpdateDisplay()
  218. {
  219. this->label_Trn_CadCountDisplay->Text = System::Convert::ToString(usCadEventCount); // Cadence event count
  220. this->label_Trn_CadenceTimeDisplay->Text = System::Convert::ToString(usCadTime1024); // Time of last cadence event (1/1024s)
  221. this->label_Trn_SpdCountDisplay->Text = System::Convert::ToString(usSpdEventCount); // Speed event cont
  222. this->label_Trn_SpeedTimeDisplay->Text = System::Convert::ToString(usSpdTime1024); // Time of last speed event (1/1024s)
  223. if(ucCadSimDataType == SIM_SWEEP) // Update only if it is changing
  224. this->numericUpDown_Sim_CadCurOutput->Value = ucCurCadence; // Current cadence generated by simulator (rpm)
  225. if(ucSpdSimDataType == SIM_SWEEP) // Update only if it is changing
  226. this->numericUpDown_Sim_SpdCurOutput->Value = System::Convert::ToDecimal((double) ulCurSpeed/1000); // Current speed generated, meters/h -> km/h
  227. }
  228. /**************************************************************************
  229. * BikeSpdCadSensor::numericUpDown_Sim_WheelCircumference_ValueChanged
  230. *
  231. * Updates wheel circumference value, if updated (either by the user or internally)
  232. * Validation is already performed by the numericUpDown control
  233. *
  234. * returns: N/A
  235. *
  236. **************************************************************************/
  237. System::Void BikeSpdCadSensor::numericUpDown_Sim_WheelCircumference_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  238. {
  239. ucWheelCircumference = System::Convert::ToByte(this->numericUpDown_Sim_WheelCircumference->Value);
  240. }
  241. /**************************************************************************
  242. * BikeSpdCadSensor::checkBox_Sim_SpeedSweeping_CheckedChanged
  243. *
  244. * Select method to generate simulator data, from user input (GUI)
  245. *
  246. * returns: N/A
  247. *
  248. **************************************************************************/
  249. System::Void BikeSpdCadSensor::checkBox_Sim_SpeedSweeping_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  250. {
  251. this->numericUpDown_Sim_SpdCurOutput->Enabled = !this->numericUpDown_Sim_SpdCurOutput->Enabled;
  252. this->numericUpDown_Sim_SpdMinOutput->Enabled = !this->numericUpDown_Sim_SpdMinOutput->Enabled;
  253. this->numericUpDown_Sim_SpdMaxOutput->Enabled = !this->numericUpDown_Sim_SpdMaxOutput->Enabled;
  254. if(this->checkBox_Sim_SpdSweeping->Checked)
  255. {
  256. bSpdSweepAscending = TRUE;
  257. ucSpdSimDataType = SIM_SWEEP;
  258. }
  259. else
  260. {
  261. ucSpdSimDataType = SIM_FIXED;
  262. }
  263. }
  264. /**************************************************************************
  265. * BikeSpdCadSensor::checkBox_Sim_CadenceSweeping_CheckedChanged
  266. *
  267. * Select method to generate simulator data, from user input (GUI)
  268. *
  269. * returns: N/A
  270. *
  271. **************************************************************************/
  272. System::Void BikeSpdCadSensor::checkBox_Sim_CadenceSweeping_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  273. {
  274. this->numericUpDown_Sim_CadCurOutput->Enabled = !this->numericUpDown_Sim_CadCurOutput->Enabled;
  275. this->numericUpDown_Sim_CadMinOutput->Enabled = !this->numericUpDown_Sim_CadMinOutput->Enabled;
  276. this->numericUpDown_Sim_CadMaxOutput->Enabled = !this->numericUpDown_Sim_CadMaxOutput->Enabled;
  277. if(this->checkBox_Sim_CadSweeping->Checked)
  278. {
  279. bCadSweepAscending = TRUE;
  280. ucCadSimDataType = SIM_SWEEP;
  281. }
  282. else
  283. {
  284. ucCadSimDataType = SIM_FIXED;
  285. }
  286. }
  287. /**************************************************************************
  288. * BikeSpdCadSensor::numericUpDown_Sim_SpdCurOutput_ValueChanged
  289. *
  290. * Validates and updates the current speed, from user input (GUI)
  291. *
  292. * returns: N/A
  293. *
  294. **************************************************************************/
  295. System::Void BikeSpdCadSensor::numericUpDown_Sim_SpdCurOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  296. {
  297. // This value is raised whenever the value changes, even if internally
  298. // Only update the current pulse if set by the user
  299. if(this->numericUpDown_Sim_SpdCurOutput->Enabled)
  300. {
  301. ulCurSpeed = (ULONG) (System:: Convert::ToDouble(this->numericUpDown_Sim_SpdCurOutput->Value) * 1000); // km/h -> meter/h
  302. if(ulCurSpeed)
  303. ulNextSpdInterval = (ULONG) 36000 * ucWheelCircumference/ulCurSpeed; // in ms (wheel circumference is in cm, speed in meter/h)
  304. else
  305. ulNextSpdInterval = 600000; // Stopping (no speed events in a very long time, so display can interpret it as stopping)
  306. ForceUpdate();
  307. }
  308. }
  309. /**************************************************************************
  310. * BikeSpdCad::numericUpDown_Sim_SpdMinMaxOutput_ValueChanged
  311. *
  312. * If the user has changed the min or max speed, validate that
  313. * minimum < current < maximum
  314. *
  315. * returns: N/A
  316. *
  317. **************************************************************************/
  318. System::Void BikeSpdCadSensor::numericUpDown_Sim_SpdMinMaxOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  319. {
  320. ULONG ulPrevSpeed = ulCurSpeed;
  321. // This event is raised whenever the min and max value change, even if internally
  322. // Check min<max if in min/max mode, and force min<cur<max
  323. if(this->numericUpDown_Sim_SpdMinOutput->Value < this->numericUpDown_Sim_SpdMaxOutput->Value)
  324. {
  325. ulMinSpeed = (ULONG) (System::Convert::ToDouble(this->numericUpDown_Sim_SpdMinOutput->Value) * 1000); // km/h -> meters/h
  326. ulMaxSpeed = (ULONG) (System::Convert::ToDouble(this->numericUpDown_Sim_SpdMaxOutput->Value) * 1000); // km/h -> meters/h
  327. if(ulCurSpeed > ulMaxSpeed)
  328. ulCurSpeed = ulMaxSpeed;
  329. else if(ulCurSpeed < ulMinSpeed)
  330. ulCurSpeed = ulMinSpeed;
  331. if(ulCurSpeed != ulPrevSpeed)
  332. {
  333. this->numericUpDown_Sim_SpdCurOutput->Value = System::Convert::ToDecimal((double) ulCurSpeed/1000); // meters/h -> km/h
  334. if(ulCurSpeed)
  335. ulNextSpdInterval = (ULONG) 36000 * ucWheelCircumference/ulCurSpeed; // in ms (wheel circumference is in cm, speed in meter/h)
  336. else
  337. ulNextSpdInterval = 600000; // Stopping (no speed events in a very long time, so display can interpret it as stopping)
  338. ForceUpdate();
  339. }
  340. }
  341. else
  342. {
  343. // If the values were invalid, set numeric values to last valid values
  344. this->numericUpDown_Sim_SpdMinOutput->Value = System::Convert::ToDecimal((double) ulMinSpeed/1000); // meters/h -> km/h
  345. this->numericUpDown_Sim_SpdMaxOutput->Value = System::Convert::ToDecimal((double) ulMaxSpeed/1000); // meters/h -> km/h
  346. }
  347. }
  348. /**************************************************************************
  349. * BikeSpdCadSensor::numericUpDown_Sim_CadCurOutput_ValueChanged
  350. *
  351. * Validates and updates the current cadence, from user input (GUI)
  352. *
  353. * returns: N/A
  354. *
  355. **************************************************************************/
  356. System::Void BikeSpdCadSensor::numericUpDown_Sim_CadCurOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  357. {
  358. // This value is raised whenever the value changes, even if internally
  359. // Only update the current pulse if set by the user
  360. if(this->numericUpDown_Sim_CadCurOutput->Enabled)
  361. {
  362. ucCurCadence = System::Convert::ToByte(this->numericUpDown_Sim_CadCurOutput->Value);
  363. if(ucCurCadence)
  364. ulNextCadInterval = (ULONG) 60000/ucCurCadence; // 60 seconds/revolutions per minute
  365. else
  366. ulNextCadInterval = 600000; // Coasting (no cadence events in a very long time so that display can interpret as coasting)
  367. ForceUpdate();
  368. }
  369. }
  370. /**************************************************************************
  371. * BikeSpdCad::numericUpDown_Sim_CadMinMaxOutput_ValueChanged
  372. *
  373. * If the user has changed the min or max cadence, validate that
  374. * minimum < current < maximum
  375. *
  376. * returns: N/A
  377. *
  378. **************************************************************************/
  379. System::Void BikeSpdCadSensor::numericUpDown_Sim_CadMinMaxOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  380. {
  381. UCHAR ucPrevCadence = ucCurCadence;
  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_CadMinOutput->Value < this->numericUpDown_Sim_CadMaxOutput->Value)
  385. {
  386. ucMinCadence = (UCHAR) this->numericUpDown_Sim_CadMinOutput->Value;
  387. ucMaxCadence = (UCHAR) this->numericUpDown_Sim_CadMaxOutput->Value;
  388. if(ucCurCadence > ucMaxCadence)
  389. ucCurCadence = ucMaxCadence;
  390. else if(ucCurCadence < ucMinCadence)
  391. ucCurCadence = ucMinCadence;
  392. if(ucCurCadence != ucPrevCadence)
  393. {
  394. this->numericUpDown_Sim_CadCurOutput->Value = ucCurCadence;
  395. if(ucCurCadence)
  396. ulNextCadInterval = (ULONG) 60000/ucCurCadence; // 60 seconds/revolutions per minute
  397. else
  398. ulNextCadInterval = 600000; // Coasting (no cadence events in a very long time so that display can interpret as coasting)
  399. ForceUpdate();
  400. }
  401. }
  402. else
  403. {
  404. // If the values were invalid, set numeric values to last valid values
  405. this->numericUpDown_Sim_CadMinOutput->Value = ucMinCadence;
  406. this->numericUpDown_Sim_CadMaxOutput->Value = ucMaxCadence;
  407. }
  408. }
  409. /**************************************************************************
  410. * BikeSpdCad::ForceUpdate
  411. *
  412. * Causes a timer event, to force the simulator to update all calculations
  413. *
  414. * returns: N/A
  415. *
  416. **************************************************************************/
  417. void BikeSpdCadSensor::ForceUpdate()
  418. {
  419. timerHandle->Interval = 250;
  420. }