internal void updateStats(DataSources.DataSourcePacket data) { Dispatcher.Invoke(new Action(() => { if (data.speed_ms < ushort.MaxValue) { if (AntPlusRacerConfig.getInstance().displayMph) { Label_Speed.Content = String.Format("{0:0.0}mph", data.speed_ms * 2.237); } else //else use real measurement units { Label_Speed.Content = String.Format("{0:0.0}kph", data.speed_ms * 3.6); } } if (data.power != ushort.MaxValue) { Label_Power.Content = String.Format("{0:0}W", data.power); } if (data.cadence != -1) { updateCadence(data.cadence); } })); }
public RaceFactoryPanel(Action <RaceDetails> raceOutputRcvr) { InitializeComponent(); raceRcvr = raceOutputRcvr; if (AntPlusRacerConfig.getInstance().autoLoadAvailableRaceSourcesForRace) { AntPlusDevMgr antMgr = AntConfigPanel.accessInstance().antMgr; for (int i = 0; i < antMgr.deviceList.Count; ++i) { AntPlusDevMgr.AntPlus_Connection dev = antMgr.deviceList[i]; //Skip devices in use if (dev.dataSource.isInUse || dev.getConnStatus() != AntPlusDevMgr.AntPlus_Connection.ConnState.Connected || isDataSourceReserved(dev.dataSource)) { continue; } else { configureRacer(0xFF, dev.dataSource, AntPlusRacerConfig.getInstance().getDefaultRaceTrack(dev.dataSource.getSportType()).distance); } } if (configuredRacers.Count == 0) { DisplayRacerList(); } } else { DisplayRacerList(); } ComboBox_RaceLength.SizeChanged += new SizeChangedEventHandler((sender, args) => comboBoxAutoLblFontSize(sender as ComboBox)); }
public void showRaceFactory() { prepareForPanelChange(true); raceConfig = null; RaceFactoryPanel toAdd; if (ss_isActive && ss_savedPanel != null) { toAdd = ss_savedPanel; ss_isActive = false; } else { toAdd = new RaceFactoryPanel(factoryComplete); } Grid_Content.Children.Add(toAdd); PanelState = panelState.RaceFactory; ss_lastActivity = DateTime.Now; if (AntPlusRacerConfig.getInstance().RecordScreenSaverTimeout_negativeIsOff > 0) { ss_ScreenSaverTimer.Start(); } }
void recordDisplayScreenSaver_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (DateTime.Now.Subtract(ss_lastActivity).TotalSeconds > AntPlusRacerConfig.getInstance().RecordScreenSaverTimeout_negativeIsOff) { lock (ss_ScreenSaverTimer) { if (!ss_isActive) { ss_lastActivity = DateTime.Now; ss_ignoreFirstMove = true; ss_isActive = true; Dispatcher.Invoke((Action)showRecords); PanelState = panelState.ScreenSaverRecordDisplay; } } } }
private void populateDistanceBox(racerSportType sport) { ComboBox_RaceLength.Items.Clear(); RacerDetails selectedRacer = null; if (racerIndexUnderConfig >= 0) { selectedRacer = configuredRacers[racerIndexUnderConfig]; ComboBox_RaceLength.Items.Add(new Label() { Content = selectedRacer.targetValue.ToString() + "m track" }); } //Add all available values foreach (AntPlusRacerConfig.RaceTrack i in AntPlusRacerConfig.getInstance().enabledRaceTracks) { if (i.sportType == sport) { //Skip the current value because we already added it if (selectedRacer != null && selectedRacer.targetValue == i.distance) { continue; } ComboBox_RaceLength.Items.Add(new Label() { Content = i.distance.ToString() + "m track" }); } } if (ComboBox_RaceLength.Items.Count == 0) { ComboBox_RaceLength.Items.Add(new Label() { Content = "499m track" }); } ComboBox_RaceLength.SelectedIndex = 0; comboBoxAutoLblFontSize(ComboBox_RaceLength); }
private AntConfigPanel() { InitializeComponent(); antMgr = new AntPlusDevMgr(); ListBox_statusPanelHolder.Items.Clear(); Binding widthBind = new Binding("ActualWidth"); widthBind.Source = ListBox_statusPanelHolder; foreach (AntPlusDevMgr.AntPlus_Connection i in antMgr.deviceList) { Fit_ConfigPanelDevice pnl = new Fit_ConfigPanelDevice(i); pnl.SetBinding(Fit_ConfigPanelDevice.WidthProperty, widthBind); ListBox_statusPanelHolder.Items.Add(pnl); } if (AntPlusRacerConfig.getInstance().remoteControlDevNum_negativeIsOff > 0) { Grid.SetRow(RacerRemoteControl.getRemoteStatus(), 1); Grid_Main.Children.Add(RacerRemoteControl.getRemoteStatus()); } }
private void finishRaceAsync() { isRaceFinished = true; raceTock.Stop(); if (target_type == targetType.Meters) { raceTimer.Stop(); } if (!AntPlusRacerConfig.getInstance().keepRecords) { sleepCheckStop(6000); //wait longer without records because they won't see the scores again } else { //Allow time to view the result before we switch screens if (AntPlusRacerConfig.getInstance().fastRecords_noNames) { sleepCheckStop(1000); } else { sleepCheckStop(3000); } //Sort racers by finish result so that the saved indexes from the post racepanel are consistent racerDetails.Sort((x, y) => Comparer <Double> .Default.Compare(x.finishResult, y.finishResult)); //Save the results of any human racers List <KeyValuePair <TrackRecords.TrackRecordList, int> > savedRecords = new List <KeyValuePair <TrackRecords.TrackRecordList, int> >(); System.Threading.AutoResetEvent recordSaveDone = new System.Threading.AutoResetEvent(false); foreach (RacerDetails i in racerDetails) { if (i.dataSource.isHuman) { if (AntPlusRacerConfig.getInstance().fastRecords_noNames) { i.racerRecordInfo = new TrackRecords.RecordData() { FirstName = i.dataSource.getSourceName() }; } if (i.racerRecordInfo != null) //If we have preset data, save the record automatically { i.racerRecordInfo.DataSourceName = i.dataSource.getSourceName(); i.racerRecordInfo.recordValue = i.finishResult; TrackRecords.TrackRecordList list = TrackRecords.RecordDatabase.getInstance().getTrackRecordList(i.dataSource.getSportType(), i.targetValue); int pos = TrackRecords.PostRacePanel.saveRacerRecord(list, i.racerRecordInfo); savedRecords.Add(new KeyValuePair <TrackRecords.TrackRecordList, int>(list, pos)); } else { OwningDisplayPanel.Dispatcher.Invoke((Action <RacerDetails, Action <TrackRecords.TrackRecordList, int> >)OwningDisplayPanel.showPostRacePanel, i, new Action <TrackRecords.TrackRecordList, int>( (list, pos) => { savedRecords.Add(new KeyValuePair <TrackRecords.TrackRecordList, int>(list, pos)); recordSaveDone.Set(); })); //Sleep until post race panel is done System.Threading.WaitHandle.WaitAny(new System.Threading.WaitHandle[] { cancelAsyncToken.Token.WaitHandle, recordSaveDone }); } cancelAsyncToken.Token.ThrowIfCancellationRequested(); } } //Yes, there are simpler ways to correlate the lists. But why not try and learn how to use new things? Lookup <TrackRecords.TrackRecordList, int> recordLists = (Lookup <TrackRecords.TrackRecordList, int>)savedRecords.ToLookup(k => k.Key, e => e.Value); foreach (IGrouping <TrackRecords.TrackRecordList, int> trackList in recordLists) { OwningDisplayPanel.Dispatcher.Invoke((Action <TrackRecords.TrackRecordList, List <int> >)OwningDisplayPanel.showResult, trackList.Key, trackList.ToList()); //Wait to view this list for a moment if (AntPlusRacerConfig.getInstance().fastRecords_noNames) { sleepCheckStop(1000); } else { sleepCheckStop(5000); } } } OwningDisplayPanel.Dispatcher.Invoke((Action)OwningDisplayPanel.showRaceFactory); //Now, back to start a new race }
private void startRaceAsync() { notFinishedHumanRacers = 0; foreach (RacerDetails i in racerDetails) { i.dataSource.reset(); OwningDisplayPanel.Dispatcher.Invoke((Action)i.racePanel.resetDisplay, System.Windows.Threading.DispatcherPriority.Loaded); if (i.dataSource.isHuman) { ++notFinishedHumanRacers; } } if (!AntPlusRacerConfig.getInstance().quickStart_noCountdown) { //Display names for (int i = 0; i < racerDetails.Count; ++i) { racerDetails[i].racePanel.makeAnnouncement(racerDetails[i].racer_displayname); sleepCheckStop(1000); } sleepCheckStop(1000); //Display target values for (int i = 0; i < racerDetails.Count; ++i) { racerDetails[i].racePanel.makeAnnouncement(" "); racerDetails[i].racePanel.makeAnnouncement(racerDetails[i].targetValue.ToString() + " " + target_type); } sleepCheckStop(2000); //Set Displays to Blank for (int i = 0; i < racerDetails.Count; ++i) { racerDetails[i].racePanel.makeAnnouncement(" "); } //Countdown (only on top screen) racerDetails[0].racePanel.makeAnnouncement("Ready?"); sleepCheckStop(2000); racerDetails[0].racePanel.makeAnnouncement("3"); sleepCheckStop(1000); racerDetails[0].racePanel.makeAnnouncement("2"); sleepCheckStop(1000); racerDetails[0].racePanel.makeAnnouncement("1"); sleepCheckStop(1000); } //TODO: qc could check speed of fit equip to make sure no one takes a running start racerDetails[0].racePanel.makeAnnouncement("GO!"); for (int i = 0; i < racerDetails.Count; ++i) { int a = i; racerDetails[i].dataSource.start((Action <DataSourcePacket>)((x) => dataSourceUpdating(a, x))); } //Start the timer(s) raceTock.Start(); if (target_type == targetType.Meters) { raceTimer.Start(); } //Clear the countdown display sleepCheckStop(1000); //Clear Displays for (int i = 0; i < racerDetails.Count; ++i) { racerDetails[i].racePanel.makeAnnouncement(""); } }
private void decodeRaceControlCmd(RacePanel selectedPanel, byte[] lastMsgBytes) { switch (lastMsgBytes[3]) { case 0: //start { if (selectedPanel.PanelState != RacePanel.panelState.RaceFactory) { sendResponse(RemoteControlReturnCodes.Error_PanelInWrongState, lastMsgBytes); return; } RaceFactoryPanel factoryPanel = selectedPanel.Grid_Content.Children[0] as RaceFactoryPanel; if (!factoryPanel.startRace()) { sendResponse(RemoteControlReturnCodes.Error_RacersNotConfigured, lastMsgBytes); return; } sendResponse(RemoteControlReturnCodes.Success, lastMsgBytes); return; } case 1: //restart { if (selectedPanel.PanelState != RacePanel.panelState.Racing) { sendResponse(RemoteControlReturnCodes.Error_PanelInWrongState, lastMsgBytes); return; } selectedPanel.raceConfig.disposeRace(); selectedPanel.raceConfig = new RaceDetails(selectedPanel.raceConfig.racerDetails, selectedPanel.raceConfig.target_type); selectedPanel.raceConfig.startRace(selectedPanel); sendResponse(RemoteControlReturnCodes.Success, lastMsgBytes); return; } case 2: //cancel race { if (selectedPanel.PanelState != RacePanel.panelState.RaceFactory && selectedPanel.PanelState != RacePanel.panelState.Racing && selectedPanel.PanelState != RacePanel.panelState.PostRaceDisplay && selectedPanel.PanelState != RacePanel.panelState.PostRaceResults) { sendResponse(RemoteControlReturnCodes.Error_PanelInWrongState, lastMsgBytes); return; } selectedPanel.showRaceFactory(); sendResponse(RemoteControlReturnCodes.Success, lastMsgBytes); return; } case 3: //get current racer list { if (selectedPanel.PanelState != RacePanel.panelState.RaceFactory && selectedPanel.PanelState != RacePanel.panelState.Racing && selectedPanel.PanelState != RacePanel.panelState.PostRaceDisplay && selectedPanel.PanelState != RacePanel.panelState.PostRaceResults) { sendResponse(RemoteControlReturnCodes.Error_PanelInWrongState, lastMsgBytes); return; } List <RacerDetails> racerList; if (selectedPanel.PanelState == RacePanel.panelState.RaceFactory) { racerList = ((RaceFactoryPanel)selectedPanel.Grid_Content.Children[0]).configuredRacers; } else { racerList = selectedPanel.raceConfig.racerDetails; } List <byte> retMsg = new List <byte> { (byte)racerList.Count }; for (byte i = 0; i < racerList.Count; ++i) { RacerDetails racer = racerList[i]; retMsg.Add(i); retMsg.Add(racer.dataSource.uid); retMsg.Add((byte)((ushort)racer.targetValue & 0xFF)); retMsg.Add((byte)(((ushort)racer.targetValue & 0xFF00) >> 8)); ushort curDistance = (ushort)racer.dataSource.getCurrentDistance(); retMsg.Add((byte)((ushort)curDistance & 0xFF)); retMsg.Add((byte)(((ushort)curDistance & 0xFF00) >> 8)); if (racer.racerRecordInfo != null) { if (!String.IsNullOrWhiteSpace(racer.racerRecordInfo.FirstName)) { retMsg.Add(1); retMsg.Add((byte)racer.racerRecordInfo.FirstName.Length); retMsg.AddRange(UTF8Encoding.ASCII.GetBytes(racer.racerRecordInfo.FirstName)); } if (!String.IsNullOrWhiteSpace(racer.racerRecordInfo.LastName)) { retMsg.Add(2); retMsg.Add((byte)racer.racerRecordInfo.LastName.Length); retMsg.AddRange(UTF8Encoding.ASCII.GetBytes(racer.racerRecordInfo.LastName)); } if (!String.IsNullOrWhiteSpace(racer.racerRecordInfo.PhoneNumber)) { retMsg.Add(3); retMsg.Add((byte)racer.racerRecordInfo.PhoneNumber.Length); retMsg.AddRange(UTF8Encoding.ASCII.GetBytes(racer.racerRecordInfo.PhoneNumber)); } if (!String.IsNullOrWhiteSpace(racer.racerRecordInfo.Email)) { retMsg.Add(4); retMsg.Add((byte)racer.racerRecordInfo.Email.Length); retMsg.AddRange(UTF8Encoding.ASCII.GetBytes(racer.racerRecordInfo.Email)); } } retMsg.Add(0); //Null term options list } sendResponse(RemoteControlReturnCodes.Success, lastMsgBytes, retMsg); return; } case 4: //Config race { if (selectedPanel.PanelState != RacePanel.panelState.RaceFactory) { if (selectedPanel.PanelState == RacePanel.panelState.ScreenSaverRecordDisplay) { selectedPanel.Dispatcher.Invoke((Action)selectedPanel.showRaceFactory); } else { sendResponse(RemoteControlReturnCodes.Error_PanelInWrongState, lastMsgBytes); return; } } selectedPanel.ss_lastActivity = DateTime.Now.Add(new TimeSpan(0, 0, 5)); //Give ourselves 5 seconds of extra time before screensaver to process ant messages RaceFactoryPanel factoryPanel = selectedPanel.Grid_Content.Children[0] as RaceFactoryPanel; if (lastMsgBytes[5] == 0xFF) { if (factoryPanel.removeRacer(lastMsgBytes[4])) { sendResponse(RemoteControlReturnCodes.Success, lastMsgBytes); return; } else { sendResponse(RemoteControlReturnCodes.Error_RacerDoesntExist, lastMsgBytes); return; } } byte sourceID = lastMsgBytes[5]; DataSources.DataSourceBase dataSrc = null; foreach (AntPlusDevMgr.AntPlus_Connection i in AntConfigPanel.accessInstance().antMgr.deviceList) { if (i.dataSource.uid == sourceID) { dataSrc = i.dataSource; if (i.getConnStatus() != AntPlusDevMgr.AntPlus_Connection.ConnState.Connected) { sendResponse(RemoteControlReturnCodes.Error_DataSourceNotConnected, lastMsgBytes); return; } break; } } if (dataSrc == null) { sendResponse(RemoteControlReturnCodes.Error_DataSourceDoesntExist, lastMsgBytes); return; } double trackDist = 0; //Get the default (first) track for the given sport type foreach (AntPlusRacerConfig.RaceTrack i in AntPlusRacerConfig.getInstance().enabledRaceTracks) { if (i.sportType == dataSrc.getSportType()) { trackDist = i.distance; break; } } //decode options string firstName = null; string lastName = null; string phoneNum = null; string emailAdr = null; int curPos = 6; while (curPos < lastMsgBytes.Length && lastMsgBytes[curPos] != 0) //0 is the end of list marker { int option = lastMsgBytes[curPos]; switch (option) { case 1: case 2: case 3: case 4: int strLength = lastMsgBytes[curPos + 1]; string str = UTF8Encoding.ASCII.GetString(lastMsgBytes.Skip(curPos + 2).Take(strLength).ToArray()); switch (option) { case 1: firstName = str; break; case 2: lastName = str; break; case 3: phoneNum = str; break; case 4: emailAdr = str; break; } curPos += 2 + strLength; break; default: sendResponse(RemoteControlReturnCodes.Error_CmdFormatWrong, lastMsgBytes); return; } } if (curPos >= lastMsgBytes.Length) //If we ended without hitting the end of the list { sendResponse(RemoteControlReturnCodes.Error_CmdFormatWrong, lastMsgBytes); return; } //Finally create/change the racer int ret = factoryPanel.configureRacer(lastMsgBytes[4], dataSrc, trackDist, firstName, lastName, phoneNum, emailAdr); if (ret == 0) { sendResponse(RemoteControlReturnCodes.Success, lastMsgBytes); } else if (ret == -1) { sendResponse(RemoteControlReturnCodes.Error_DataSourceInUse, lastMsgBytes); } else if (ret == -2) { sendResponse(RemoteControlReturnCodes.Error_RacerDoesntExist, lastMsgBytes); } return; } default: sendResponse(RemoteControlReturnCodes.Error_CmdFormatWrong, lastMsgBytes); return; } }
public AntPlusDevMgr() { if (antStick == null) { ANT_Common.enableDebugLogs(); findUsableAntDevice(); } if (AntPlusRacerConfig.getInstance().remoteControlDevNum_negativeIsOff > 0) { numChannelsForDevices = antStick.getNumChannels() - 1; RacerRemoteControl.startRemoteControl(antStick.getChannel(numChannelsForDevices)); } else { numChannelsForDevices = antStick.getNumChannels(); } //Add all devices from config foreach (AntPlusRacerConfig.RacerInput i in AntPlusRacerConfig.getInstance().enabledRacerInputs) { switch (i.type) { case AntPlusRacerConfig.RacerInputType.ant_BikeCad_UsingSpd: ds_AntPlus_BikeSpd spdOnly = new ds_AntPlus_BikeSpd(); deviceList.Add(new AntPlus_Connection(spdOnly)); deviceList.Add(new AntPlus_Connection(new ds_AntPlus_BikeCad_UsingSpd(spdOnly))); break; case AntPlusRacerConfig.RacerInputType.ant_BikeCadAndSpd: deviceList.Add(new AntPlus_Connection(new ds_AntPlus_BikeSpdCad())); break; case AntPlusRacerConfig.RacerInputType.ant_BikeSpd: deviceList.Add(new AntPlus_Connection(new ds_AntPlus_BikeSpd())); break; case AntPlusRacerConfig.RacerInputType.ant_FitEqpmt: deviceList.Add(new AntPlus_Connection(new ds_AntPlus_Fit())); break; case AntPlusRacerConfig.RacerInputType.ant_StrideSDM: deviceList.Add(new AntPlus_Connection(new ds_AntPlus_StrideSDM())); break; default: //Not one of the ant types, ignore break; } if (i.defaultDeviceId != 0) { deviceList.Last().dataSource.searchProfile.deviceNumber = i.defaultDeviceId; } if (!String.IsNullOrWhiteSpace(i.displayName)) { deviceList.Last().dataSource.customSourceName = i.displayName; } } startNextSearch(); }