public void showPostRacePanel(RacerDetails racer, Action <TrackRecords.TrackRecordList, int> postRaceDoneHandler) { prepareForPanelChange(false); Grid_Content.Children.Add(new TrackRecords.PostRacePanel(postRaceDoneHandler, racer)); PanelState = panelState.PostRaceDisplay; }
void dataSourceUpdating(int racerIndex, DataSourcePacket data) { RacerDetails racer = racerDetails[racerIndex]; //Handle targets if this is a distance race if (target_type == targetType.Meters) { if (data.distance >= racer.targetValue) { double finishTime = raceTimer.Elapsed.TotalMilliseconds / 1000; //Since the finish distance is usually a little past the target when we get it, we need to interpolate to get an accurate value for the actual finish //TODO qc Another issue with accuracy is that depending on the timing of the first update packets between racers, one racer can have up to one packet period advantage. racer.finish(++finishOrder, targetType.Seconds, finishTime - ((data.distance - racer.targetValue) / data.speed_ms)); //If everyone is done, stop the timer, don't wait for simulator results if (racer.dataSource.isHuman) { if (--notFinishedHumanRacers == 0) { //Make sure all non-humans are closed too foreach (RacerDetails i in racerDetails) { i.dataSource.stop(); i.dataSource.isInUse = false; } startAsync(finishRaceAsync); } } } else { if (data.speed_ms != 0) { racer.racePanel.updateProgressDisplay(data.distance, (int)(1000 * (racer.targetValue - data.distance) / data.speed_ms)); } else { racer.racePanel.updateProgressDisplay(data.distance, 0); } } } racer.racePanel.updateStats(data); }
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 void updateRaceAnimations() { RacerDetails leadingRacer = racerDetails[0]; double leadingRaceProgress = leadingRacer.dataSource.getCurrentDistance() / leadingRacer.targetValue; List <RacerDetails> trailingRacers = new List <RacerDetails>(); List <double> trailerRaceProgress = new List <double>(); for (int i = 1; i < racerDetails.Count; ++i) { double currentRacePosition = racerDetails[i].dataSource.getCurrentDistance() / racerDetails[i].targetValue; if (currentRacePosition > leadingRaceProgress) { //Push the old highest into the trailing list trailingRacers.Add(leadingRacer); trailerRaceProgress.Add(leadingRaceProgress); //Save the new highest leadingRacer = racerDetails[i]; leadingRaceProgress = currentRacePosition; } else { trailingRacers.Add(racerDetails[i]); trailerRaceProgress.Add(currentRacePosition); } } if (leadingRaceProgress == 0) //Updating when the leading racer is 0 causes divide by 0 errors { return; } //Take care of leader's positioning first double leadingDisplayPosition; if (leadingRacer.dataSource.isRunning()) { if (leadingRaceProgress < 0.2) { leadingDisplayPosition = leadingRaceProgress * 2; // ~ pos/0.2 * 0.4 } else if (leadingRaceProgress < 0.8) { leadingDisplayPosition = (((leadingRaceProgress - 0.2) / 0.6) * 0.4) + 0.4; } else { leadingDisplayPosition = leadingRaceProgress; } //System.Console.Write("f-{0}, {1:0.00}, ", leadingRacer.dataSource.getSourceName(), leadingRaceProgress); leadingRacer.racePanel.moveDistance(leadingDisplayPosition, 1); } else { leadingRaceProgress = 1; leadingDisplayPosition = 1; //System.Console.WriteLine("f-{0}, {1:0.00}, Finished.", leadingRacer.dataSource.getSourceName(), leadingRaceProgress); } //Now take care of trailers for (int i = 0; i < trailingRacers.Count; ++i) { if (trailingRacers[i].dataSource.isRunning()) { double fractionOfLead = trailerRaceProgress[i] / leadingRaceProgress; double displayPosition = 0; double trailingScale = 1; if (fractionOfLead > 0.5) { displayPosition = (fractionOfLead - 0.5) * 2; } // if (fractionOfLead > 0.7) // displayPosition = fractionOfLead / 0.6; // ~ 1 - ((x / 0.3) * 0.5) // else if (fractionOfLead > 0.5) // displayPosition = (fractionOfLead - 0.3) / 0.4; // ~((x - 0.3) / 0.2) * 0.5 else if (raceTimer.Elapsed.TotalSeconds > 1) //Don't start scaling at very start of race or it swings back and forth a bunch { trailingScale = Math.Max(fractionOfLead / 0.5, 0.2); //Max at 20%, we don't want racer to get too small to see } //System.Console.Write("t-{0}, {1:0.00}, ", trailingRacers[i].dataSource.getSourceName(), trailerRaceProgress[i]); trailingRacers[i].racePanel.moveDistance(displayPosition * leadingDisplayPosition, trailingScale); } } }
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; } }