BikePowerDisplay.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  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 "BikePowerDisplay.h"
  10. /**************************************************************************
  11. * BikePowerDisplay::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 BikePowerDisplay::ANT_eventNotification(UCHAR ucEventCode_, UCHAR* pucEventBuffer_)
  23. {
  24. switch(ucEventCode_)
  25. {
  26. case EVENT_RX_BURST_PACKET:
  27. case EVENT_RX_BROADCAST:
  28. case EVENT_RX_ACKNOWLEDGED: // Intentional fall thru
  29. HandleReceive((UCHAR*) pucEventBuffer_); // Decode current data
  30. break;
  31. case EVENT_TRANSFER_TX_COMPLETED:
  32. ucAckRetryCount = 0; // Reset retransmission counter
  33. ucMsgExpectingAck = 0; // Clear pending msg code
  34. UpdateDisplayAckStatus(ACK_SUCCESS); // Tx successful
  35. break;
  36. case EVENT_TRANSFER_TX_FAILED:
  37. case EVENT_ACK_TIMEOUT: // Intentional fall thru
  38. if(ucMsgExpectingAck)
  39. {
  40. if(HandleRetransmit())
  41. UpdateDisplayAckStatus(ACK_RETRY); // Data was retransmitted
  42. else
  43. UpdateDisplayAckStatus(ACK_FAIL); // Maximum number of retries exceeded, Tx failed
  44. }
  45. break;
  46. default:
  47. break;
  48. }
  49. }
  50. /**************************************************************************
  51. * BikePowerDisplay::InitializeSim
  52. *
  53. * Initializes simulator variables
  54. *
  55. * returns: N/A
  56. *
  57. **************************************************************************/
  58. void BikePowerDisplay::InitializeSim()
  59. {
  60. bSeenPower = FALSE;
  61. bSeenWheelTorque = FALSE;
  62. bSeenCrankTorque = FALSE;
  63. bSeenCTF = FALSE;
  64. ePrevType = BikePower::SensorType::UNKNOWN;
  65. ulAcumPowerEventCount = 0;
  66. ulAcumTorqueEventCount = 0;
  67. ulAcumTicks = 0;
  68. ulDistance100 = 0;
  69. ucWheelCircumference100 = System::Convert::ToByte(this->numericUpDown_Cal_WheelCircum->Value); // Initial value set on UI (cm)
  70. usCTFOffset = 0; // Initial uncalibrated offset
  71. bAutoZeroInvalid = FALSE;
  72. bAZOn = (BOOL) this->radioButton_Cal_AZon->Checked; // Initial value set on UI
  73. usCalSerialToSend = System::Convert::ToUInt16(this->numericUpDown_Cal_CTFSerial->Value);
  74. usCalSlopeToSend = System::Convert::ToUInt16(10 * this->numericUpDown_Cal_CTFSlope->Value);
  75. ucMsgExpectingAck = 0;
  76. bCoasting = FALSE;
  77. bStopped = FALSE;
  78. }
  79. /**************************************************************************
  80. * BikePowerDisplay::HandleReceive
  81. *
  82. * Decodes received data
  83. *
  84. * pucRxBuffer_: pointer to the buffer containing the received data
  85. *
  86. * returns: N/A
  87. *
  88. **************************************************************************/
  89. void BikePowerDisplay::HandleReceive(UCHAR* pucRxBuffer_)
  90. {
  91. static USHORT usNoEventCount = 0; // Counter for successive transmissions with no new events
  92. // Power sensors
  93. static UCHAR ucPrevPowerEventCount = 0; // Previous value for the power event count
  94. static USHORT usPrevAcumPower = 0; // Previous value for the cumulative power (W)
  95. // Crank/wheel torque sensors
  96. static UCHAR ucPrevTorqueEventCount = 0; // Previous value for the torque event count
  97. static UCHAR ucPrevTicks = 0; // Previous number of revolutions (wheel or torque)
  98. static USHORT usPrevPeriod2048 = 0; // Previous period (wheel or torque), in 1/2048s
  99. static USHORT usPrevTorque32 = 0; // Previous torque (1/32 Nm)
  100. static UCHAR ucCurTorqueEventCount = 0; // Current torque event count
  101. static UCHAR ucCurTicks = 0; // Current number of ticks
  102. static USHORT usCurPeriod2048 = 0; // Current period
  103. static USHORT usCurTorque32 = 0; // Current torque
  104. // Crank torque frequency
  105. static UCHAR ucPrevCTFEventCount = 0; // Previous value for the crank torque frequency event count
  106. static USHORT usPrevTime2000 = 0; // Previous CTF time stamp (1/2000 s)
  107. static USHORT usPrevCTFTicks = 0; // Previous torque tick count
  108. UCHAR ucPageNum = pucRxBuffer_[0]; // Get page number
  109. // Decode common pages if available
  110. if(ucPageNum >= CommonData::PAGE80 && ucPageNum <= CommonData::PAGE82)
  111. {
  112. try
  113. {
  114. commonPages->Decode(pucRxBuffer_);
  115. }
  116. catch(CommonData::Error^ errorCommon)
  117. {
  118. }
  119. }
  120. // Decode bike power pages if available
  121. if(ucPageNum <= BikePower::PAGE_CTF)
  122. {
  123. try
  124. {
  125. bpPages->Decode(pucRxBuffer_);
  126. bAutoZeroInvalid = FALSE;
  127. bBadCalPage = FALSE;
  128. }
  129. catch(BikePower::Error^ errorBikePower)
  130. {
  131. if(errorBikePower->bUndefAutoZero)
  132. bAutoZeroInvalid = TRUE;
  133. if(ucPageNum == BikePower::PAGE_CALIBRATION)
  134. bBadCalPage = TRUE;
  135. }
  136. }
  137. // If sensor type changed, reset calculated values
  138. if(ePrevType != bpPages->eType)
  139. {
  140. ChangeSensorType(); // Update sensor type on interface
  141. bCoasting = FALSE; // Reset state variables
  142. bStopped = FALSE;
  143. bSeenCTF = FALSE;
  144. bSeenPower = FALSE;
  145. bSeenWheelTorque = FALSE;
  146. bSeenCrankTorque = FALSE;
  147. bSeenCTF = FALSE;
  148. if(bpPages->eType == BikePower::SensorType::CRANK_TORQUE_FREQ) // For CTF sensor
  149. SendMessage(BikePower::CAL_REQUEST); // Request offset to be able to do calculations
  150. }
  151. // Process bike power pages
  152. switch(ucPageNum)
  153. {
  154. case BikePower::PAGE_GET_SET_PARAMETERS:
  155. if(bpPages->ucCrankLength == 0xFF)
  156. {
  157. label_CrankLength->Text = "Invalid";
  158. checkBox_InvalidCrankLength->Checked = true;
  159. checkBox_AutoCrank->Checked = false;
  160. }
  161. else if(bpPages->ucCrankLength == 0xFE)
  162. {
  163. label_CrankLength->Text = "Auto Crank";
  164. checkBox_InvalidCrankLength->Checked = false;
  165. checkBox_AutoCrank->Checked = true;
  166. }
  167. else
  168. {
  169. label_CrankLength->Text = (((float)bpPages->ucCrankLength * (float)0.5) + (110.0)).ToString("F1");
  170. checkBox_InvalidCrankLength->Checked = false;
  171. checkBox_AutoCrank->Checked = false;
  172. numericUpDown_CrankLength->Value = (Decimal)(((float)bpPages->ucCrankLength * (float)0.5) + (110.0));
  173. }
  174. label_AutoCrankLength->Text = ((bpPages->ucSensorCapabilities & 0x01) == 0) ? "Manually Set Crank Length" : "Automatically Set Crank Length";
  175. switch((bpPages->ucSensorStatus & 0x30) >> 4)
  176. {
  177. case BikePower::SensorStatus::UNDEFINED:
  178. label_SensorStatus->Text = "Undefined";
  179. break;
  180. case BikePower::SensorStatus::LEFT_PRESENT:
  181. label_SensorStatus->Text = "Left Present";
  182. break;
  183. case BikePower::SensorStatus::RIGHT_PRESENT:
  184. label_SensorStatus->Text = "Right Present";
  185. break;
  186. case BikePower::SensorStatus::LEFT_RIGHT_PRESENT:
  187. label_SensorStatus->Text = "Left + Right Present";
  188. break;
  189. default:
  190. label_SensorStatus->Text = "----";
  191. break;
  192. }
  193. switch((bpPages->ucSensorStatus & 0x0C) >> 2)
  194. {
  195. case BikePower::SWMistmatchStatus::UNDEFINED:
  196. label_SWMistmatchStatus->Text = "Undefined";
  197. break;
  198. case BikePower::SWMistmatchStatus::RIGHT_SENSOR_OLDER:
  199. label_SWMistmatchStatus->Text = "Right Sensor Older";
  200. break;
  201. case BikePower::SWMistmatchStatus::LEFT_SENSOR_OLDER:
  202. label_SWMistmatchStatus->Text = "Left Sensor Older";
  203. break;
  204. case BikePower::SWMistmatchStatus::SW_SAME:
  205. label_SWMistmatchStatus->Text = "No mismatch";
  206. break;
  207. default:
  208. label_SWMistmatchStatus->Text = "----";
  209. break;
  210. }
  211. switch(bpPages->ucSensorStatus & 0x03)
  212. {
  213. case BikePower::CrankLengthStatus::LENGTH_INVALID:
  214. label_CrankLengthStatus->Text = "Invalid";
  215. break;
  216. case BikePower::CrankLengthStatus::DEFAULT_LENGTH_USED:
  217. label_CrankLengthStatus->Text = "Default Length Used";
  218. break;
  219. case BikePower::CrankLengthStatus::LENGTH_MANUALLY_SET:
  220. label_CrankLengthStatus->Text = "Manually Set";
  221. break;
  222. case BikePower::CrankLengthStatus::LENGTH_AUTOMATICALLY_SET:
  223. label_CrankLengthStatus->Text = "Automatically Set";
  224. break;
  225. default:
  226. label_CrankLengthStatus->Text = "----";
  227. break;
  228. }
  229. break;
  230. case BikePower::PAGE_POWER:
  231. {
  232. if(!bSeenPower) // Initialize previous values if first time the page is seen
  233. {
  234. ucPrevPowerEventCount = bpPages->ucPowEventCount;
  235. usPrevAcumPower = bpPages->usAcumPower;
  236. ulAcumPowerEventCount = 0;
  237. bSeenPower = TRUE;
  238. }
  239. // Difference between current and previous event
  240. UCHAR ucEventDiff = GetDifference(bpPages->ucPowEventCount, ucPrevPowerEventCount);
  241. USHORT usPowerDiff = GetDifference(bpPages->usAcumPower, usPrevAcumPower);
  242. // Update last event
  243. ucPrevPowerEventCount = bpPages->ucPowEventCount;
  244. usPrevAcumPower = bpPages->usAcumPower;
  245. // Cumulative values
  246. ulAcumPowerEventCount += ucEventDiff; // Cumulative power event count
  247. // Update calculation if dealing with a new event
  248. if(ucEventDiff && bpPages->eType == BikePower::SensorType::POWER_ONLY)
  249. ulAveragePower256 = (((ULONG) usPowerDiff) << 8)/ucEventDiff; // Average power (1/256W)
  250. break;
  251. }
  252. case BikePower::PAGE_WHEEL_TORQUE:
  253. ucCurTorqueEventCount = bpPages->ucWTEventCount;
  254. ucCurTicks = bpPages->ucWheelTicks;
  255. usCurPeriod2048 = bpPages->usAcumWheelPeriod2048;
  256. usCurTorque32 = bpPages->usAcumTorque32;
  257. case BikePower::PAGE_CRANK_TORQUE: // intentional fall-thru (most of the calculations for these two sensors are the same)
  258. {
  259. if(bpPages->eType == BikePower::SensorType::TORQUE_CRANK)
  260. {
  261. ucCurTorqueEventCount = bpPages->ucCTEventCount;
  262. ucCurTicks = bpPages->ucCrankTicks;
  263. usCurPeriod2048 = bpPages->usAcumCrankPeriod2048;
  264. usCurTorque32 = bpPages->usAcumTorque32;
  265. }
  266. // Initialize previous values if first time the wheel or crank torque page is seen
  267. if((!bSeenCrankTorque && bpPages->eType == BikePower::SensorType::TORQUE_CRANK) || (!bSeenWheelTorque && bpPages->eType == BikePower::SensorType::TORQUE_WHEEL))
  268. {
  269. if(!bSeenCrankTorque && bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  270. bSeenWheelTorque = TRUE;
  271. if(!bSeenWheelTorque && bpPages->eType == BikePower::SensorType::TORQUE_CRANK)
  272. bSeenCrankTorque = TRUE;
  273. ulAcumTorqueEventCount = 0; // Reset accumulated values
  274. ulAcumTicks = 0;
  275. usNoEventCount = 0;
  276. ulDistance100 = 0;
  277. ucPrevTorqueEventCount = ucCurTorqueEventCount;
  278. ucPrevTicks = ucCurTicks;
  279. usPrevPeriod2048 = usCurPeriod2048;
  280. usPrevTorque32 = usCurTorque32;
  281. }
  282. // Difference between current and previous event
  283. UCHAR ucTorqueEventDiff = GetDifference(ucCurTorqueEventCount, ucPrevTorqueEventCount);
  284. UCHAR ucTicksDiff = GetDifference(ucCurTicks, ucPrevTicks);
  285. USHORT usPeriodDiff = GetDifference(usCurPeriod2048, usPrevPeriod2048);
  286. USHORT usTorqueDiff = GetDifference(usCurTorque32, usPrevTorque32);
  287. // Update last event
  288. ucPrevTorqueEventCount =ucCurTorqueEventCount;
  289. ucPrevTicks = ucCurTicks;
  290. usPrevPeriod2048 = usCurPeriod2048;
  291. usPrevTorque32 = usCurTorque32;
  292. // Update cumulative values
  293. ulAcumTorqueEventCount += ucTorqueEventDiff; // Cumulative torque event count
  294. ulAcumTicks += ucTicksDiff; // Cumulative revolutions
  295. // Update calculations if dealing with a new event
  296. if(ucTorqueEventDiff)
  297. {
  298. usNoEventCount = 0;
  299. if(usPeriodDiff)
  300. {
  301. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  302. {
  303. bStopped = FALSE;
  304. ulSpeed = ((ULONG) 3600 * 2048 * ucWheelCircumference100 * ucTorqueEventDiff)/((ULONG) 100 * usPeriodDiff); // Average speed in m/h (Circumference in cm, Period in 1/2048s)
  305. }
  306. else // Crank Torque
  307. {
  308. bCoasting = FALSE;
  309. ulAverageCadence = ((ULONG) 60 * 2048 * ucTorqueEventDiff)/(ULONG) usPeriodDiff; // Average cadence (rpm)
  310. }
  311. ulAngularVelocity256 = ((ULONG) 2 * 2048 * PI256 * ucTorqueEventDiff)/(ULONG) usPeriodDiff; // Angular velocity (1/256 rad/s) -> 2 * 2048 * 256 * pi
  312. }
  313. else
  314. {
  315. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  316. {
  317. bStopped = TRUE; // No changes in wheel period if bike has stopped (time synchronous update)
  318. ulSpeed = 0; // If the bike has stopped, its speed and wheel angular velocity are zero
  319. }
  320. else // Crank Torque
  321. {
  322. bCoasting = TRUE; // No changes in crank period if the bike is coasting (time synchronous update)
  323. ulAverageCadence = 0; // If the bike is coasting, its cadence and crank angular velocity are zero
  324. }
  325. ulAngularVelocity256 = 0;
  326. }
  327. ulAverageTorque32 = (ULONG) usTorqueDiff/(ULONG) ucTorqueEventDiff; // Average torque (1/32 Nm)
  328. ulAveragePower256 = (ulAverageTorque32 * ulAngularVelocity256)/32; // Average power => (1/32Nm) * (1/256 rad/s) * 1/32 = 1/256W
  329. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  330. {
  331. ulDistance100 += (ULONG) ucWheelCircumference100 * ucTicksDiff; // Distance (cm)
  332. if(usTorqueDiff) // Check for coasting
  333. bCoasting = FALSE;
  334. else
  335. bCoasting = TRUE; // The bike is coasting if there are wheel events but the accumulated torque does not change
  336. }
  337. }
  338. else
  339. { // Event synchronous
  340. usNoEventCount++;
  341. if(usNoEventCount >= BikePower::MAX_NOEVENT)
  342. {
  343. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  344. {
  345. bStopped = TRUE; // Detect stop (no new wheel events before a preset number of messages)
  346. ulSpeed = 0; // Bike stopped, so speed and wheel angular velocity is zero
  347. }
  348. else // Crank Torque
  349. {
  350. bCoasting = TRUE; // Detect coasting (no new crank events before a preset number of messages)
  351. ulAverageCadence = 0; // If the bike is coasting, cadence and crank angular velocity are zero
  352. }
  353. ulAngularVelocity256 = 0;
  354. }
  355. }
  356. break;
  357. }
  358. case BikePower::PAGE_CTF:
  359. {
  360. if(!bSeenCTF) // Initialize previous values if first time the page has been seen
  361. {
  362. bSeenCTF = TRUE;
  363. ulAcumCTFEventCount = 0;
  364. usNoEventCount = 0;
  365. ucPrevCTFEventCount = bpPages->ucCTFEventCount;
  366. usPrevTime2000 = bpPages->usTime2000;
  367. usPrevCTFTicks = bpPages->usTorqueTicks;
  368. }
  369. // Difference between current and previous event
  370. UCHAR ucCTFEventDiff = GetDifference(bpPages->ucCTFEventCount, ucPrevCTFEventCount);
  371. USHORT usTimeDiff = GetDifference(bpPages->usTime2000, usPrevTime2000);
  372. USHORT usCTFTicksDiff = GetDifference(bpPages->usTorqueTicks, usPrevCTFTicks);
  373. // Update last event
  374. ucPrevCTFEventCount = bpPages->ucCTFEventCount;
  375. usPrevTime2000 = bpPages->usTime2000;
  376. usPrevCTFTicks = bpPages->usTorqueTicks;
  377. // Update cumulative values
  378. ulAcumCTFEventCount += ucCTFEventDiff;
  379. // Update calculations if dealing with a new event
  380. if(ucCTFEventDiff)
  381. {
  382. usNoEventCount = 0;
  383. bCoasting = FALSE;
  384. if(usTimeDiff)
  385. {
  386. ulAverageCadence = ((ULONG) 60 * 2000 * ucCTFEventDiff)/(ULONG) usTimeDiff; // Cadence (rpm)
  387. if(!bpPages->IsSlopeInvalid(bpPages->usSlope10))
  388. {
  389. ulAverageTorque32 = ((((ULONG) 32 * 10 * 2000 * usCTFTicksDiff)/usTimeDiff) - (32 * 10 * usCTFOffset))/(ULONG)bpPages->usSlope10; // Torque (1/32 Nm): time is in 1/2000s, slope in 1/10 Hz/Nm, convert to 1/32 Nm for consistency
  390. ulAveragePower256 = (ULONG) (PI256 * ulAverageTorque32 * ulAverageCadence)/(30*32); // Average power (1/256 W) , torque is in 1/32 m
  391. if(ulAverageTorque32)
  392. ulAngularVelocity256 = ((ULONG) 32 * ulAveragePower256)/ulAverageTorque32; // Power (1/256W) / Torque (1/32 Nm) -> 1/256 rad/s
  393. }
  394. }
  395. }
  396. else
  397. {
  398. usNoEventCount++;
  399. if(usNoEventCount >= BikePower::MAX_NOEVENT)
  400. {
  401. bCoasting = TRUE; // Detect coasting
  402. ulAverageCadence = 0;
  403. ulAveragePower256 = 0;
  404. }
  405. }
  406. break;
  407. }
  408. case BikePower::PAGE_CALIBRATION:
  409. // Set calibration offset to use on calculations if it received a valid value
  410. if(bpPages->ucRxCalibrationID == BikePower::CAL_CTF && bpPages->ucRxCTFMsgID == BikePower::CTF_OFFSET)
  411. {
  412. if(!bpPages->IsOffsetInvalid(bpPages->usCalOffset))
  413. usCTFOffset = bpPages->usCalOffset;
  414. }
  415. break;
  416. default:
  417. break;
  418. }
  419. UpdateDisplay(ucPageNum);
  420. ePrevType = bpPages->eType; // Previous detected sensor type
  421. }
  422. /**************************************************************************
  423. * BikePowerDisplay::HandleRetransmit
  424. *
  425. * Retransmits calibration message, up to the maximum retransmission number
  426. * If values are updated on the GUI while attempting to retransmit, the
  427. * newest values will be sent
  428. *
  429. * returns: TRUE if message was retransmitted
  430. * FALSE if maximum number of retransmissions was reached
  431. *
  432. **************************************************************************/
  433. BOOL BikePowerDisplay::HandleRetransmit()
  434. {
  435. BOOL bSuccess = TRUE;
  436. if(ucMsgExpectingAck) // Message still expecting an ack
  437. {
  438. if(ucAckRetryCount++ < MAX_RETRIES)
  439. {
  440. SendMessage(ucMsgExpectingAck);
  441. }
  442. else
  443. bSuccess = FALSE;
  444. }
  445. return bSuccess;
  446. }
  447. /**************************************************************************
  448. * BikePowerDisplay::UpdateDisplay
  449. *
  450. * Shows received decoded data on GUI
  451. *
  452. * ucPageNum_: received page
  453. *
  454. * returns: N/A
  455. *
  456. **************************************************************************/
  457. void BikePowerDisplay::UpdateDisplay(UCHAR ucPageNum_)
  458. {
  459. // Display current message received
  460. switch(ucPageNum_)
  461. {
  462. case BikePower::PAGE_POWER:
  463. this->label_Trn_PageDisplay->Text = "BAS";
  464. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucPowEventCount.ToString(); // Current power event count
  465. if(bpPages->IsCadenceInvalid(bpPages->ucCadence))
  466. this->label_Trn_CadenceDisplay->Text = "Off";
  467. else
  468. this->label_Trn_CadenceDisplay->Text = bpPages->ucCadence.ToString(); // Cadence (RPM)
  469. if(bpPages->ucPedalPower != BikePower::RESERVED)
  470. {
  471. UCHAR ucTemp = 0x00;
  472. ucTemp = ((bpPages->ucPedalPower) & 0x7F); //0x7F is a mask used to remove "Pedal Differentiation Bit" leaving pedal power percent value only
  473. if(ucTemp >= 0x65) // Checking pedal power percent value is within the valid range 0%-100%
  474. {
  475. this->label_Trn_PedalDisplay->Text = "---";
  476. this->label_Trn_PedalPwrDisplay->Text = "Invalid";
  477. }
  478. else
  479. {
  480. if((bpPages->ucPedalPower) & 0x80) // 0x80 is a mask for right pedal power contribution
  481. this->label_Trn_PedalDisplay->Text = "Right"; // Power contribution is from the right pedal
  482. else
  483. this->label_Trn_PedalDisplay->Text = "Unknown"; // Power contribution is unknown
  484. this->label_Trn_PedalPwrDisplay->Text = ucTemp.ToString();
  485. }
  486. }
  487. else
  488. {
  489. this->label_Trn_PedalDisplay->Text = "---";
  490. this->label_Trn_PedalPwrDisplay->Text = "Off";
  491. }
  492. this->label_Trn_AccumPowerDisplay->Text = bpPages->usAcumPower.ToString(); // Current cumulative power (W)
  493. this->label_Trn_InstPowerDisplay->Text = bpPages->usPower.ToString(); // Power (W)
  494. this->label_Dat_InstCadenceDisplay->Text = this->label_Trn_CadenceDisplay->Text; // Cadence (RPM)
  495. this->label_Dat_InstPowerDisplay->Text = bpPages->usPower.ToString(); // Power (W)
  496. this->label_Dat_PedalPwrDisplay->Text = this->label_Trn_PedalPwrDisplay->Text;
  497. this->label_Dat_PedalDisplay->Text = this->label_Trn_PedalDisplay->Text;
  498. break;
  499. case BikePower::PAGE_WHEEL_TORQUE:
  500. this->label_Trn_PageDisplay->Text = "WHL";
  501. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucWTEventCount.ToString();
  502. this->label_Trn_EventCountDisplay->Text = bpPages->ucWheelTicks.ToString();
  503. if(bpPages->IsCadenceInvalid(bpPages->ucCadence))
  504. this->label_Trn_CadenceDisplay->Text = "Off";
  505. else
  506. this->label_Trn_CadenceDisplay->Text = bpPages->ucCadence.ToString(); // Cadence (RPM)
  507. this->label_Dat_InstCadenceDisplay->Text = this->label_Trn_CadenceDisplay->Text; // Cadence (RPM)
  508. this->label_Trn_AccumOneDisplay->Text = bpPages->usAcumWheelPeriod2048.ToString(); // Period (1/2048 s)
  509. this->label_Trn_AccumTwoDisplay->Text = bpPages->usAcumTorque32.ToString(); // Torque (1/32 Nm)
  510. break;
  511. case BikePower::PAGE_CRANK_TORQUE:
  512. this->label_Trn_PageDisplay->Text = "CRK";
  513. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucCTEventCount.ToString();
  514. this->label_Trn_EventCountDisplay->Text = bpPages->ucCrankTicks.ToString();
  515. if(bpPages->IsCadenceInvalid(bpPages->ucCadence))
  516. this->label_Trn_CadenceDisplay->Text = "Off";
  517. else
  518. this->label_Trn_CadenceDisplay->Text = bpPages->ucCadence.ToString(); // Cadence (RPM)
  519. this->label_Dat_InstCadenceDisplay->Text = this->label_Trn_CadenceDisplay->Text; // Cadence (RPM)
  520. this->label_Trn_AccumOneDisplay->Text = bpPages->usAcumCrankPeriod2048.ToString();
  521. this->label_Trn_AccumTwoDisplay->Text = (bpPages->usAcumTorque32).ToString(); // Accum torque (1/32 Nm)
  522. break;
  523. case BikePower::PAGE_TEPS:
  524. {
  525. if(bpPages->ucLeftTorqueEffectiveness == bpPages->INVALID_TEPS)
  526. label_LeftTorqueEffectiveness->Text = "INVALID";
  527. else
  528. label_LeftTorqueEffectiveness->Text = (bpPages->ucLeftTorqueEffectiveness / 2.0).ToString();
  529. if(bpPages->ucRightTorqueEffectiveness == bpPages->INVALID_TEPS)
  530. label_RightTorqueEffectiveness->Text = "INVALID";
  531. else
  532. label_RightTorqueEffectiveness->Text = (bpPages->ucRightTorqueEffectiveness / 2.0).ToString();
  533. if(bpPages->ucLeftPedalSmoothness == bpPages->INVALID_TEPS)
  534. label_LeftPedalSmoothness->Text = "INVALID";
  535. else
  536. label_LeftPedalSmoothness->Text = (bpPages->ucLeftPedalSmoothness / 2.0).ToString();
  537. if(bpPages->ucRightPedalSmoothness == bpPages->INVALID_TEPS)
  538. label_RightPedalSmoothness->Text = "INVALID";
  539. else if(bpPages->ucRightPedalSmoothness == bpPages->COMBINED_PEDAL_SMOOTHNESS)
  540. label_RightPedalSmoothness->Text = "COMBINED PEDAL SMOOTHNESS";
  541. else
  542. label_RightPedalSmoothness->Text = (bpPages->ucRightPedalSmoothness / 2.0).ToString();
  543. break;
  544. }
  545. case BikePower::PAGE_CTF:
  546. this->label_Trn_PageDisplay->Text = "CTF";
  547. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucCTFEventCount.ToString();
  548. this->label_Trn_SlopeDisplay->Text = bpPages->usSlope10.ToString();
  549. this->label_Trn_AccumOneDisplay->Text = bpPages->usTime2000.ToString();
  550. this->label_Trn_AccumTwoDisplay->Text = bpPages->usTorqueTicks.ToString();
  551. if(bpPages->IsSlopeInvalid(bpPages->usSlope10))
  552. this->label_Dat_SlopeDisplay->Text = "---";
  553. else
  554. this->label_Dat_SlopeDisplay->Text = ((double)bpPages->usSlope10/10).ToString();
  555. break;
  556. case BikePower::PAGE_CALIBRATION:
  557. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Green;
  558. if(bBadCalPage)
  559. {
  560. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Red;
  561. this->label_Cal_StatusDisplay->Text = "xPAG";
  562. }
  563. switch(bpPages->ucRxCalibrationID)
  564. {
  565. case BikePower::CAL_SUCCESS:
  566. case BikePower::CAL_FAIL: // Intentional fall thru
  567. if(!bAutoZeroInvalid)
  568. {
  569. this->button_Cal_AutoZeroSet->Enabled = (bpPages->bAutoZeroEnable == TRUE);
  570. this->radioButton_Cal_AZoff->Enabled = (bpPages->bAutoZeroEnable == TRUE);
  571. this->radioButton_Cal_AZon->Enabled = (bpPages->bAutoZeroEnable == TRUE);
  572. if(!bpPages->bAutoZeroEnable)
  573. this->listBox_Cal_AZStatus->SelectedIndex = 2;
  574. else
  575. this->listBox_Cal_AZStatus->SelectedIndex = (UCHAR) bpPages->bAutoZeroOn;
  576. }
  577. this->label_Cal_CalNumberDisplay->Text = bpPages->sCalibrationData.ToString();
  578. if(bpPages->ucRxCalibrationID == BikePower::CAL_SUCCESS)
  579. {
  580. this->label_Cal_StatusDisplay->Text = "+CAL";
  581. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Green;
  582. }
  583. else
  584. {
  585. this->label_Cal_StatusDisplay->Text = "xCAL";
  586. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Red;
  587. }
  588. break;
  589. case BikePower::CAL_TORQUE_METER_CAPABILITIES:
  590. this->button_Cal_AutoZeroSet->Enabled = (bpPages->bAutoZeroEnable == TRUE);
  591. this->radioButton_Cal_AZoff->Enabled = (bpPages->bAutoZeroEnable == TRUE);
  592. this->radioButton_Cal_AZon->Enabled = (bpPages->bAutoZeroEnable == TRUE);
  593. if(!bpPages->bAutoZeroEnable) // Auto zero not supported
  594. this->listBox_Cal_AZStatus->SelectedIndex = 2;
  595. else
  596. this->listBox_Cal_AZStatus->SelectedIndex = (UCHAR) bpPages->bAutoZeroOn;
  597. if(bpPages->IsRawTorqueInvalid(bpPages->sRawTorque))
  598. this->label_Cal_RawTorqueDisplay->Text = "---";
  599. else
  600. this->label_Cal_RawTorqueDisplay->Text = bpPages->sRawTorque.ToString();
  601. if(bpPages->IsOffsetTorqueInvalid(bpPages->sOffsetTorque))
  602. this->label_Cal_OffsetTorqueDisplay->Text = "---";
  603. else
  604. this->label_Cal_OffsetTorqueDisplay->Text = bpPages->sOffsetTorque.ToString();
  605. break;
  606. case BikePower::CAL_CTF:
  607. if(bpPages->ucRxCTFMsgID == BikePower::CTF_OFFSET)
  608. {
  609. this->label_Cal_CalNumberDisplay->Text = bpPages->usCalOffset.ToString();
  610. if(!bpPages->usCalOffset)
  611. {
  612. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Yellow;
  613. this->label_Cal_StatusDisplay->Text = "ZERO";
  614. }
  615. else if(bpPages->IsOffsetInvalid(bpPages->usCalOffset))
  616. {
  617. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Red;
  618. this->label_Cal_StatusDisplay->Text = "xOFS";
  619. }
  620. else
  621. {
  622. this->label_Dat_CTFOffsetDisplay->Text = usCTFOffset.ToString();
  623. this->label_Cal_StatusDisplay->Text = "+OFS";
  624. }
  625. }
  626. if(bpPages->ucRxCTFMsgID == BikePower::CTF_ACK)
  627. {
  628. if(bpPages->ucRxCTFMsgID == BikePower::CTF_SLOPE)
  629. this->label_Cal_StatusDisplay->Text = "+SLP";
  630. if(bpPages->ucRxCTFMsgID == BikePower::CTF_SERIAL)
  631. this->label_Cal_StatusDisplay->Text = "+SRL";
  632. }
  633. break;
  634. default:
  635. break;
  636. }
  637. break;
  638. case CommonData::PAGE80:
  639. this->label_Glb_HardwareVerDisplay->Text = commonPages->ucHwVersion.ToString(); // Hw version
  640. this->label_Glb_ManfIDDisplay->Text = commonPages->usMfgID.ToString(); // Mfg ID
  641. this->label_Glb_ModelNumDisplay->Text = commonPages->usModelNum.ToString(); // Model number
  642. break;
  643. case CommonData::PAGE81:
  644. this->label_Glb_SoftwareVerDisplay->Text = commonPages->ucSwVersion.ToString(); // Sw version
  645. if(commonPages->ulSerialNum != 0xFFFFFFFF)
  646. this->label_Glb_SerialNumDisplay->Text = commonPages->ulSerialNum.ToString(); // Serial number
  647. else
  648. this->label_Glb_SerialNumDisplay->Text = "N/A";
  649. break;
  650. case CommonData::PAGE82:
  651. if(commonPages->IsBatteryVoltageInvalid(commonPages->usBatVoltage256)) // Battery voltage
  652. this->label_Bat_VoltsDisplay->Text = "Invalid Voltage";
  653. else
  654. this->label_Bat_VoltsDisplay->Text = System::Math::Round((double)commonPages->usBatVoltage256/256,4).ToString();
  655. if(commonPages->IsBatteryStatusInvalid(commonPages->eBatStatus)) // Battery status
  656. this->listBox_Bat_Status->SelectedIndex = this->listBox_Bat_Status->Items->Count - 1;
  657. else
  658. this->listBox_Bat_Status->SelectedIndex = (UCHAR) (commonPages->eBatStatus) - 1;
  659. this->label_Bat_ElpTimeDisplay->Text = ((ULONG) (commonPages->ulOpTime & CommonData::OPERATING_TIME_MASK) * (UCHAR) commonPages->eTimeResolution).ToString(); // Operating time (s)
  660. this->label_Bat_SecPrecis->Text = System::String::Concat(((UCHAR)commonPages->eTimeResolution).ToString(), " Sec Precision"); // Time resolution
  661. break;
  662. default:
  663. break;
  664. }
  665. // Calculations are not displayed initially, so they will only be displayed once the sensor type is known
  666. // A sensor type would change from UNKNOWN to the correct type after initialization
  667. if(ePrevType == bpPages->eType)
  668. {
  669. switch(bpPages->eType)
  670. {
  671. case BikePower::SensorType::POWER_ONLY:
  672. this->label_Dat_Coasting->Visible = (bCoasting == TRUE);
  673. this->label_Dat_Stopped->Visible = (bStopped == TRUE);
  674. this->label_Dat_CalcPowerDisplay->Text = System::Math::Round((double)ulAveragePower256/256,2).ToString(); // Average power (W)
  675. this->label_Dat_UpdateCountDisplay->Text = ulAcumPowerEventCount.ToString(); // Cumulative power event count
  676. break;
  677. case BikePower::SensorType::TORQUE_WHEEL:
  678. case BikePower::SensorType::TORQUE_CRANK: // intentional fall - thru
  679. this->label_Dat_Coasting->Visible = (bCoasting == TRUE);
  680. this->label_Dat_Stopped->Visible = (bStopped == TRUE);
  681. this->label_Dat_CalcPowerDisplay->Text = System::Math::Round((double) ulAveragePower256/256,2).ToString(); // Average power (W)
  682. this->label_Dat_UpdateCountDisplay->Text = ulAcumTorqueEventCount.ToString(); // Torque event count
  683. this->label_Dat_EventCountDisplay->Text = ulAcumTicks.ToString(); // Ticks
  684. this->label_Dat_AngVelDisplay->Text = System::Math::Round((double) ulAngularVelocity256/256,2).ToString(); // Angular velocity (rad/s)
  685. this->label_Dat_TorqueDisplay->Text = System::Math::Round((double) ulAverageTorque32/32,2).ToString(); // Average torque (Nm)
  686. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  687. {
  688. this->label_Dat_SpeedDisplay->Text = System::Math::Round((double)ulSpeed/1000,2).ToString(); // Average speed (meters/h -> km/h)
  689. this->label_Dat_DistDisplay->Text = System::Math::Round((double)ulDistance100/100,2).ToString(); // Distance (m)
  690. }
  691. else // Crank Torque
  692. {
  693. this->label_Dat_CalcRPMDisplay->Text = System::Math::Round(ulAverageCadence,2).ToString();
  694. }
  695. break;
  696. case BikePower::SensorType::CRANK_TORQUE_FREQ:
  697. if(ucPageNum_ == BikePower::PAGE_CALIBRATION && bpPages->ucRxCTFMsgID == BikePower::CTF_OFFSET)
  698. {
  699. // Blank calculations while receiving CTF offset, rather than displaying erroneous data
  700. this->label_Dat_CalcPowerDisplay->Text = "---";
  701. this->label_Dat_UpdateCountDisplay->Text = "---";
  702. this->label_Dat_AngVelDisplay->Text = "---";
  703. this->label_Dat_TorqueDisplay->Text = "---";
  704. this->label_Dat_CalcRPMDisplay->Text = "---";
  705. }
  706. else
  707. {
  708. this->label_Dat_Coasting->Visible = (bCoasting == TRUE);
  709. this->label_Dat_Stopped->Visible = (bStopped == TRUE);
  710. this->label_Dat_CalcPowerDisplay->Text = System::Math::Round((double)ulAveragePower256/256,2).ToString();
  711. this->label_Dat_UpdateCountDisplay->Text = ulAcumCTFEventCount.ToString();
  712. this->label_Dat_AngVelDisplay->Text = System::Math::Round((double)ulAngularVelocity256/256,2).ToString();
  713. this->label_Dat_TorqueDisplay->Text = System::Math::Round((double)ulAverageTorque32/32,2).ToString();
  714. this->label_Dat_CalcRPMDisplay->Text = ulAverageCadence.ToString();
  715. }
  716. break;
  717. default:
  718. break;
  719. }
  720. }
  721. }
  722. /**************************************************************************
  723. * BikePowerDisplay::UpdateDisplayAckStatus
  724. *
  725. * Updates display to show if acknowledged calibration messages were
  726. * transmitted successfully
  727. *
  728. * returns: N/A
  729. *
  730. **************************************************************************/
  731. void BikePowerDisplay::UpdateDisplayAckStatus(UCHAR ucStatus_)
  732. {
  733. switch(ucStatus_)
  734. {
  735. case ACK_SUCCESS:
  736. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Green;
  737. this->label_Cal_StatusDisplay->Text = "SENT";
  738. break;
  739. case ACK_RETRY:
  740. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Blue;
  741. this->label_Cal_StatusDisplay->Text = "RTRY";
  742. break;
  743. case ACK_FAIL:
  744. this->label_Cal_StatusDisplay->ForeColor = System::Drawing::Color::Red;
  745. this->label_Cal_StatusDisplay->Text = "xSNT";
  746. break;
  747. default:
  748. break;
  749. }
  750. }
  751. /**************************************************************************
  752. * BikePowerDisplay::ChangeSensorType
  753. *
  754. * Updates display to enable/disable elements available only on certain
  755. * type of sensors, after a change in sensor type is detected
  756. *
  757. * returns: N/A
  758. *
  759. **************************************************************************/
  760. void BikePowerDisplay::ChangeSensorType()
  761. {
  762. switch(bpPages->eType)
  763. {
  764. case BikePower::SensorType::POWER_ONLY:
  765. this->label_Dat_PageRecDisplay->Text = "Power Only Sensor";
  766. this->label_Trn_EventCountDisplay->Text = "---";
  767. this->label_Trn_AccumOneDisplay->Text = "---";
  768. this->label_Trn_AccumTwoDisplay->Text = "---";
  769. this->label_Trn_Slope->Visible = false;
  770. this->label_Trn_SlopeDisplay->Visible = false;
  771. this->label_Dat_SlopeDisplay->Text = "---";
  772. this->label_Dat_AngVelDisplay->Text = "---";
  773. this->label_Dat_TorqueDisplay->Text = "---";
  774. this->label_Dat_CalcRPMDisplay->Text = "---";
  775. this->label_Dat_SpeedDisplay->Text = "---";
  776. this->label_Dat_DistDisplay->Text = "---";
  777. this->label_Dat_CTFOffsetDisplay->Text = "---";
  778. this->numericUpDown_Cal_CTFSlope->Enabled = false;
  779. this->numericUpDown_Cal_CTFSerial->Enabled = false;
  780. this->button_Cal_CTFSerialSet->Enabled = false;
  781. this->button_Cal_CTFSlopeSet->Enabled = false;
  782. break;
  783. case BikePower::SensorType::TORQUE_WHEEL:
  784. this->label_Dat_PageRecDisplay->Text = "Wheel Torque Sensor";
  785. this->label_Trn_AccumOne->Text = "Wheel P:";
  786. this->label_Trn_Slope->Visible = false;
  787. this->label_Trn_SlopeDisplay->Visible = false;
  788. this->label_Trn_InstPowerDisplay->Text = "---";
  789. this->label_Trn_AccumPowerDisplay->Text = "---";
  790. this->label_Dat_InstPowerDisplay->Text = "---";
  791. this->label_Dat_CTFOffsetDisplay->Text = "---";
  792. this->label_Dat_SlopeDisplay->Text = "---";
  793. this->numericUpDown_Cal_CTFSlope->Enabled = false;
  794. this->numericUpDown_Cal_CTFSerial->Enabled = false;
  795. this->button_Cal_CTFSerialSet->Enabled = false;
  796. this->button_Cal_CTFSlopeSet->Enabled = false;
  797. break;
  798. case BikePower::SensorType::TORQUE_CRANK:
  799. this->label_Dat_PageRecDisplay->Text = "Crank Torque Sensor";
  800. this->label_Trn_AccumOne->Text = "Crank P:";
  801. this->label_Trn_Slope->Visible = false;
  802. this->label_Trn_SlopeDisplay->Visible = false;
  803. this->label_Trn_InstPowerDisplay->Text = "---";
  804. this->label_Trn_AccumPowerDisplay->Text = "---";
  805. this->label_Dat_SlopeDisplay->Text = "---";
  806. this->label_Dat_SpeedDisplay->Text = "---";
  807. this->label_Dat_DistDisplay->Text = "---";
  808. this->label_Dat_InstPowerDisplay->Text = "---";
  809. this->label_Dat_CTFOffsetDisplay->Text = "---";
  810. this->numericUpDown_Cal_CTFSlope->Enabled = false;
  811. this->numericUpDown_Cal_CTFSerial->Enabled = false;
  812. this->button_Cal_CTFSerialSet->Enabled = false;
  813. this->button_Cal_CTFSlopeSet->Enabled = false;
  814. break;
  815. case BikePower::SensorType::CRANK_TORQUE_FREQ:
  816. this->label_Dat_PageRecDisplay->Text = "Crank Torque Frequency Sensor";
  817. this->label_Trn_AccumOne->Text = " Time:";
  818. this->label_Trn_EventCountDisplay->Text = "---";
  819. this->label_Trn_Slope->Visible = true;
  820. this->label_Trn_SlopeDisplay->Visible = true;
  821. this->label_Trn_InstPowerDisplay->Text = "---";
  822. this->label_Trn_AccumPowerDisplay->Text = "---";
  823. this->label_Trn_CadenceDisplay->Text = "---";
  824. this->label_Trn_PedalDisplay->Text = "---";
  825. this->label_Trn_PedalPwrDisplay->Text = "---";
  826. this->label_Dat_SpeedDisplay->Text = "---";
  827. this->label_Dat_DistDisplay->Text = "---";
  828. this->label_Dat_InstPowerDisplay->Text = "---";
  829. this->label_Dat_InstCadenceDisplay->Text = "---";
  830. this->label_Dat_CTFOffsetDisplay->Text = "Unknown";
  831. this->numericUpDown_Cal_CTFSlope->Enabled = true;
  832. this->numericUpDown_Cal_CTFSerial->Enabled = true;
  833. this->button_Cal_CTFSerialSet->Enabled = true;
  834. this->button_Cal_CTFSlopeSet->Enabled = true;
  835. this->button_Cal_AutoZeroSet->Enabled = false;
  836. this->radioButton_Cal_AZoff->Enabled = false;
  837. this->radioButton_Cal_AZon->Enabled = false;
  838. this->listBox_Cal_AZStatus->SelectedIndex = -1;
  839. break;
  840. case BikePower::SensorType::UNKNOWN:
  841. this->label_Dat_PageRecDisplay->Text = "Updating...";
  842. this->label_Trn_EventCountDisplay->Text = "---";
  843. this->label_Trn_AccumOneDisplay->Text = "---";
  844. this->label_Trn_AccumTwoDisplay->Text = "---";
  845. this->label_Trn_Slope->Visible = false;
  846. this->label_Trn_SlopeDisplay->Visible = false;
  847. this->label_Dat_SlopeDisplay->Text = "---";
  848. this->label_Dat_AngVelDisplay->Text = "---";
  849. this->label_Dat_TorqueDisplay->Text = "---";
  850. this->label_Dat_CalcRPMDisplay->Text = "---";
  851. this->label_Dat_SpeedDisplay->Text = "---";
  852. this->label_Dat_DistDisplay->Text = "---";
  853. this->label_Dat_CTFOffsetDisplay->Text = "---";
  854. this->numericUpDown_Cal_CTFSlope->Enabled = false;
  855. this->numericUpDown_Cal_CTFSerial->Enabled = false;
  856. this->button_Cal_CTFSerialSet->Enabled = false;
  857. this->button_Cal_CTFSlopeSet->Enabled = false;
  858. break;
  859. default:
  860. break;
  861. }
  862. }
  863. /**************************************************************************
  864. * BikePowerDisplay::button_Cal_Calibrate_Click
  865. *
  866. * Sends a calibration request
  867. *
  868. * returns: N/A
  869. *
  870. **************************************************************************/
  871. System::Void BikePowerDisplay::button_Cal_Calibrate_Click(System::Object^ sender, System::EventArgs^ e)
  872. {
  873. bRequestCalibration = true;
  874. SendMessage(BikePower::CAL_REQUEST);
  875. }
  876. /**************************************************************************
  877. * BikePowerDisplay::button_Cal_AutoZeroSet_Click
  878. *
  879. * Sends an Auto Zero Configuration request
  880. *
  881. * returns: N/A
  882. *
  883. **************************************************************************/
  884. System::Void BikePowerDisplay::button_Cal_AutoZeroSet_Click(System::Object^ sender, System::EventArgs^ e)
  885. {
  886. bRequestCalibration = true;
  887. SendMessage(BikePower::CAL_AUTOZERO_CONFIG);
  888. }
  889. /**************************************************************************
  890. * BikePowerDisplay::button_Cal_CTFSerialSet_Click
  891. *
  892. * Sends a CTF defined message for serial number, to save a new serial
  893. * number to the power sensor flash
  894. *
  895. * returns: N/A
  896. *
  897. **************************************************************************/
  898. System::Void BikePowerDisplay::button_Cal_CTFSerialSet_Click(System::Object^ sender, System::EventArgs^ e)
  899. {
  900. bRequestCalibration = true;
  901. SendMessage(BikePower::CTF_SERIAL);
  902. }
  903. /**************************************************************************
  904. * BikePowerDisplay::button_Cal_CTFSlopeSet_Click
  905. *
  906. * Sends a CTF defined message for slope to the power sensor, to save a new
  907. * value for the slope to the sensor flash
  908. *
  909. * returns: N/A
  910. *
  911. **************************************************************************/
  912. System::Void BikePowerDisplay::button_Cal_CTFSlopeSet_Click(System::Object^ sender, System::EventArgs^ e)
  913. {
  914. bRequestCalibration = true;
  915. SendMessage(BikePower::CTF_SLOPE);
  916. }
  917. /**************************************************************************
  918. * BikePowerDisplay::numericUpDown_Cal_WheelCircum_ValueChanged
  919. *
  920. * Updates value of wheel circumference
  921. *
  922. * returns: N/A
  923. *
  924. **************************************************************************/
  925. System::Void BikePowerDisplay::numericUpDown_Cal_WheelCircum_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  926. {
  927. ucWheelCircumference100 = System::Convert::ToByte(this->numericUpDown_Cal_WheelCircum->Value);
  928. }
  929. /**************************************************************************
  930. * BikePowerDisplay::radioButton_Cal_AZ_CheckedChanged
  931. *
  932. * Updates auto zero status set on display
  933. *
  934. * returns: N/A
  935. *
  936. **************************************************************************/
  937. System::Void BikePowerDisplay::radioButton_Cal_AZ_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  938. {
  939. bAZOn = (BOOL) this->radioButton_Cal_AZon->Checked;
  940. }
  941. /**************************************************************************
  942. * BikePowerDisplay::numericUpDown_Cal_CTFSerial_ValueChanged
  943. *
  944. * Updates serial number set on display, for CTF Serial message
  945. *
  946. * returns: N/A
  947. *
  948. **************************************************************************/
  949. System::Void BikePowerDisplay::numericUpDown_Cal_CTFSerial_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  950. {
  951. usCalSerialToSend = System::Convert::ToUInt16(this->numericUpDown_Cal_CTFSerial->Value); // serial number
  952. }
  953. /**************************************************************************
  954. * BikePowerDisplay::numericUpDown_Cal_CTFSlope_ValueChanged
  955. *
  956. * Updates slope number set on display, for CTF Slope message
  957. *
  958. * returns: N/A
  959. *
  960. **************************************************************************/
  961. System::Void BikePowerDisplay::numericUpDown_Cal_CTFSlope_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  962. {
  963. usCalSlopeToSend = System::Convert::ToUInt16(10*(this->numericUpDown_Cal_CTFSlope->Value)); // slope in 1/10 Nm/Hz
  964. }
  965. System::Void BikePowerDisplay::button_SetCrankStatus_Click(System::Object ^sender, System::EventArgs ^e)
  966. {
  967. bpPages->ucSubpageNumber = BikePower::SUBPAGE_CRANK_PARAMETERS;
  968. if(checkBox_InvalidCrankLength->Checked)
  969. bpPages->ucCrankLength = 0xFF; // Invalid
  970. else if(checkBox_AutoCrank->Checked)
  971. bpPages->ucCrankLength = 0xFE; // Request Auto Crank
  972. else
  973. bpPages->ucCrankLength = (UCHAR)(((float)numericUpDown_CrankLength->Value - (float)110.0) / (float)0.5); // Send Crank Length value
  974. bpPages->ucSensorStatus = 0x00; // Readonly byte
  975. bpPages->ucSensorCapabilities = 0x00; // Readonly byte
  976. bRequestCalibration = false;
  977. SendMessage(bpPages->PAGE_GET_SET_PARAMETERS);
  978. }
  979. System::Void BikePowerDisplay::button_GetCrankStatus_Click(System::Object ^sender, System::EventArgs ^e)
  980. {
  981. commonPages->ucDescriptorByte1 = BikePower::SUBPAGE_CRANK_PARAMETERS; // for requesting subpages
  982. commonPages->ucDescriptorByte2 = 0xFF; // Invalid byte
  983. commonPages->ucReqTransResp = System::Convert::ToByte(numericUpDown_TransResponse->Value); //Number of times to transmit, don't use ack messages
  984. commonPages->ucReqPageNum = BikePower::PAGE_GET_SET_PARAMETERS; // request Get/Set page
  985. commonPages->ucCommandType = 0x01; // For requesting a data page
  986. bRequestCalibration = false;
  987. SendMessage(commonPages->PAGE70);
  988. }
  989. System::Void BikePowerDisplay::SendMessage(UCHAR ucMsgCode_)
  990. {
  991. UCHAR aucAckBuffer[8] = {0,0,0,0,0,0,0,0};
  992. // If a calibration request should be sent
  993. if(bRequestCalibration)
  994. {
  995. switch(ucMsgCode_)
  996. {
  997. case BikePower::CAL_REQUEST: // Manual calibration request
  998. bpPages->EncodeManualCalibrationRequest(aucAckBuffer);
  999. break;
  1000. case BikePower::CAL_AUTOZERO_CONFIG: // Auto zero calibration request
  1001. bpPages->EncodeAZCalibrationRequest(TRUE, bAZOn, aucAckBuffer);
  1002. break;
  1003. case BikePower::CTF_SLOPE: // Save slope to flash
  1004. bpPages->EncodeCTFCalibrationPage(ucMsgCode_, usCalSlopeToSend, aucAckBuffer);
  1005. break;
  1006. case BikePower::CTF_SERIAL: // Save serial to flash
  1007. bpPages->EncodeCTFCalibrationPage(ucMsgCode_, usCalSerialToSend, aucAckBuffer);
  1008. break;
  1009. default:
  1010. break;
  1011. }
  1012. }
  1013. // If a non calibration request should be sent
  1014. else
  1015. {
  1016. switch(ucMsgCode_)
  1017. {
  1018. case BikePower::PAGE_GET_SET_PARAMETERS:
  1019. bpPages->EncodeMainData(ucMsgCode_, aucAckBuffer);
  1020. break;
  1021. case CommonData::PAGE70:
  1022. commonPages->Encode(commonPages->PAGE70, aucAckBuffer);
  1023. break;
  1024. default:
  1025. return;
  1026. }
  1027. }
  1028. if(!ucMsgExpectingAck)
  1029. {
  1030. ucAckRetryCount = 0;
  1031. ucMsgExpectingAck = ucMsgCode_;
  1032. }
  1033. requestAckMsg(aucAckBuffer);
  1034. }
  1035. /**************************************************************************
  1036. * BikePowerDisplay::GetDifference
  1037. *
  1038. * Gets the difference between the current and previous value, considering
  1039. * rollover
  1040. * Template allows using the function for UCHAR, USHORT and ULONG types
  1041. *
  1042. * CurrentVal_: Current value
  1043. * PreviousVal_: Previous value
  1044. *
  1045. * returns: difference between the two values
  1046. *
  1047. **************************************************************************/
  1048. template< typename T>
  1049. T BikePowerDisplay::GetDifference(T CurrentVal_, T PreviousVal_)
  1050. {
  1051. T MaxVal = (T) 0xFFFFFF;
  1052. T Diff = CurrentVal_ - PreviousVal_;
  1053. if(PreviousVal_ > CurrentVal_)
  1054. Diff = MaxVal + Diff + 1; // handle rollover
  1055. return Diff;
  1056. }
  1057. void BikePowerDisplay::checkBox_InvalidCrankLength_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
  1058. {
  1059. if(checkBox_InvalidCrankLength->Checked)
  1060. {
  1061. checkBox_AutoCrank->Checked = false;
  1062. numericUpDown_CrankLength->Enabled = false;
  1063. }
  1064. else
  1065. {
  1066. numericUpDown_CrankLength->Enabled = true;
  1067. }
  1068. }
  1069. void BikePowerDisplay::checkBox_AutoCrank_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
  1070. {
  1071. if(checkBox_AutoCrank->Checked)
  1072. {
  1073. checkBox_InvalidCrankLength->Checked = false;
  1074. numericUpDown_CrankLength->Enabled = false;
  1075. }
  1076. else
  1077. numericUpDown_CrankLength->Enabled = true;
  1078. }