BikePowerSensor.cpp 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872
  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. #pragma once
  9. #include "StdAfx.h"
  10. #include "BikePowerSensor.h"
  11. /**************************************************************************
  12. * BikePowerSensor::ANT_eventNotification
  13. *
  14. * Process ANT channel event
  15. *
  16. * ucEventCode_: code of ANT channel event
  17. * pucEventBuffer_: pointer to buffer containing data received from ANT,
  18. * or a pointer to the transmit buffer in the case of an EVENT_TX
  19. *
  20. * returns: N/A
  21. *
  22. **************************************************************************/
  23. void BikePowerSensor::ANT_eventNotification(UCHAR ucEventCode_, UCHAR* pucEventBuffer_)
  24. {
  25. switch(ucEventCode_)
  26. {
  27. case EVENT_TX:
  28. HandleTransmit((UCHAR*) pucEventBuffer_);
  29. UpdateDisplay();
  30. break;
  31. case EVENT_RX_ACKNOWLEDGED:
  32. if(pucEventBuffer_[0] == commonPages->PAGE70)
  33. {
  34. commonPages->Decode((UCHAR*)pucEventBuffer_);
  35. HandleRequest((UCHAR*)pucEventBuffer_);
  36. }
  37. else if(pucEventBuffer_[0] == bpPages->PAGE_GET_SET_PARAMETERS)
  38. {
  39. bpPages->ucCrankLength = pucEventBuffer_[4];
  40. HandleReceive((UCHAR*)pucEventBuffer_);
  41. }
  42. else
  43. {
  44. HandleCalibration((UCHAR*) pucEventBuffer_);
  45. UpdateCalDisplay();
  46. }
  47. break;
  48. case EVENT_TRANSFER_TX_COMPLETED:
  49. break;
  50. case EVENT_TRANSFER_TX_FAILED:
  51. break;
  52. default:
  53. break;
  54. }
  55. }
  56. /**************************************************************************
  57. * BikePowerSensor::InitializeSim
  58. *
  59. * Initializes simulator variables
  60. *
  61. * returns: N/A
  62. *
  63. **************************************************************************/
  64. void BikePowerSensor::InitializeSim()
  65. {
  66. ulTimerInterval = 667; //90rpm
  67. ulRunTime1000 = 0;
  68. // Simulation settings
  69. bSweepAscending = TRUE;
  70. ucSimDataType = SIM_FIXED;
  71. bByCadence = TRUE;
  72. bStop = FALSE;
  73. bCoast = FALSE;
  74. bCalSuccess = TRUE;
  75. ucCurPedalPwrValue = System::Convert::ToByte(this->numericUpDown_PedalPwr_CurrOutput->Value);
  76. ucNumWheelGearTeeth = System::Convert::ToByte(this->numericUpDown_Sim_WheelGearTeeth->Value);
  77. ucNumCrankGearTeeth = System::Convert::ToByte(this->numericUpDown_Sim_CrankGearTeeth->Value);
  78. ucWheelCircumference100 = System::Convert::ToByte(this->numericUpDown_Sim_WheelCircumference->Value); // Wheel circumference (cm)
  79. usWheelTorque32 = System::Convert::ToUInt16(32 * this->numericUpDown_Sim_WheelTorque->Value); // Wheel torque (1/10 Nm)
  80. usCrankTorque32 = System::Convert::ToUInt16(32 * this->numericUpDown_Sim_CrankTorque->Value); // Crank torque (1/10 Nm)
  81. ulMinValue1000 = System::Convert::ToUInt32(1000 * this->numericUpDown_Sim_MinOutput->Value); // Min speed or cadence (resolution 1/1000)
  82. ulCurValue1000 = System::Convert::ToUInt32(1000 * this->numericUpDown_Sim_CurOutput->Value); // Current speed or cadence (resolution 1/1000)
  83. ulMaxValue1000 = System::Convert::ToUInt32(1000 * this->numericUpDown_Sim_MaxOutput->Value); // Max speed or cadence (resolution 1/1000)
  84. ulEventTime1000 = 0;
  85. sCalData = System::Convert::ToInt16(this->numericUpDown_Cal_CalNumber->Value); // Calibration data
  86. usCalOffset = System::Convert::ToUInt16(this->numericUpDown_Cal_CalNumber->Value); // CTF calibration data
  87. bpPages->usSlope10 = System::Convert::ToUInt16(10* this->numericUpDown_Ppg_SlopeConstant->Value); // Slope (1/10 Nm/Hz)
  88. bpPages->sRawTorque = System::Convert::ToInt16(this->numericUpDown_Cal_RawTorque->Value); // Raw torque (signed)
  89. bpPages->sOffsetTorque = System::Convert::ToInt16(this->numericUpDown_Cal_OffsetTorque->Value); // Offset torque (signed)
  90. this->listBox_Cal_AZStatus->SelectedIndex = 1; // Auto Zero On
  91. bpPages->bAutoZeroEnable = TRUE;
  92. bpPages->bAutoZeroOn = TRUE;
  93. // Paging
  94. bpPages->eType = BikePower::SensorType::POWER_ONLY; // Power only sensor by default
  95. bTxPage82 = TRUE; // Include battery info
  96. bTxAZ = TRUE; // Include auto zero support
  97. bTxCadence = TRUE; // Include cadence
  98. bTxPedalPower = TRUE; //Include pedal power
  99. bRightPedal = FALSE; //Unknown pedal side contribution to power
  100. ucPowerInterleave = System::Convert::ToByte(this->numericUpDown_Ppg_BasicPowerInterlvTime->Value); // Interleaving interval from UI
  101. ucEventFreq10 = System::Convert::ToByte(10 * this->numericUpDown_Ppg_TimerEventFreq->Value); // Event freq from UI
  102. eUpdateType = BikePower::UpdateType::TIME_SYNCH; // Event synchronous sensor
  103. ucMsgExpectingAck = 0; // No messages pending at initialization
  104. // Common Data (initial values set on UI)
  105. commonPages->usBatVoltage256 = (System::Convert::ToByte(this->numericUpDown_Bat_VoltInt->Value) << 8) + (System::Convert::ToByte(this->numericUpDown_Bat_VoltFrac->Value));
  106. this->label_Voltage_Display->Text = ((double) commonPages->usBatVoltage256/256).ToString(); // Display in V
  107. commonPages->usMfgID = System::Convert::ToUInt16(this->textBox_Glb_ManfIDChange->Text);
  108. commonPages->ulSerialNum = System::Convert::ToUInt32(this->textBox_Glb_SerialNumChange->Text);
  109. commonPages->ucHwVersion = System::Convert::ToByte(this->textBox_Glb_HardwareVerChange->Text);
  110. commonPages->ucSwVersion = System::Convert::ToByte(this->textBox_Glb_SoftwareVerChange->Text);
  111. commonPages->usModelNum = System::Convert::ToUInt16(this->textBox_Glb_ModelNumChange->Text);
  112. commonPages->eTimeResolution = CommonData::TimeResolution::TWO; // Two second resolution
  113. commonPages->ulOpTime = 0;
  114. this->listBox_Bat_Status->SelectedIndex = 2; // OK
  115. commonPages->eBatStatus = CommonData::BatStatus::OK;
  116. ucBcastMessage = 0;
  117. ucBcastCount = 0;
  118. ucTransmissionCount = 0;
  119. bpPages->ucCrankLength = (UCHAR)(((float)numericUpDown_CrankLength->Value - (float)110.0) / (float)0.5);
  120. bpPages->ucSensorCapabilities = 0;
  121. bpPages->ucSensorStatus = 0x3E;
  122. bpPages->ucLeftTorqueEffectiveness = (UCHAR)(numericUpDown_LeftTorqueEffectiveness->Value * 2);
  123. bpPages->ucRightTorqueEffectiveness = (UCHAR) (numericUpDown_RightTorqueEffectiveness->Value * 2);
  124. bpPages->ucLeftPedalSmoothness = (UCHAR) (numericUpDown_LeftPedalSmoothness->Value * 2);
  125. bpPages->ucRightPedalSmoothness = (UCHAR) (numericUpDown_RightPedalSmoothness->Value * 2);
  126. }
  127. /**************************************************************************
  128. * BikePowerSensor::HandleTransmit
  129. *
  130. * Encode data generated by simulator for transmission
  131. *
  132. * pucTxBuffer_: pointer to the transmit buffer
  133. *
  134. * returns: N/A
  135. *
  136. **************************************************************************/
  137. void BikePowerSensor::HandleTransmit(UCHAR* pucTxBuffer_)
  138. {
  139. static ULONG ulMessageCount = 0;
  140. static UCHAR ucExtMesgType = 0;
  141. UCHAR ucPageNum;
  142. if(ucBcastMessage)
  143. {
  144. switch(ucBcastMessage)
  145. {
  146. case bpPages->PAGE_GET_SET_PARAMETERS:
  147. ucBcastCount++;
  148. bpPages->EncodeMainData(ucBcastMessage, pucTxBuffer_);
  149. if(ucBcastCount > ucTransmissionCount)
  150. ucBcastMessage = 0;
  151. break;
  152. default:
  153. if((bpPages->eType == BikePower::SensorType::CRANK_TORQUE_FREQ) && (ucBcastMessage == BikePower::CAL_REQUEST))
  154. {
  155. bpPages->EncodeCTFCalibrationPage(BikePower::CTF_OFFSET, usCalOffset, pucTxBuffer_); // CTF sensors, send calibration offset
  156. ucBcastCount++;
  157. if(ucBcastCount > BikePower::MAX_RETRY_CTF)
  158. {
  159. ucBcastMessage = 0;
  160. ucBcastCount = 0;
  161. }
  162. }
  163. else if(ucBcastMessage)
  164. {
  165. switch(ucBcastMessage)
  166. {
  167. case BikePower::CAL_REQUEST: // Manual calibration request, send calibration response
  168. if(bCalSuccess) // Other sensors, report success or failure
  169. bpPages->EncodeCalibrationResponse(BikePower::CAL_SUCCESS, bpPages->bAutoZeroEnable, bpPages->bAutoZeroOn, sCalData, pucTxBuffer_);
  170. else
  171. bpPages->EncodeCalibrationResponse(BikePower::CAL_FAIL, bpPages->bAutoZeroEnable, bpPages->bAutoZeroOn, sCalData, pucTxBuffer_);
  172. break;
  173. case BikePower::CAL_AUTOZERO_CONFIG: // Auto zero calibration request, send response (which includes auto zero status)
  174. if(bCalSuccess)
  175. bpPages->EncodeCalibrationResponse(BikePower::CAL_SUCCESS, bpPages->bAutoZeroEnable, bpPages->bAutoZeroOn, sCalData, pucTxBuffer_);
  176. else
  177. bpPages->EncodeCalibrationResponse(BikePower::CAL_FAIL, bpPages->bAutoZeroEnable, bpPages->bAutoZeroOn, sCalData, pucTxBuffer_);
  178. break;
  179. case BikePower::CTF_SLOPE:
  180. bpPages->EncodeCTFCalibrationPage(BikePower::CTF_ACK, BikePower::CTF_SLOPE, pucTxBuffer_);
  181. break;
  182. case BikePower::CTF_SERIAL: // ACK save serial to flash
  183. bpPages->EncodeCTFCalibrationPage(BikePower::CTF_ACK, BikePower::CTF_SERIAL, pucTxBuffer_);
  184. break;
  185. default:
  186. return;
  187. }
  188. ucBcastMessage = 0;
  189. ucBcastCount = 0;
  190. }
  191. break;
  192. }
  193. return;
  194. }
  195. // Figure out what page to send
  196. // Set first to primary page according to sensor type
  197. switch(bpPages->eType)
  198. {
  199. case BikePower::SensorType::POWER_ONLY:
  200. ucPageNum = BikePower::PAGE_POWER;
  201. break;
  202. case BikePower::SensorType::TORQUE_WHEEL:
  203. ucPageNum = BikePower::PAGE_WHEEL_TORQUE;
  204. break;
  205. case BikePower::SensorType::TORQUE_CRANK:
  206. ucPageNum = BikePower::PAGE_CRANK_TORQUE;
  207. break;
  208. case BikePower::SensorType::CRANK_TORQUE_FREQ:
  209. ucPageNum = BikePower::PAGE_CTF;
  210. break;
  211. default:
  212. break;
  213. }
  214. // Handle interleaving:
  215. // The page with lowest frequency takes priority when there is a conflict
  216. // Every 121st message - one of the two global data pages, or the autozero support page (except CTF)
  217. if(bpPages->eType != BikePower::SensorType::CRANK_TORQUE_FREQ)
  218. {
  219. if(ulMessageCount % BikePower::INTERVAL_COMMON_AND_AZ == 0 && ulMessageCount != 0)
  220. {
  221. if(ucExtMesgType == 0)
  222. {
  223. ucPageNum = CommonData::PAGE80;
  224. ucExtMesgType++;
  225. }
  226. else if(ucExtMesgType == 1)
  227. {
  228. ucPageNum = CommonData::PAGE81;
  229. if(bTxAZ)
  230. ucExtMesgType++;
  231. else
  232. ucExtMesgType = 0;
  233. }
  234. else if(ucExtMesgType == 2)
  235. {
  236. ucPageNum = BikePower::PAGE_CALIBRATION;
  237. ucExtMesgType = 0;
  238. }
  239. }
  240. // Every 61st message - battery status (except CTF)
  241. else if((ulMessageCount % BikePower::INTERVAL_BATTERY == 0) && bTxPage82 && ulMessageCount != 0)
  242. {
  243. ucPageNum = CommonData::PAGE82;
  244. }
  245. // Every 2-9 messages (user defined) - basic power (wheel/crank torque)
  246. else if((ulMessageCount % ucPowerInterleave == 0) && bpPages->eType != BikePower::SensorType::POWER_ONLY && ulMessageCount != 0)
  247. {
  248. ucPageNum = BikePower::PAGE_POWER;
  249. }
  250. // Every 5 messages, if enabled, toque effectiveness & pedal smoothness page
  251. else if((ulMessageCount % BikePower::INTERVAL_TEPS == 1) && bTxPage19) // offset by 1, so it doesn't overlap with basic power if sent every 5 messages
  252. {
  253. ucPageNum = BikePower::PAGE_TEPS;
  254. }
  255. ulMessageCount++;
  256. }
  257. // Main Bike Power Data Pages
  258. if(ucPageNum >= BikePower::PAGE_POWER && ucPageNum <= BikePower::PAGE_CTF)
  259. {
  260. try
  261. {
  262. bpPages->EncodeMainData(ucPageNum, pucTxBuffer_);
  263. }
  264. catch(BikePower::Error^ errorMain)
  265. {
  266. }
  267. }
  268. // Calibration (Auto Zero Support)
  269. if(ucPageNum == BikePower::PAGE_CALIBRATION)
  270. bpPages->EncodeAutoZeroSupport(pucTxBuffer_);
  271. // Common Pages
  272. if(ucPageNum >= CommonData::PAGE80 && ucPageNum <= CommonData::PAGE82)
  273. {
  274. try
  275. {
  276. commonPages->Encode(ucPageNum, pucTxBuffer_);
  277. }
  278. catch(CommonData::Error^ errorCommon)
  279. {
  280. }
  281. }
  282. }
  283. /**************************************************************************
  284. * BikePowerSensor::HandleCalibration
  285. *
  286. * Decodes recived calibration messages and sends a response if required
  287. *
  288. * pucRxBuffer_: pointer to the receive buffer
  289. *
  290. * returns: N/A
  291. *
  292. **************************************************************************/
  293. void BikePowerSensor::HandleCalibration(UCHAR* pucRxBuffer_)
  294. {
  295. BOOL bAutoZeroInvalid = FALSE;
  296. UCHAR ucPageNum = pucRxBuffer_[0];
  297. if(ucPageNum == BikePower::PAGE_CALIBRATION)
  298. {
  299. try
  300. {
  301. bpPages->Decode(pucRxBuffer_);
  302. }
  303. catch(BikePower::Error^ errorBikePower)
  304. {
  305. if(errorBikePower->bUndefAutoZero)
  306. bAutoZeroInvalid = TRUE;
  307. }
  308. if(bpPages->ucRxCalibrationID == BikePower::CAL_REQUEST)
  309. SendCalibrationResponse(BikePower::CAL_REQUEST);
  310. if(bpPages->ucRxCalibrationID == BikePower::CAL_AUTOZERO_CONFIG)
  311. {
  312. // The received auto zero status (if valid) is updated directly when decoding
  313. BOOL bPrevCalStatus = bCalSuccess;
  314. if(bAutoZeroInvalid)
  315. bCalSuccess = FALSE; // Report as failure if an invalid status was received, regardless of how it is set on interface
  316. SendCalibrationResponse(BikePower::CAL_AUTOZERO_CONFIG);
  317. bCalSuccess = bPrevCalStatus;
  318. }
  319. if(bpPages->ucRxCalibrationID == BikePower::CAL_CTF)
  320. {
  321. if(bpPages->ucRxCTFMsgID == BikePower::CTF_SLOPE)
  322. {
  323. // Validate and send response
  324. if(bpPages->usCalSlope > BikePower::MAX_SLOPE)
  325. bpPages->usCalSlope = BikePower::MAX_SLOPE;
  326. else if(bpPages->usCalSlope < BikePower::MIN_SLOPE)
  327. bpPages->usCalSlope = BikePower::MIN_SLOPE;
  328. bpPages->usSlope10 = bpPages->usCalSlope; // Save on flash
  329. SendCalibrationResponse(BikePower::CTF_SLOPE);
  330. }
  331. else if(bpPages->ucRxCTFMsgID == BikePower::CTF_SERIAL)
  332. {
  333. // The received serial num is also already updated by the Bike Power decoding
  334. this->commonPages->ulSerialNum = bpPages->usCalSerialNum; // Save on flash
  335. SendCalibrationResponse(BikePower::CTF_SERIAL);
  336. }
  337. }
  338. }
  339. }
  340. void BikePowerSensor::HandleRequest(UCHAR* pucRxBuffer_)
  341. {
  342. //Request pages supported so far
  343. if(commonPages->ucReqPageNum != bpPages->PAGE_GET_SET_PARAMETERS)
  344. return;
  345. if(!ucBcastMessage)
  346. {
  347. ucTransmissionCount = (commonPages->ucReqTransResp & 0x7F);
  348. ucBcastCount = 1; // Reset transmission counter
  349. ucBcastMessage = commonPages->ucReqPageNum; // Set code to message for which to transmit
  350. }
  351. }
  352. void BikePowerSensor::HandleReceive(UCHAR *pucRxBuffer_)
  353. {
  354. switch(pucRxBuffer_[0])
  355. {
  356. case BikePower::PAGE_GET_SET_PARAMETERS:
  357. if(bpPages->ucCrankLength < 0xFE)
  358. {
  359. numericUpDown_CrankLength->Value = (Decimal)(((float)bpPages->ucCrankLength * (float)0.5) + (float)110.0);
  360. checkBox_InvalidCrankLength->Checked = false;
  361. }
  362. else if(bpPages->ucCrankLength == 0xFE)
  363. {
  364. numericUpDown_CrankLength->Value = (Decimal)172.5;
  365. bpPages->ucCrankLength = 0x7D;
  366. checkBox_InvalidCrankLength->Checked = false;
  367. }
  368. else if(bpPages->ucCrankLength == 0xFF)
  369. checkBox_InvalidCrankLength->Checked = true;
  370. break;
  371. default:
  372. break;
  373. }
  374. }
  375. /**************************************************************************
  376. * BikePowerSensor::SendCalibrationResponse
  377. *
  378. * Sends calibration message according to the message code, using the values
  379. * for the parameters previously set on the GUI
  380. *
  381. * ucMsgCode_: message ID of the calibration message requiring a response
  382. * Supported messages:
  383. * - calibration response (success or fail, or for CTF sensors, calibration offset)
  384. * - auto zero calibration response
  385. * - serial CTF ack
  386. * - slope CTF ack
  387. *
  388. * returns: N/A
  389. *
  390. **************************************************************************/
  391. void BikePowerSensor::SendCalibrationResponse(UCHAR ucMsgCode_)
  392. {
  393. // Send acknowledged message
  394. if(!ucBcastMessage)
  395. {
  396. ucBcastCount = 1; // Reset retransmission counter
  397. ucBcastMessage = ucMsgCode_;
  398. }
  399. }
  400. /**************************************************************************
  401. * BikePowerSensor::onTimerTock
  402. *
  403. * Simulates a sensor event, updating simulator data based on this event
  404. * Modifications to the timer interval are applied immediately after this
  405. * at ANTChannel
  406. *
  407. * usEventTime_: current time (ms)
  408. *
  409. * returns: N/A
  410. *
  411. **************************************************************************/
  412. void BikePowerSensor::onTimerTock(USHORT eventTime_)
  413. {
  414. bpPages->usTime2000 = 2 * eventTime_; // Time in intervals of 1/2000s
  415. if(bTxPage82) // Update battery page if enabled
  416. {
  417. // Update operating time
  418. ulRunTime1000 += ulTimerInterval; // in ms
  419. while(ulRunTime1000/((USHORT) 1000 * (UCHAR) commonPages->eTimeResolution))
  420. {
  421. (commonPages->ulOpTime)++; // elapsed time is updated every 2 or 16 seconds, depending on resolution
  422. ulRunTime1000 -= ((USHORT) 1000 * (UCHAR) commonPages->eTimeResolution);
  423. }
  424. }
  425. // Calculate next value, if sweeping
  426. if(ucSimDataType == SIM_SWEEP && !bStop && !bCoast)
  427. {
  428. // Value sweeps between max and min
  429. // 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
  430. ULONG tempOffset = ulMaxValue1000 - ulMinValue1000;
  431. tempOffset = ((tempOffset & 0x800) >> 6) + ((tempOffset & 0x400) >> 5) + ((tempOffset & 0x200) >> 4) + 0xFF;
  432. if(bSweepAscending)
  433. ulCurValue1000 += tempOffset;
  434. else
  435. ulCurValue1000 -= tempOffset;
  436. // Ensure value is more than min and less than max
  437. if(ulCurValue1000 > ulMaxValue1000)
  438. {
  439. ulMaxValue1000 = ulMaxValue1000;
  440. bSweepAscending = FALSE;
  441. }
  442. if(ulCurValue1000 < ulMinValue1000)
  443. {
  444. ulCurValue1000 = ulMinValue1000;
  445. bSweepAscending = TRUE;
  446. }
  447. }
  448. // Update cadence
  449. if(bByCadence)
  450. {
  451. bpPages->ucCadence = (UCHAR) (ulCurValue1000/1000); // We already have cadence
  452. ulSpeed1000 = CadenceToSpeed(ulCurValue1000); // Get speed from cadence
  453. }
  454. else
  455. {
  456. bpPages->ucCadence = (UCHAR) (SpeedToCadence(ulCurValue1000)/1000); // Get cadence from speed
  457. ulSpeed1000 = ulCurValue1000; // We already have speed
  458. }
  459. if(bTxPedalPower)
  460. {
  461. if(bRightPedal)
  462. {
  463. UCHAR ucTemp = 0x00;
  464. ucTemp = ucCurPedalPwrValue | 0x80; // 0x80 mask for right pedal power contribution
  465. bpPages->ucPedalPower = ucTemp;
  466. }
  467. else
  468. bpPages->ucPedalPower = ucCurPedalPwrValue;
  469. }
  470. // Calculate sensor event interval (in ms) based on the location of the sensor, wheel or crank
  471. ULONG ulEventPeriod1000;
  472. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  473. {
  474. if(bpPages->ucCadence)
  475. ulEventPeriod1000 = ((ULONG) 60000 * ucNumWheelGearTeeth)/((ULONG) bpPages->ucCadence * ucNumCrankGearTeeth); // rpm -> ms
  476. else
  477. ulEventPeriod1000 = 600000; // No events, set interval to a very large value
  478. }
  479. else // crank sensor
  480. {
  481. if(bpPages->ucCadence)
  482. ulEventPeriod1000 = (ULONG) 60000/bpPages->ucCadence; // rpm -> ms
  483. else
  484. ulEventPeriod1000 = 600000; // No events, set interval to a very large value
  485. }
  486. // Update values, depending on type of updates (event or time synchronous)
  487. if(eUpdateType == BikePower::UpdateType::EVENT_SYNCH)
  488. {
  489. ulTimerInterval = ulEventPeriod1000; // Event synchronous, the next interval corresponds to a wheel or crank rotation
  490. //If stopped and event driven, there is no update at all, because the sensor never fires
  491. //If coasting, event driven, and a crank mounted sensor there is no update at all, because the sensor never fires
  492. if(bStop || (bCoast &&
  493. (bpPages->eType == BikePower::SensorType::TORQUE_CRANK ||
  494. bpPages->eType == BikePower::SensorType::CRANK_TORQUE_FREQ)))
  495. return;
  496. // If there is an event, update event count
  497. switch(bpPages->eType)
  498. {
  499. case BikePower::SensorType::TORQUE_WHEEL:
  500. bpPages->ucWTEventCount++;
  501. bpPages->ucWheelTicks++;
  502. break;
  503. case BikePower::SensorType::TORQUE_CRANK:
  504. bpPages->ucCTEventCount++;
  505. bpPages->ucCrankTicks++;
  506. break;
  507. case BikePower::SensorType::CRANK_TORQUE_FREQ:
  508. bpPages->ucCTFEventCount++;
  509. break;
  510. default: // no event synch Power Only sensor
  511. break;
  512. }
  513. }
  514. else
  515. {
  516. ulTimerInterval = (ULONG) 10000/ucEventFreq10; // Time syncrhonous, fixed interval. Freq in 1/10 Hz -> ms
  517. // The data page is updated every time for time synchronous sensors, so the event count is incremented
  518. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  519. bpPages->ucWTEventCount++;
  520. else if(bpPages->eType == BikePower::SensorType::TORQUE_CRANK)
  521. bpPages->ucCTEventCount++;
  522. // If there are wheel or crank revolutions, the ticks also increment
  523. if(!bStop && (!bCoast || (bCoast && bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)))
  524. {
  525. ulEventTime1000 += ulTimerInterval;
  526. UCHAR ucTicks = (UCHAR) (ulEventTime1000/ulEventPeriod1000); // Number of ticks since last sensor event
  527. ulEventTime1000 = ulEventTime1000%ulEventPeriod1000; // Update last sensor event time for next calculation
  528. switch(bpPages->eType)
  529. {
  530. case BikePower::SensorType::TORQUE_WHEEL:
  531. bpPages->ucWheelTicks += ucTicks;
  532. break;
  533. case BikePower::SensorType::TORQUE_CRANK:
  534. bpPages->ucCrankTicks += ucTicks;
  535. break;
  536. default: // no time synch CTF
  537. break;
  538. }
  539. }
  540. }
  541. //If we are not pedalling there is, theoretically, no torque and thus no power; also cadence will be zero
  542. if(bStop || bCoast)
  543. {
  544. bpPages->usPower = 0;
  545. bpPages->ucCadence = 0;
  546. bpPages->ucPedalPower = 0;
  547. }
  548. else
  549. {
  550. bpPages->usPower = (USHORT) ( (((ULONG) PI256 * bpPages->ucCadence * usCrankTorque32)/((ULONG) 30 * 32) + 128) >> 8); // 2*pi*Cadence*CrankTorque/60; convert CrankTorque from 1/32Nm to Nm, and constant PI256 = pi * 256. Adding 0.5 (128/256) for rounding.
  551. }
  552. // Basic power page is updated every time (except if CTF)
  553. if(bpPages->eType != BikePower::SensorType::CRANK_TORQUE_FREQ)
  554. {
  555. bpPages->ucPowEventCount++;
  556. bpPages->usAcumPower += bpPages->usPower;
  557. }
  558. if(bpPages->eType == BikePower::SensorType::TORQUE_WHEEL)
  559. {
  560. //Don't update the wheel period if we stopped
  561. if(!bStop)
  562. bpPages->usAcumWheelPeriod2048 += (USHORT) ((ulEventPeriod1000*2048)/1000);
  563. // If we are coasting the wheel event is happening but there is, theoretically, no torque
  564. if(!bCoast)
  565. bpPages->usAcumTorque32 += usWheelTorque32; // Update cumulative torque
  566. }
  567. else if(bpPages->eType == BikePower::SensorType::TORQUE_CRANK)
  568. {
  569. //Don't update the crank period if it is not spinning
  570. if(!bStop && !bCoast)
  571. bpPages->usAcumCrankPeriod2048 += (USHORT) ((ulEventPeriod1000*2048)/1000);
  572. // If we are coasting there is no torque
  573. if(!bCoast)
  574. bpPages->usAcumTorque32 += usCrankTorque32; // Update cumulative torque
  575. }
  576. else if(bpPages->eType == BikePower::SensorType::CRANK_TORQUE_FREQ)
  577. {
  578. //If we are coasting there is no torque
  579. if(!bCoast)
  580. bpPages->usTorqueTicks += (USHORT) ((((ULONG) usCrankTorque32 * bpPages->usSlope10)/(32 * 10) + (ULONG) usCalOffset) * ulTimerInterval/1000);
  581. }
  582. // If transmission of cadence is disabled, blank it
  583. if(!bTxCadence)
  584. bpPages->ucCadence = BikePower::INVALID_CADENCE;
  585. // If transmission of pedal power is disabled, blank it
  586. if(!bTxPedalPower)
  587. bpPages->ucPedalPower = BikePower::RESERVED;
  588. }
  589. /***************************************************************************
  590. * BikePowerSensor::UpdateDisplay
  591. *
  592. * Updates displayed simulator data on GUI
  593. *
  594. * returns: N/A
  595. *
  596. **************************************************************************/
  597. void BikePowerSensor::UpdateDisplay()
  598. {
  599. if(bTxPage82)
  600. {
  601. this->label_Bat_ElpTimeDisplay->Text = ((ULONG) (commonPages->ulOpTime & CommonData::OPERATING_TIME_MASK) * (UCHAR) commonPages->eTimeResolution).ToString();
  602. }
  603. if(ucSimDataType == SIM_SWEEP)
  604. this->numericUpDown_Sim_CurOutput->Value = System::Convert::ToDecimal((double)ulCurValue1000/1000);
  605. if(bStop)
  606. {
  607. // The speed is just a display, so we zero it so the user knows the bike is stopped
  608. this->label_Trn_InstSpeedDisplay->Text = "0";
  609. // We display zero cadence to avoid user confusion, but the value transmitted will remain the same
  610. this->label_Trn_CadenceDisplay->Text = "0";
  611. // No power can be generated with no movement
  612. this->label_Trn_PowerDisplay->Text = "0";
  613. if(bpPages->ucPedalPower != BikePower::RESERVED)
  614. {
  615. this->label_Trn_PedalPwrDisplay->Text = "0";
  616. this->label_Trn_PedalDisplay->Text = "---";
  617. }
  618. return; // no other sensor data updated
  619. }
  620. else if(bCoast && bpPages->eType == BikePower::SensorType::TORQUE_CRANK)
  621. {
  622. // We display zero cadence to avoid user confusion, but the value transmitted will remain the same
  623. this->label_Trn_CadenceDisplay->Text = "0";
  624. //No power can be generated with no torque
  625. this->label_Trn_PowerDisplay->Text = "0";
  626. return; // no other sensor data updated
  627. }
  628. if(bCoast)
  629. {
  630. if(bpPages->ucPedalPower != BikePower::RESERVED)
  631. {
  632. this->label_Trn_PedalPwrDisplay->Text = "0";
  633. this->label_Trn_PedalDisplay->Text = "---";
  634. }
  635. }
  636. // Not all values are directly transmitted by all sensor types, but they are calculated at the receiver
  637. if(!bpPages->IsCadenceInvalid(bpPages->ucCadence))
  638. this->label_Trn_CadenceDisplay->Text = bpPages->ucCadence.ToString();
  639. else
  640. this->label_Trn_CadenceDisplay->Text = "Off";
  641. this->label_Trn_InstSpeedDisplay->Text = ((double) ulSpeed1000/1000).ToString();
  642. this->label_Trn_PowerDisplay->Text = bpPages->usPower.ToString();
  643. if(bpPages->eType != BikePower::SensorType::CRANK_TORQUE_FREQ)
  644. {
  645. if(bpPages->ucPedalPower != BikePower::RESERVED) //Pedal power byte is used
  646. {
  647. UCHAR ucTemp = 0x00;
  648. if(0x80 & bpPages->ucPedalPower)
  649. this->label_Trn_PedalDisplay->Text = "Right"; // Right pedal power contribution
  650. else
  651. this->label_Trn_PedalDisplay->Text = "Unknown"; // Unknown pedal power contribution
  652. ucTemp = ((bpPages->ucPedalPower) & 0x7F); // 0x7F is a mask to remove "Pedal Differentiation Bit" and find
  653. // out pedal power percent value
  654. this->label_Trn_PedalPwrDisplay->Text = ucTemp.ToString();
  655. }
  656. else
  657. {
  658. this->label_Trn_PedalPwrDisplay->Text = "Off";
  659. this->label_Trn_PedalDisplay->Text = "---";
  660. }
  661. }
  662. // Sensor specific data
  663. switch(bpPages->eType)
  664. {
  665. case BikePower::SensorType::POWER_ONLY:
  666. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucPowEventCount.ToString();
  667. this->label_Trn_AccumOneDisplay->Text = bpPages->usAcumPower.ToString();
  668. break;
  669. case BikePower::SensorType::TORQUE_WHEEL:
  670. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucWTEventCount.ToString();
  671. this->label_Trn_EventCountDisplay->Text = bpPages->ucWheelTicks.ToString();
  672. this->label_Trn_AccumTwoDisplay->Text = bpPages->usAcumTorque32.ToString();
  673. this->label_Trn_AccumOneDisplay->Text = bpPages->usAcumWheelPeriod2048.ToString();
  674. break;
  675. case BikePower::SensorType::TORQUE_CRANK:
  676. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucCTEventCount.ToString();
  677. this->label_Trn_EventCountDisplay->Text = bpPages->ucCrankTicks.ToString();
  678. this->label_Trn_AccumTwoDisplay->Text = bpPages->usAcumTorque32.ToString();
  679. this->label_Trn_AccumOneDisplay->Text = bpPages->usAcumCrankPeriod2048.ToString();
  680. break;
  681. case BikePower::SensorType::CRANK_TORQUE_FREQ:
  682. this->label_Trn_UpdateCountDisplay->Text = bpPages->ucCTFEventCount.ToString();
  683. this->label_Trn_AccumTwoDisplay->Text = bpPages->usTorqueTicks.ToString();
  684. break;
  685. default:
  686. break;
  687. }
  688. }
  689. /***************************************************************************
  690. * BikePowerSensor::UpdateCalDisplay
  691. *
  692. * Updates received calibration data
  693. *
  694. * returns: N/A
  695. *
  696. **************************************************************************/
  697. void BikePowerSensor::UpdateCalDisplay()
  698. {
  699. // Update Auto Zero status
  700. if(!bpPages->bAutoZeroEnable)
  701. this->listBox_Cal_AZStatus->SelectedIndex = 2; // Not supported
  702. else if(bpPages->bAutoZeroOn)
  703. this->listBox_Cal_AZStatus->SelectedIndex = 1; // On
  704. else
  705. this->listBox_Cal_AZStatus->SelectedIndex = 0; // Off
  706. // Update slope
  707. this->numericUpDown_Ppg_SlopeConstant->Value = (System::Decimal)bpPages->usSlope10/10;
  708. // Update serial number
  709. this->textBox_Glb_SerialNumChange->Text = commonPages->ulSerialNum.ToString();
  710. }
  711. /***************************************************************************
  712. * BikePowerSensor::radioButton_SensorType_CheckedChanged
  713. *
  714. * Sets simulator type and updates interface to enable sensor specific features
  715. *
  716. * returns: N/A
  717. *
  718. **************************************************************************/
  719. System::Void BikePowerSensor::radioButton_SensorType_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  720. {
  721. // Power Only Sensor
  722. if(this->radioButton_Power->Checked)
  723. {
  724. bpPages->eType = BikePower::SensorType::POWER_ONLY;
  725. this->label_Trn_AccumOne->Text = "Acc.Power:";
  726. this->label_Trn_AccumOne->Visible = true;
  727. this->label_Trn_AccumOneDisplay->Visible = true;
  728. this->label_Trn_AccumTwo->Visible = false;
  729. this->label_Trn_AccumTwoDisplay->Visible = false;
  730. this->checkBox_Cal_TorqAZMesg->Enabled = true;
  731. this->label_Cal_CalNum->Text = "Calibration Number To Send:";
  732. this->numericUpDown_Cal_CalNumber->Increment = System::Decimal(gcnew cli::array< System::Int32 >(4) {1000, 0, 0, 0});
  733. this->numericUpDown_Cal_CalNumber->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {32767, 0, 0, 0});
  734. this->numericUpDown_Cal_CalNumber->Minimum = System::Decimal(gcnew cli::array< System::Int32 >(4) {32768, 0, 0, System::Int32::MinValue});
  735. this->radioButton_Ppg_EventOnTime->Enabled = true;
  736. this->numericUpDown_Ppg_TimerEventFreq->Enabled = true;
  737. this->radioButton_Ppg_EventOnTime->Checked = true;
  738. this->radioButton_Ppg_EventOnRotation->Enabled = false;
  739. this->numericUpDown_Ppg_BasicPowerInterlvTime->Enabled = false;
  740. this->numericUpDown_Ppg_SlopeConstant->Enabled = false;
  741. this->checkBox_Bat_Status->Enabled = true;
  742. this->checkBox_Bat_Status->Checked = true;
  743. this->numericUpDown_Cal_CalNumber->Maximum = BikePower::MAX_CALDATA;
  744. this->numericUpDown_Cal_CalNumber->Minimum = BikePower::MIN_CALDATA;
  745. this->checkBox_Ppg_TxCadence->Enabled = true;
  746. this->checkBox_Ppg_TxPedalPwr->Enabled = true;
  747. this->numericUpDown_PedalPwr_CurrOutput->Enabled = true;
  748. this->checkBox_RightPedal->Enabled = true;
  749. this->tabControl_TEPS->Enabled = true;
  750. }
  751. // Wheel Torque Sensor
  752. else if(this->radioButton_WheelTorque->Checked)
  753. {
  754. bpPages->eType = BikePower::SensorType::TORQUE_WHEEL;
  755. this->label_Trn_AccumOne->Text = "Acc.Wheel P:";
  756. this->label_Trn_AccumTwo->Text = "Acc.Torque:";
  757. this->label_Trn_AccumOne->Visible = true;
  758. this->label_Trn_AccumOneDisplay->Visible = true;
  759. this->label_Trn_AccumTwo->Visible = true;
  760. this->label_Trn_AccumTwoDisplay->Visible = true;
  761. this->checkBox_Cal_TorqAZMesg->Enabled = true;
  762. this->label_Cal_CalNum->Text = "Calibration Number To Send:";
  763. this->numericUpDown_Cal_CalNumber->Increment = System::Decimal(gcnew cli::array< System::Int32 >(4) {1000, 0, 0, 0});
  764. this->numericUpDown_Cal_CalNumber->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {32767, 0, 0, 0});
  765. this->numericUpDown_Cal_CalNumber->Minimum = System::Decimal(gcnew cli::array< System::Int32 >(4) {32768, 0, 0, System::Int32::MinValue});
  766. this->radioButton_Ppg_EventOnTime->Enabled = true;
  767. this->numericUpDown_Ppg_TimerEventFreq->Enabled = true;
  768. this->radioButton_Ppg_EventOnRotation->Enabled = true;
  769. this->numericUpDown_Ppg_BasicPowerInterlvTime->Enabled = true;
  770. this->numericUpDown_Ppg_SlopeConstant->Enabled = false;
  771. this->checkBox_Bat_Status->Enabled = true;
  772. this->checkBox_Bat_Status->Checked = true;
  773. this->numericUpDown_Cal_CalNumber->Maximum = BikePower::MAX_CALDATA;
  774. this->numericUpDown_Cal_CalNumber->Minimum = BikePower::MIN_CALDATA;
  775. this->checkBox_Ppg_TxCadence->Enabled = true;
  776. this->checkBox_Ppg_TxPedalPwr->Enabled = true;
  777. this->numericUpDown_PedalPwr_CurrOutput->Enabled = true;
  778. this->checkBox_RightPedal->Enabled = true;
  779. this->tabControl_TEPS->Enabled = true;
  780. }
  781. // Crank Torque Sensor
  782. else if(this->radioButton_CrankTorque->Checked)
  783. {
  784. bpPages->eType = BikePower::SensorType::TORQUE_CRANK;
  785. this->label_Trn_AccumOne->Text = "Acc.Crank P:";
  786. this->label_Trn_AccumTwo->Text = "Acc.Torque:";
  787. this->label_Trn_AccumOne->Visible = true;
  788. this->label_Trn_AccumOneDisplay->Visible = true;
  789. this->label_Trn_AccumTwo->Visible = true;
  790. this->label_Trn_AccumTwoDisplay->Visible = true;
  791. this->checkBox_Cal_TorqAZMesg->Enabled = true;
  792. this->label_Cal_CalNum->Text = "Calibration Number To Send:";
  793. this->numericUpDown_Cal_CalNumber->Increment = System::Decimal(gcnew cli::array< System::Int32 >(4) {1000, 0, 0, 0});
  794. this->numericUpDown_Cal_CalNumber->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {32767, 0, 0, 0});
  795. this->numericUpDown_Cal_CalNumber->Minimum = System::Decimal(gcnew cli::array< System::Int32 >(4) {32768, 0, 0, System::Int32::MinValue});
  796. this->radioButton_Ppg_EventOnTime->Enabled = true;
  797. this->numericUpDown_Ppg_TimerEventFreq->Enabled = true;
  798. this->radioButton_Ppg_EventOnRotation->Enabled = true;
  799. this->numericUpDown_Ppg_BasicPowerInterlvTime->Enabled = true;
  800. this->numericUpDown_Ppg_SlopeConstant->Enabled = false;
  801. this->checkBox_Bat_Status->Enabled = true;
  802. this->checkBox_Bat_Status->Checked = true;
  803. this->numericUpDown_Cal_CalNumber->Maximum = BikePower::MAX_CALDATA;
  804. this->numericUpDown_Cal_CalNumber->Minimum = BikePower::MIN_CALDATA;
  805. this->checkBox_Ppg_TxCadence->Enabled = true;
  806. this->checkBox_Ppg_TxPedalPwr->Enabled = true;
  807. this->numericUpDown_PedalPwr_CurrOutput->Enabled = true;
  808. this->checkBox_RightPedal->Enabled = true;
  809. this->tabControl_TEPS->Enabled = true;
  810. }
  811. // Crank Torque Frequency Sensor
  812. else
  813. {
  814. bpPages->eType = BikePower::SensorType::CRANK_TORQUE_FREQ;
  815. this->label_Trn_AccumTwo->Text = "Acc.Torque:";
  816. this->label_Trn_AccumOne->Visible = false;
  817. this->label_Trn_AccumOneDisplay->Visible = false;
  818. this->label_Trn_AccumTwo->Visible = true;
  819. this->label_Trn_AccumTwoDisplay->Visible = true;
  820. this->checkBox_Cal_TorqAZMesg->Checked = false;
  821. this->checkBox_Cal_TorqAZMesg->Enabled = false;
  822. this->label_Cal_CalNum->Text = "Current Torque Ticks Offset:";
  823. this->numericUpDown_Cal_CalNumber->Value = 100;
  824. this->numericUpDown_Cal_CalNumber->Increment = System::Decimal(gcnew cli::array< System::Int32 >(4) {100, 0, 0, 0});
  825. this->numericUpDown_Cal_CalNumber->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {65535, 0, 0, 0});
  826. this->numericUpDown_Cal_CalNumber->Minimum = System::Decimal(gcnew cli::array< System::Int32 >(4) {0, 0, 0, 0});
  827. this->radioButton_Ppg_EventOnRotation->Enabled = true;
  828. this->numericUpDown_Ppg_BasicPowerInterlvTime->Enabled = false;
  829. this->numericUpDown_Ppg_SlopeConstant->Enabled = true;
  830. this->radioButton_Ppg_EventOnRotation->Checked = true;
  831. this->radioButton_Ppg_EventOnTime->Enabled = false;
  832. this->numericUpDown_Ppg_TimerEventFreq->Enabled = false;
  833. this->checkBox_Bat_Status->Enabled = false;
  834. this->checkBox_Bat_Status->Checked = false;
  835. // Validate calibration offset
  836. if(this->numericUpDown_Cal_CalNumber->Value < BikePower::MIN_OFFSET)
  837. this->numericUpDown_Cal_CalNumber->Value = BikePower::MIN_OFFSET;
  838. else if(this->numericUpDown_Cal_CalNumber-> Value > BikePower::MAX_OFFSET)
  839. this->numericUpDown_Cal_CalNumber->Value = BikePower::MIN_OFFSET;
  840. this->numericUpDown_Cal_CalNumber->Maximum = BikePower::MAX_OFFSET;
  841. this->numericUpDown_Cal_CalNumber->Minimum = BikePower::MIN_OFFSET;
  842. this->checkBox_Ppg_TxCadence->Enabled = false;
  843. this->checkBox_Ppg_TxPedalPwr->Enabled = false;
  844. this->numericUpDown_PedalPwr_CurrOutput->Enabled = false;
  845. this->checkBox_RightPedal->Enabled = false;
  846. this->label_Trn_PedalDisplay->Text = "---";
  847. this->label_Trn_PedalPwrDisplay->Text = "---";
  848. this->tabControl_TEPS->Enabled = false;
  849. this->checkBox_EnableTEPS->Checked = false;
  850. }
  851. }
  852. /**************************************************************************
  853. * BikePowerSensor::numericUpDown_Ppg_BasicPowerInterlvTime_ValueChanged
  854. *
  855. * Updates interleaving period for basic power page
  856. *
  857. * returns: N/A
  858. *
  859. **************************************************************************/
  860. System::Void BikePowerSensor::numericUpDown_Ppg_BasicPowerInterlvTime_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  861. {
  862. ucPowerInterleave = System::Convert::ToByte(this->numericUpDown_Ppg_BasicPowerInterlvTime->Value);
  863. }
  864. /**************************************************************************
  865. * BikePowerSensor::numericUpDown_Ppg_TimerEventFreq_ValueChanged
  866. *
  867. * Updates event frequency for time synchronous simulation
  868. *
  869. * returns: N/A
  870. *
  871. **************************************************************************/
  872. System::Void BikePowerSensor::numericUpDown_Ppg_TimerEventFreq_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  873. {
  874. ucEventFreq10 = System::Convert::ToByte(10 * this->numericUpDown_Ppg_TimerEventFreq->Value);
  875. }
  876. /**************************************************************************
  877. * BikePowerSensor::radioButton_Ppg_UpdateType_CheckedChanged
  878. *
  879. * Updates type of simulation (event/time synch)
  880. *
  881. * returns: N/A
  882. *
  883. **************************************************************************/
  884. System::Void BikePowerSensor::radioButton_Ppg_UpdateType_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  885. {
  886. if(this->radioButton_Ppg_EventOnRotation->Checked)
  887. eUpdateType = BikePower::UpdateType::EVENT_SYNCH;
  888. else
  889. eUpdateType = BikePower::UpdateType::TIME_SYNCH;
  890. }
  891. /**************************************************************************
  892. * BikePowerSensor::button_GlobalDataUpdate_Click
  893. *
  894. * Validates and updates product information, from user input (GUI)
  895. *
  896. * returns: N/A
  897. *
  898. **************************************************************************/
  899. System::Void BikePowerSensor::button_GlobalDataUpdate_Click(System::Object^ sender, System::EventArgs^ e)
  900. {
  901. this->label_Glb_GlobalDataError->Visible = false;
  902. this->label_Glb_GlobalDataError->Text = "Error: ";
  903. // Convert and catch failed conversions
  904. try{
  905. commonPages->usMfgID = System::Convert::ToUInt16(this->textBox_Glb_ManfIDChange->Text);
  906. }
  907. catch(...){
  908. this->label_Glb_GlobalDataError->Text = System::String::Concat(this->label_Glb_GlobalDataError->Text, " MFID");
  909. this->label_Glb_GlobalDataError->Visible = true;
  910. }
  911. try{
  912. commonPages->ulSerialNum = System::Convert::ToUInt32(this->textBox_Glb_SerialNumChange->Text);
  913. }
  914. catch(...){
  915. this->label_Glb_GlobalDataError->Text = System::String::Concat(this->label_Glb_GlobalDataError->Text, " Ser#");
  916. this->label_Glb_GlobalDataError->Visible = true;
  917. }
  918. try{
  919. commonPages->ucHwVersion = System::Convert::ToByte(this->textBox_Glb_HardwareVerChange->Text);
  920. }
  921. catch(...){
  922. this->label_Glb_GlobalDataError->Text = System::String::Concat(this->label_Glb_GlobalDataError->Text, " HWVr");
  923. this->label_Glb_GlobalDataError->Visible = true;
  924. }
  925. try{
  926. commonPages->ucSwVersion = System::Convert::ToByte(this->textBox_Glb_SoftwareVerChange->Text);
  927. }
  928. catch(...){
  929. this->label_Glb_GlobalDataError->Text = System::String::Concat(this->label_Glb_GlobalDataError->Text, " SWVr");
  930. this->label_Glb_GlobalDataError->Visible = true;
  931. }
  932. try{
  933. commonPages->usModelNum = System::Convert::ToUInt16(this->textBox_Glb_ModelNumChange->Text);
  934. }
  935. catch(...){
  936. this->label_Glb_GlobalDataError->Text = System::String::Concat(this->label_Glb_GlobalDataError->Text, " Mdl#");
  937. this->label_Glb_GlobalDataError->Visible = true;
  938. }
  939. }
  940. /**************************************************************************
  941. * BikePowerSensor::bcheckBox_Bat_Status_CheckedChanged
  942. *
  943. * Enables/disables transmission of battery page
  944. *
  945. * returns: N/A
  946. *
  947. **************************************************************************/
  948. System::Void BikePowerSensor::checkBox_Bat_Status_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  949. {
  950. bTxPage82 = this->checkBox_Bat_Status->Checked;
  951. }
  952. /**************************************************************************
  953. * BikePowerSensor::radioButton_Bat_ElpUnits_CheckedChanged
  954. *
  955. * Selects time resolution (two or sixteen seconds)
  956. *
  957. * returns: N/A
  958. *
  959. **************************************************************************/
  960. System::Void BikePowerSensor::radioButton_Bat_ElpUnits_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  961. {
  962. if(this->radioButton_Bat_Elp2Units->Checked && commonPages->eTimeResolution == CommonData::TimeResolution::SIXTEEN)
  963. {
  964. commonPages->eTimeResolution = CommonData::TimeResolution::TWO;
  965. commonPages->ulOpTime = commonPages->ulOpTime << 3; // OpTime*8: Convert from interval of 16 seconds to interval of 2 seconds
  966. }
  967. else if(this->radioButton_Bat_Elp16Units->Checked && commonPages->eTimeResolution == CommonData::TimeResolution::TWO)
  968. {
  969. commonPages->eTimeResolution = CommonData::TimeResolution::SIXTEEN;
  970. commonPages->ulOpTime = commonPages->ulOpTime >> 3; // OpTime/8: Convert from interval of 2 seconds to interval of 16 seconds
  971. }
  972. this->label_Bat_ElpTimeDisplay->Text = ((ULONG) (commonPages->ulOpTime & CommonData::OPERATING_TIME_MASK) * (UCHAR) commonPages->eTimeResolution).ToString();
  973. ulRunTime1000 = 0; // reset run time value so that next update happens in 2 or 16 seconds
  974. }
  975. /**************************************************************************
  976. * BikePowerSensor::button_ElpTimeUpdate_Click
  977. *
  978. * Updates cumulative operating time (in seconds)
  979. *
  980. * returns: N/A
  981. *
  982. **************************************************************************/
  983. System::Void BikePowerSensor::button_ElpTimeUpdate_Click(System::Object^ sender, System::EventArgs^ e)
  984. {
  985. this->button_Bat_ElpTimeUpdate->Text = "Update";
  986. try{
  987. ULONG ulTimeS = System::Convert::ToUInt32(this->textBox_Bat_ElpTimeChange->Text); // Get time in seconds
  988. if(commonPages->eTimeResolution == CommonData::TimeResolution::TWO) // Conver to two second resolution
  989. {
  990. if(ulTimeS > CommonData::MAX_2SEC)
  991. ulTimeS = CommonData::MAX_2SEC;
  992. commonPages->ulOpTime = ulTimeS >> 1; // Time/2
  993. }
  994. else
  995. { // Convert to sixteen second resolution
  996. if(ulTimeS > CommonData::MAX_16SEC)
  997. ulTimeS = CommonData::MAX_16SEC;
  998. commonPages->ulOpTime = ulTimeS >> 4; // Time/16
  999. }
  1000. this->label_Bat_ElpTimeDisplay->Text = ulTimeS.ToString();
  1001. }
  1002. catch(...){
  1003. this->button_Bat_ElpTimeUpdate->Text = "Retry"; // Invalid input, try again
  1004. }
  1005. }
  1006. /**************************************************************************
  1007. * BikePowerSensor::numericUpDown_Bat_VoltInt_ValueChanged
  1008. *
  1009. * Updates coarse (integer) battery voltage
  1010. *
  1011. * returns: N/A
  1012. *
  1013. **************************************************************************/
  1014. System::Void BikePowerSensor::numericUpDown_Bat_VoltInt_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1015. {
  1016. commonPages->usBatVoltage256 = ((USHORT) System::Convert::ToByte(this->numericUpDown_Bat_VoltInt->Value)) << 8 | (commonPages->usBatVoltage256 & 0xFF); // Integer portion in high byte
  1017. this->label_Voltage_Display->Text = ((double) commonPages->usBatVoltage256/256).ToString(); // Display in V
  1018. }
  1019. /**************************************************************************
  1020. * BikePowerSensor::numericUpDown_Bat_VoltInt_ValueChanged
  1021. *
  1022. * Updates fractional battery voltage
  1023. *
  1024. * returns: N/A
  1025. *
  1026. **************************************************************************/
  1027. System::Void BikePowerSensor::numericUpDown_Bat_VoltFrac_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1028. {
  1029. commonPages->usBatVoltage256 = System::Convert::ToByte(this->numericUpDown_Bat_VoltFrac->Value) | (commonPages->usBatVoltage256 & 0xFF00); // Fractional portion in low byte
  1030. this->label_Voltage_Display->Text = ((double) commonPages->usBatVoltage256/256).ToString(); // Display in V
  1031. }
  1032. /**************************************************************************
  1033. * BikePowerSensor::checkBox_Bat_Voltage_CheckedChanged
  1034. *
  1035. * Enables/disables coarse battery voltage
  1036. *
  1037. * returns: N/A
  1038. *
  1039. **************************************************************************/
  1040. System::Void BikePowerSensor::checkBox_Bat_Voltage_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1041. {
  1042. this->numericUpDown_Bat_VoltInt->Enabled = this->checkBox_Bat_Voltage->Checked;
  1043. this->numericUpDown_Bat_VoltFrac->Enabled = this->checkBox_Bat_Voltage->Checked;
  1044. this->checkBox_Bat_FracVolt->Enabled = this->checkBox_Bat_Voltage->Checked;
  1045. if(!this->checkBox_Bat_Voltage->Checked)
  1046. {
  1047. commonPages->usBatVoltage256 = (USHORT) CommonData::BATTERY_VOLTAGE_INVALID << 8 | (commonPages->usBatVoltage256 & 0xFF); // Integer portion in high byte
  1048. this->label_Voltage_Display->Text = "Off";
  1049. }
  1050. else
  1051. {
  1052. commonPages->usBatVoltage256 = ((USHORT) System::Convert::ToByte(this->numericUpDown_Bat_VoltInt->Value)) << 8 | (commonPages->usBatVoltage256 & 0xFF); // Integer portion in high byte
  1053. this->label_Voltage_Display->Text = ((double) commonPages->usBatVoltage256/256).ToString(); // Display in V
  1054. }
  1055. }
  1056. /**************************************************************************
  1057. * BikePowerSensor::checkBox_Bat_FracVolt_CheckedChanged
  1058. *
  1059. * Enables/disables fractional battery voltage
  1060. *
  1061. * returns: N/A
  1062. *
  1063. **************************************************************************/
  1064. System::Void BikePowerSensor::checkBox_Bat_FracVolt_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1065. {
  1066. this->numericUpDown_Bat_VoltFrac->Enabled = this->checkBox_Bat_FracVolt->Checked;
  1067. if(!this->checkBox_Bat_FracVolt->Checked)
  1068. commonPages->usBatVoltage256 &= 0xFF00; // Fractional portion in low byte, set to zero
  1069. else
  1070. commonPages->usBatVoltage256 = System::Convert::ToByte(this->numericUpDown_Bat_VoltFrac->Value) | (commonPages->usBatVoltage256 & 0xFF00); // Fractional portion in low byte, from GUI
  1071. this->label_Voltage_Display->Text = ((double) commonPages->usBatVoltage256/256).ToString(); // Display in V
  1072. }
  1073. /**************************************************************************
  1074. * BikePowerSensor::listBox_Bat_Status_SelectedIndexChanged
  1075. *
  1076. * Sets battery status
  1077. *
  1078. * returns: N/A
  1079. *
  1080. **************************************************************************/
  1081. System::Void BikePowerSensor::listBox_Bat_Status_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e)
  1082. {
  1083. if(this->listBox_Bat_Status->SelectedIndex == 5) // Set manually as indexes don't match enum (due to reserved bits)
  1084. commonPages->eBatStatus = CommonData::BatStatus::INVALID;
  1085. else
  1086. commonPages->eBatStatus = (CommonData::BatStatus) (this->listBox_Bat_Status->SelectedIndex + 1);
  1087. }
  1088. /**************************************************************************
  1089. * BikePowerSensor::numericUpDown_Ppg_SlopeConstant_ValueChanged
  1090. *
  1091. * Updates slope
  1092. *
  1093. * returns: N/A
  1094. *
  1095. **************************************************************************/
  1096. System::Void BikePowerSensor::numericUpDown_Ppg_SlopeConstant_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1097. {
  1098. bpPages->usSlope10 = System::Convert::ToUInt16(10 * this->numericUpDown_Ppg_SlopeConstant->Value);
  1099. }
  1100. /**************************************************************************
  1101. * BikePowerSensor::numericUpDown_Sim_WheelCircumference_ValueChanged
  1102. *
  1103. * Updates wheel circumference (cm)
  1104. *
  1105. * returns: N/A
  1106. *
  1107. **************************************************************************/
  1108. System::Void BikePowerSensor::numericUpDown_Sim_WheelCircumference_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1109. {
  1110. ucWheelCircumference100 = System::Convert::ToByte(this->numericUpDown_Sim_WheelCircumference->Value);
  1111. }
  1112. /**************************************************************************
  1113. * BikePowerSensor::checkBox_Sim_Coast_CheckedChanged
  1114. *
  1115. * Enables/disables coasting
  1116. *
  1117. * returns: N/A
  1118. *
  1119. **************************************************************************/
  1120. System::Void BikePowerSensor::checkBox_Sim_Coast_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1121. {
  1122. bCoast = this->checkBox_Sim_Coast->Checked;
  1123. this->checkBox_Sim_Stop->Enabled = !bCoast;
  1124. }
  1125. /**************************************************************************
  1126. * BikePowerSensor::checkBox_Sim_Stop_CheckedChanged
  1127. *
  1128. * Enables/disables stopping
  1129. *
  1130. * returns: N/A
  1131. *
  1132. **************************************************************************/
  1133. System::Void BikePowerSensor::checkBox_Sim_Stop_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1134. {
  1135. bStop = this->checkBox_Sim_Stop->Checked;
  1136. this->checkBox_Sim_Coast->Enabled = !bStop;
  1137. }
  1138. /**************************************************************************
  1139. * BikePowerSensor::checkBox_Sim_Sweeping_CheckedChanged
  1140. *
  1141. * Enables/disables sweeping
  1142. *
  1143. * returns: N/A
  1144. *
  1145. **************************************************************************/
  1146. System::Void BikePowerSensor::checkBox_Sim_Sweeping_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1147. {
  1148. this->numericUpDown_Sim_CurOutput->Enabled = !this->numericUpDown_Sim_CurOutput->Enabled;
  1149. this->numericUpDown_Sim_MinOutput->Enabled = !this->numericUpDown_Sim_MinOutput->Enabled;
  1150. this->numericUpDown_Sim_MaxOutput->Enabled = !this->numericUpDown_Sim_MaxOutput->Enabled;
  1151. if(this->checkBox_Sim_Sweeping->Checked)
  1152. {
  1153. ucSimDataType = SIM_SWEEP;
  1154. bSweepAscending = TRUE;
  1155. }
  1156. else
  1157. {
  1158. ucSimDataType = SIM_FIXED;
  1159. }
  1160. }
  1161. /**************************************************************************
  1162. * BikePowerSensor::numericUpDown_Sim_WheelTorque_ValueChanged
  1163. *
  1164. * Updates wheel and crank torque
  1165. *
  1166. * returns: N/A
  1167. *
  1168. **************************************************************************/
  1169. System::Void BikePowerSensor::numericUpDown_Sim_WheelTorque_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1170. {
  1171. usWheelTorque32 = System::Convert::ToUInt16(32 * this->numericUpDown_Sim_WheelTorque->Value); // Update wheel torque from UI
  1172. CalculateCrankTorque();
  1173. this->numericUpDown_Sim_WheelTorque->Value = (System::Decimal) usWheelTorque32/32; // Update values displayed
  1174. this->numericUpDown_Sim_CrankTorque->Value = (System::Decimal) usCrankTorque32/32;
  1175. }
  1176. /**************************************************************************
  1177. * BikePowerSensor::numericUpDown_Sim_CrankTorque_ValueChanged
  1178. *
  1179. * Updates wheel and crank torque
  1180. *
  1181. * returns: N/A
  1182. *
  1183. **************************************************************************/
  1184. System::Void BikePowerSensor::numericUpDown_Sim_CrankTorque_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1185. {
  1186. usCrankTorque32 = System::Convert::ToUInt16(32 * this->numericUpDown_Sim_CrankTorque->Value); // Update crank torque from UI
  1187. CalculateWheelTorque();
  1188. this->numericUpDown_Sim_CrankTorque->Value = (System::Decimal) usCrankTorque32/32; // Update values displayed
  1189. this->numericUpDown_Sim_WheelTorque->Value = (System::Decimal) usWheelTorque32/32;
  1190. }
  1191. /**************************************************************************
  1192. * BikePowerSensor::numericUpDown_Sim_CrankGearTeeth_ValueChanged
  1193. *
  1194. * Updates crank gear teeth, and wheel/crank torque
  1195. *
  1196. * returns: N/A
  1197. *
  1198. **************************************************************************/
  1199. System::Void BikePowerSensor::numericUpDown_Sim_CrankGearTeeth_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1200. {
  1201. ucNumCrankGearTeeth = System::Convert::ToByte(this->numericUpDown_Sim_CrankGearTeeth->Value); // Update from UI
  1202. CalculateWheelTorque();
  1203. this->numericUpDown_Sim_CrankTorque->Value = (System::Decimal) usCrankTorque32/32; // Update values displayed
  1204. this->numericUpDown_Sim_WheelTorque->Value = (System::Decimal) usWheelTorque32/32;
  1205. }
  1206. /**************************************************************************
  1207. * BikePowerSensor::numericUpDown_Sim_WheelGearTeeth_ValueChanged
  1208. *
  1209. * Updates wheel gear teeth, and wheel/crank torque
  1210. *
  1211. * returns: N/A
  1212. *
  1213. **************************************************************************/
  1214. System::Void BikePowerSensor::numericUpDown_Sim_WheelGearTeeth_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1215. {
  1216. ucNumWheelGearTeeth = System::Convert::ToByte(this->numericUpDown_Sim_WheelGearTeeth->Value); // Update from UI
  1217. CalculateCrankTorque();
  1218. this->numericUpDown_Sim_WheelTorque->Value = (System::Decimal) usWheelTorque32/32; // Update values displayed
  1219. this->numericUpDown_Sim_CrankTorque->Value = (System::Decimal) usCrankTorque32/32;
  1220. }
  1221. /**************************************************************************
  1222. * BikePowerSensor::numericUpDown_PedalPwr_CurOutput_ValueChanged
  1223. *
  1224. * Updates the current power pedal value, when it changes
  1225. *
  1226. * returns: N/A
  1227. *
  1228. **************************************************************************/
  1229. System::Void BikePowerSensor::numericUpDown_PedalPwr_CurrOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1230. {
  1231. ucCurPedalPwrValue = System::Convert::ToByte(this->numericUpDown_PedalPwr_CurrOutput->Value); //Update from UI
  1232. }
  1233. /**************************************************************************
  1234. * BikePowerSensor::numericUpDown_Sim_CurOutput_ValueChanged
  1235. *
  1236. * Updates and converts units of the current speed or cadence value, when it changes
  1237. *
  1238. * returns: N/A
  1239. *
  1240. **************************************************************************/
  1241. System::Void BikePowerSensor::numericUpDown_Sim_CurOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1242. {
  1243. // Ignore changes when sweeping
  1244. if(this->numericUpDown_Sim_CurOutput->Enabled)
  1245. {
  1246. ulCurValue1000 = System::Convert::ToUInt32(1000 * this->numericUpDown_Sim_CurOutput->Value); // Convert to 1/1000 resolution
  1247. ForceUpdate();
  1248. }
  1249. }
  1250. /**************************************************************************
  1251. * BikePowerSensor::numericUpDown_Sim_MinMaxOutput_ValueChanged
  1252. *
  1253. * If the user has changed the min or max speed, validate that
  1254. * minimum < current < maximum
  1255. *
  1256. * returns: N/A
  1257. *
  1258. **************************************************************************/
  1259. System::Void BikePowerSensor::numericUpDown_Sim_MinMaxOutput_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1260. {
  1261. ULONG ulPrevValue1000 = ulCurValue1000;
  1262. // Check only if user changes values (not sweeping)
  1263. if(this->numericUpDown_Sim_MinOutput->Enabled && this->numericUpDown_Sim_MaxOutput->Enabled)
  1264. {
  1265. // Check min<max, and force min<cur<max
  1266. if(this->numericUpDown_Sim_MinOutput->Value < this->numericUpDown_Sim_MaxOutput->Value)
  1267. {
  1268. ulMinValue1000 = System::Convert::ToUInt32(1000 * this->numericUpDown_Sim_MinOutput->Value);
  1269. ulMaxValue1000 = System::Convert::ToUInt32(1000 * this->numericUpDown_Sim_MaxOutput->Value);
  1270. if(ulCurValue1000 > ulMaxValue1000)
  1271. ulCurValue1000 = ulMaxValue1000;
  1272. else if(ulCurValue1000 < ulMinValue1000)
  1273. ulCurValue1000 = ulMinValue1000;
  1274. if(ulCurValue1000 != ulPrevValue1000)
  1275. {
  1276. this->numericUpDown_Sim_CurOutput->Value = System::Convert::ToDecimal((double)ulCurValue1000/1000);
  1277. ForceUpdate();
  1278. }
  1279. }
  1280. else
  1281. {
  1282. // If the values were invalid, set numeric values to last valid values
  1283. this->numericUpDown_Sim_MinOutput->Value = System::Convert::ToDecimal((double)ulMinValue1000/1000);
  1284. this->numericUpDown_Sim_MaxOutput->Value = System::Convert::ToDecimal((double)ulMaxValue1000/1000);
  1285. }
  1286. }
  1287. }
  1288. /**************************************************************************
  1289. * BikePowerSensor::radioButton_SimByChanged
  1290. *
  1291. * Selects simulation by cadence or speed, and converts last value to appropiate
  1292. * unit for consistency
  1293. *
  1294. * returns: N/A
  1295. *
  1296. **************************************************************************/
  1297. System::Void BikePowerSensor::radioButton_SimByChanged(System::Object^ sender, System::EventArgs^ e)
  1298. {
  1299. bByCadence = (BOOL) this->radioButton_Sim_SimByCadence->Checked;
  1300. // Disable boxes momentarily, to keep values from being checked and modified again as they change
  1301. this->numericUpDown_Sim_CurOutput->Enabled = FALSE;
  1302. this->numericUpDown_Sim_MaxOutput->Enabled = FALSE;
  1303. this->numericUpDown_Sim_MinOutput->Enabled = FALSE;
  1304. // Update input data
  1305. if(bByCadence)
  1306. {
  1307. // Selected cadence (switching from speed to cadence)
  1308. // Latest speed and cadence values are maintained, so the values that represented speed are converted to cadence
  1309. ulCurValue1000 = SpeedToCadence(ulCurValue1000);
  1310. ulMinValue1000 = SpeedToCadence(ulMinValue1000);
  1311. ulMaxValue1000 = SpeedToCadence(ulMaxValue1000);
  1312. }
  1313. else
  1314. {
  1315. // Selected speed (switching from cadence to speed)
  1316. // Latest speed and cadence value are maintained, so values representing cadence are converted to speed
  1317. ulCurValue1000 = CadenceToSpeed(ulCurValue1000);
  1318. ulMinValue1000 = CadenceToSpeed(ulMinValue1000);
  1319. ulMaxValue1000 = CadenceToSpeed(ulMaxValue1000);
  1320. }
  1321. // Validate values do not exceed max
  1322. if(ulCurValue1000 > 255000)
  1323. ulCurValue1000 = 255000;
  1324. if(ulMinValue1000 > 255000)
  1325. ulMinValue1000 = 255000;
  1326. if(ulMaxValue1000 > 255000)
  1327. ulMaxValue1000 = 255000;
  1328. // Update output
  1329. this->numericUpDown_Sim_CurOutput->Value = System::Convert::ToDecimal((double)ulCurValue1000/1000);
  1330. this->numericUpDown_Sim_MinOutput->Value = System::Convert::ToDecimal((double)ulMinValue1000/1000);
  1331. this->numericUpDown_Sim_MaxOutput->Value = System::Convert::ToDecimal((double)ulMaxValue1000/1000);
  1332. // Enable input boxes again so that they can be modified by user
  1333. if(ucSimDataType == SIM_SWEEP)
  1334. {
  1335. this->numericUpDown_Sim_MaxOutput->Enabled = TRUE;
  1336. this->numericUpDown_Sim_MinOutput->Enabled = TRUE;
  1337. }
  1338. else
  1339. {
  1340. this->numericUpDown_Sim_CurOutput->Enabled = TRUE;
  1341. }
  1342. }
  1343. /**************************************************************************
  1344. * BikePowerSensor::checkBox_Cal_TorqAZMesg_CheckedChanged
  1345. *
  1346. * Enables/disables transmission of auto zero support page
  1347. *
  1348. * returns: N/A
  1349. *
  1350. **************************************************************************/
  1351. System::Void BikePowerSensor::checkBox_Cal_TorqAZMesg_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1352. {
  1353. bTxAZ = (BOOL) this->checkBox_Cal_TorqAZMesg->Checked;
  1354. }
  1355. /**************************************************************************
  1356. * BikePowerSensor::listBox_Cal_AZStatus_SelectedIndexChanged
  1357. *
  1358. * Sets auto zero status
  1359. *
  1360. * returns: N/A
  1361. *
  1362. **************************************************************************/
  1363. System::Void BikePowerSensor::listBox_Cal_AZStatus_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e)
  1364. {
  1365. switch(this->listBox_Cal_AZStatus->SelectedIndex)
  1366. {
  1367. case 0:
  1368. bpPages->bAutoZeroEnable = TRUE;
  1369. bpPages->bAutoZeroOn = FALSE;
  1370. break;
  1371. case 1:
  1372. bpPages->bAutoZeroEnable = TRUE;
  1373. bpPages->bAutoZeroOn = TRUE;
  1374. break;
  1375. case 2:
  1376. bpPages->bAutoZeroEnable = FALSE;
  1377. bpPages->bAutoZeroOn = FALSE;
  1378. break;
  1379. default:
  1380. break;
  1381. }
  1382. }
  1383. /**************************************************************************
  1384. * BikePowerSensor::numericUpDown_Cal_RawTorque_ValueChanged
  1385. *
  1386. * Updates raw torque for auto zero support page
  1387. *
  1388. * returns: N/A
  1389. *
  1390. **************************************************************************/
  1391. System::Void BikePowerSensor::numericUpDown_Cal_RawTorque_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1392. {
  1393. bpPages->sRawTorque = System::Convert::ToInt16(this->numericUpDown_Cal_RawTorque->Value);
  1394. }
  1395. /**************************************************************************
  1396. * BikePowerSensor::numericUpDown_Cal_OffsetTorque_ValueChanged
  1397. *
  1398. * Updates offset torque for auto zero support page
  1399. *
  1400. * returns: N/A
  1401. *
  1402. **************************************************************************/
  1403. System::Void BikePowerSensor::numericUpDown_Cal_OffsetTorque_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1404. {
  1405. bpPages->sOffsetTorque = System::Convert::ToInt16(this->numericUpDown_Cal_OffsetTorque->Value);
  1406. }
  1407. /**************************************************************************
  1408. * BikePowerSensor::numericUpDown_Cal_CalNumber_ValueChanged
  1409. *
  1410. * Updates the calibration number to send, depending on the sensor type
  1411. * When dealing with CTF sensors, the input is converted to an unsigned short,
  1412. * and when dealing with other sensors, the input is converted to a signed
  1413. * short
  1414. *
  1415. * returns: N/A
  1416. *
  1417. **************************************************************************/
  1418. System::Void BikePowerSensor::numericUpDown_Cal_CalNumber_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1419. {
  1420. if(bpPages->eType == BikePower::SensorType::CRANK_TORQUE_FREQ)
  1421. usCalOffset = System::Convert::ToUInt16(this->numericUpDown_Cal_CalNumber->Value);
  1422. else
  1423. sCalData = System::Convert::ToInt16(this->numericUpDown_Cal_CalNumber->Value);
  1424. }
  1425. /**************************************************************************
  1426. * BikePowerSensor::radioButton_Cal_Success_CheckedChanged
  1427. *
  1428. * Sets next calibration response to report a success or failure
  1429. *
  1430. * returns: N/A
  1431. *
  1432. **************************************************************************/
  1433. System::Void BikePowerSensor::radioButton_Cal_Success_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1434. {
  1435. bCalSuccess = (BOOL) this->radioButton_Cal_Success->Checked;
  1436. }
  1437. /**************************************************************************
  1438. * BikePowerSensor::checkBox_Ppg_TxCadence_CheckedChanged
  1439. *
  1440. * Enables/disables transmission of cadence in power and torque data pages
  1441. *
  1442. * returns: N/A
  1443. *
  1444. **************************************************************************/
  1445. System::Void BikePowerSensor::checkBox_Ppg_TxCadence_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1446. {
  1447. bTxCadence = (BOOL) this->checkBox_Ppg_TxCadence->Checked;
  1448. }
  1449. /**************************************************************************
  1450. * BikePowerSensor::checkBox_Ppg_TxPedalPwr_CheckedChanged
  1451. *
  1452. * Enables/disables transmission of pedal power in power data page
  1453. *
  1454. * returns: N/A
  1455. *
  1456. **************************************************************************/
  1457. System::Void BikePowerSensor::checkBox_Ppg_TxPedalPwr_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1458. {
  1459. bTxPedalPower = (BOOL) this->checkBox_Ppg_TxPedalPwr->Checked;
  1460. if(bTxPedalPower)
  1461. {
  1462. this->numericUpDown_PedalPwr_CurrOutput->Enabled = true;
  1463. this->checkBox_RightPedal->Enabled = true;
  1464. }
  1465. else
  1466. {
  1467. this->numericUpDown_PedalPwr_CurrOutput->Enabled = false;
  1468. this->checkBox_RightPedal->Enabled = false;
  1469. }
  1470. }
  1471. /**************************************************************************
  1472. * BikePowerSensor::checkBox_RightPedal_CheckedChanged
  1473. *
  1474. * Enables/disables right pedal % power contribution
  1475. *
  1476. * returns: N/A
  1477. *
  1478. **************************************************************************/
  1479. System::Void BikePowerSensor::checkBox_RightPedal_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1480. {
  1481. bRightPedal = (BOOL) this->checkBox_RightPedal->Checked;
  1482. }
  1483. /**************************************************************************
  1484. * BikePowerSensor::CalculateWheelTorque
  1485. *
  1486. * Calculates wheel torque from crank torque, and updates the crank torque
  1487. * if the value is invalid
  1488. *
  1489. * returns: N/A
  1490. *
  1491. **************************************************************************/
  1492. void BikePowerSensor::CalculateWheelTorque()
  1493. {
  1494. usWheelTorque32 = (ucNumWheelGearTeeth * usCrankTorque32)/ucNumCrankGearTeeth; // Calculate wheel torque
  1495. if(usWheelTorque32 > 3196) // 99.9 * 32
  1496. {
  1497. usWheelTorque32 = 3196;
  1498. usCrankTorque32 = (ucNumCrankGearTeeth * usWheelTorque32)/ucNumWheelGearTeeth; // Calculate crank torque from max wheel torque
  1499. }
  1500. }
  1501. /**************************************************************************
  1502. * BikePowerSensor::CalculateCrankTorque
  1503. *
  1504. * Calculates crank torque from wheel torque, and updates the wheel torque
  1505. * if the value is invalid
  1506. *
  1507. * returns: N/A
  1508. *
  1509. **************************************************************************/
  1510. void BikePowerSensor::CalculateCrankTorque()
  1511. {
  1512. usCrankTorque32 = (ucNumCrankGearTeeth * usWheelTorque32)/ucNumWheelGearTeeth; // Calculate crank torque
  1513. if(usCrankTorque32 > 3196) // 99.9 * 32
  1514. {
  1515. usCrankTorque32 = 3196;
  1516. usWheelTorque32 = (ucNumWheelGearTeeth * usCrankTorque32)/ucNumCrankGearTeeth; // Calculate wheel torque from max crank torque
  1517. }
  1518. }
  1519. /**************************************************************************
  1520. * BikePowerSensor::SpeedToCadence
  1521. *
  1522. * Converts from speed (m/h) to cadence (1/1000 rpm)
  1523. *
  1524. * ulSpeed1000_ : Speed (m/h)
  1525. *
  1526. * returns: Cadence (1/1000 rpm)
  1527. *
  1528. **************************************************************************/
  1529. ULONG BikePowerSensor::SpeedToCadence(ULONG ulSpeed1000_)
  1530. {
  1531. ULONG ulCadence1000;
  1532. ulCadence1000 = 100 * ((ulSpeed1000_ * 1000 * ucNumWheelGearTeeth)/((ULONG) 60 * ucWheelCircumference100 * ucNumCrankGearTeeth)); // m/h to rpm, circumference is in cm
  1533. return ulCadence1000;
  1534. }
  1535. /**************************************************************************
  1536. * BikePowerSensor::CadenceToSpeed
  1537. *
  1538. * Converts from cadence (1/1000 rpm) to speed (m/h)
  1539. *
  1540. * ulCadence1000_ : Cadence (1/1000 rpm)
  1541. *
  1542. * returns: Speed (m/h)
  1543. *
  1544. **************************************************************************/
  1545. ULONG BikePowerSensor::CadenceToSpeed(ULONG ulCadence1000_)
  1546. {
  1547. ULONG ulSpeed1000;
  1548. ulSpeed1000 = (ulCadence1000_/100 * 60 * ucWheelCircumference100 * ucNumCrankGearTeeth)/(1000* ucNumWheelGearTeeth); // rpm to m/h, circumference is in cm
  1549. return ulSpeed1000;
  1550. }
  1551. /**************************************************************************
  1552. * BikePowerSensor::ForceUpdate
  1553. *
  1554. * Causes a timer event, to force the simulator to update all calculations
  1555. *
  1556. * returns: N/A
  1557. *
  1558. **************************************************************************/
  1559. void BikePowerSensor::ForceUpdate()
  1560. {
  1561. // Only performed in event synchronous simulations, to prevent simulator from
  1562. // getting stuck on low speed/cadence values
  1563. if(eUpdateType == BikePower::UpdateType::EVENT_SYNCH)
  1564. timerHandle->Interval = 250;
  1565. }
  1566. /**************************************************************************
  1567. * BikePowerSensor::checkBox_InvalidSerial_CheckedChanged
  1568. *
  1569. * Handles the CheckedChanged event
  1570. *
  1571. * returns: N/A
  1572. *
  1573. **************************************************************************/
  1574. void BikePowerSensor::checkBox_InvalidSerial_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
  1575. {
  1576. if(this->checkBox_InvalidSerial->Checked)
  1577. this->textBox_Glb_SerialNumChange->Enabled = false;
  1578. else
  1579. this->textBox_Glb_SerialNumChange->Enabled = true;
  1580. }
  1581. void BikePowerSensor::button_UpdateGetSet_Click(System::Object ^sender, System::EventArgs ^e)
  1582. {
  1583. bpPages->ucSubpageNumber = 0x01;
  1584. if(checkBox_InvalidCrankLength->Checked)
  1585. bpPages->ucCrankLength = BikePower::INVALID_CRANK_LENGTH;
  1586. else
  1587. bpPages->ucCrankLength = (UCHAR)(((float)numericUpDown_CrankLength->Value - (float)110.0) / (float)0.5);
  1588. //clear the sensor status;
  1589. bpPages->ucSensorStatus = 0;
  1590. if(radioButton_SensorUndefined->Checked)
  1591. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SensorStatus::UNDEFINED << 4);
  1592. else if(radioButton_SensorLeft->Checked)
  1593. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SensorStatus::LEFT_PRESENT << 4);
  1594. else if(radioButton_SensorRight->Checked)
  1595. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SensorStatus::RIGHT_PRESENT << 4);
  1596. else if(radioButton_SensorBoth->Checked)
  1597. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SensorStatus::LEFT_RIGHT_PRESENT << 4);
  1598. if(radioButton_MismatchUndefined->Checked)
  1599. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SWMistmatchStatus::UNDEFINED << 2);
  1600. else if(radioButton_MismatchRight->Checked)
  1601. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SWMistmatchStatus::RIGHT_SENSOR_OLDER << 2);
  1602. else if(radioButton_MismatchLeft->Checked)
  1603. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SWMistmatchStatus::LEFT_SENSOR_OLDER << 2);
  1604. else if(radioButton_MismatchNone->Checked)
  1605. bpPages->ucSensorStatus |= ((UCHAR)BikePower::SWMistmatchStatus::SW_SAME << 2);
  1606. if(radioButton_CrankInvalid->Checked)
  1607. bpPages->ucSensorStatus |= ((UCHAR)BikePower::CrankLengthStatus::LENGTH_INVALID);
  1608. else if(radioButton_CrankDefault->Checked)
  1609. bpPages->ucSensorStatus |= ((UCHAR)BikePower::CrankLengthStatus::DEFAULT_LENGTH_USED);
  1610. else if(radioButton_CrankManual->Checked)
  1611. bpPages->ucSensorStatus |= ((UCHAR)BikePower::CrankLengthStatus::LENGTH_MANUALLY_SET);
  1612. else if(radioButton_CrankAuto->Checked)
  1613. bpPages->ucSensorStatus |= ((UCHAR)BikePower::CrankLengthStatus::LENGTH_AUTOMATICALLY_SET);
  1614. //Clear auto crank bit
  1615. bpPages->ucSensorCapabilities &= 0xFE;
  1616. // Set auto crank bit
  1617. if(checkBox_AutoCrank->Checked)
  1618. bpPages->ucSensorCapabilities |= 0x01;
  1619. }
  1620. void BikePowerSensor::checkBox_InvalidCrankLength_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
  1621. {
  1622. if(checkBox_InvalidCrankLength->Checked)
  1623. numericUpDown_CrankLength->Enabled = false;
  1624. else
  1625. numericUpDown_CrankLength->Enabled = true;
  1626. }
  1627. System::Void BikePowerSensor::checkBox_LeftTorqueEffectivenessInvalid_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1628. {
  1629. numericUpDown_LeftTorqueEffectiveness->Enabled = !checkBox_LeftTorqueEffectivenessInvalid->Checked;
  1630. if(checkBox_LeftTorqueEffectivenessInvalid->Checked)
  1631. bpPages->ucLeftTorqueEffectiveness = bpPages->INVALID_TEPS;
  1632. else
  1633. bpPages->ucLeftTorqueEffectiveness = (UCHAR) (numericUpDown_LeftTorqueEffectiveness->Value * 2);
  1634. }
  1635. System::Void BikePowerSensor::checkBox_RightTorqueEffectivenessInvalid_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1636. {
  1637. numericUpDown_RightTorqueEffectiveness->Enabled = !checkBox_RightTorqueEffectivenessInvalid->Checked;
  1638. if(checkBox_RightTorqueEffectivenessInvalid->Checked)
  1639. bpPages->ucRightTorqueEffectiveness = bpPages->INVALID_TEPS;
  1640. else
  1641. bpPages->ucRightTorqueEffectiveness = (UCHAR) (numericUpDown_RightTorqueEffectiveness->Value *2);
  1642. }
  1643. System::Void BikePowerSensor::checkBox_LeftPedalSmoothnessInvalid_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1644. {
  1645. numericUpDown_LeftPedalSmoothness->Enabled = !checkBox_LeftPedalSmoothnessInvalid->Checked;
  1646. if(checkBox_LeftPedalSmoothnessInvalid->Checked)
  1647. bpPages->ucLeftPedalSmoothness = bpPages->INVALID_TEPS;
  1648. else
  1649. bpPages->ucLeftPedalSmoothness = (UCHAR) (numericUpDown_LeftPedalSmoothness->Value * 2);
  1650. }
  1651. System::Void BikePowerSensor::checkBox_RightPedalSmoothnessInvalid_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1652. {
  1653. numericUpDown_RightPedalSmoothness->Enabled = !checkBox_RightPedalSmoothnessInvalid->Checked;
  1654. if(checkBox_RightPedalSmoothnessInvalid->Checked)
  1655. bpPages->ucRightPedalSmoothness = bpPages->INVALID_TEPS;
  1656. else
  1657. bpPages->ucRightPedalSmoothness = (UCHAR) (numericUpDown_RightPedalSmoothness->Value * 2);
  1658. }
  1659. System::Void BikePowerSensor::checkBox_Combined_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1660. {
  1661. // If this is a combined system, torque effectiveness doesn't apply
  1662. checkBox_LeftTorqueEffectivenessInvalid->Checked = checkBox_Combined->Checked;
  1663. checkBox_RightTorqueEffectivenessInvalid->Checked = checkBox_Combined->Checked;
  1664. // Pedal Smoothness is a little trickier...
  1665. numericUpDown_RightPedalSmoothness->Enabled = !checkBox_Combined->Checked;
  1666. checkBox_RightPedalSmoothnessInvalid->Enabled = !checkBox_Combined->Checked;
  1667. if(checkBox_Combined->Checked)
  1668. bpPages->ucRightPedalSmoothness = bpPages->COMBINED_PEDAL_SMOOTHNESS;
  1669. else
  1670. checkBox_RightPedalSmoothnessInvalid_CheckedChanged(this, nullptr); // trigger an update to check for invalid values and read numeric box
  1671. }
  1672. System::Void BikePowerSensor::checkBox_EnableTEPS_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
  1673. {
  1674. bTxPage19 = checkBox_EnableTEPS->Checked;
  1675. }
  1676. System::Void BikePowerSensor::numericUpDown_LeftTorqueEffectiveness_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1677. {
  1678. if(!checkBox_LeftTorqueEffectivenessInvalid->Checked)
  1679. bpPages->ucLeftTorqueEffectiveness = (UCHAR) (numericUpDown_LeftTorqueEffectiveness->Value * 2);
  1680. }
  1681. System::Void BikePowerSensor::numericUpDown_RightTorqueEffectiveness_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1682. {
  1683. if(!checkBox_RightTorqueEffectivenessInvalid->Checked)
  1684. bpPages->ucRightTorqueEffectiveness = (UCHAR) (numericUpDown_RightTorqueEffectiveness->Value * 2);
  1685. }
  1686. System::Void BikePowerSensor::numericUpDown_LeftPedalSmoothness_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1687. {
  1688. if(!checkBox_LeftPedalSmoothnessInvalid->Checked)
  1689. bpPages->ucLeftPedalSmoothness = (UCHAR) (numericUpDown_LeftPedalSmoothness->Value *2);
  1690. }
  1691. System::Void BikePowerSensor::numericUpDown_RightPedalSmoothness_ValueChanged(System::Object^ sender, System::EventArgs^ e)
  1692. {
  1693. if(!checkBox_RightPedalSmoothnessInvalid->Checked)
  1694. bpPages->ucRightPedalSmoothness = (UCHAR) (numericUpDown_RightPedalSmoothness->Value * 2);
  1695. }