/// <summary> /// Execute this request and wait for a valid response. /// </summary> /// <param name="lb">The locobuffer to execute on</param> /// <param name="validateResponse">Predicate used to filter our the valid response</param> /// <param name="timeout">Timeout in milliseconds to wait for a valid response</param> public T ExecuteAndWaitForResponse <T>(LocoBuffer lb, Predicate <T> validateResponse, int timeout) where T : Message { object waitLock = new object(); T result = null; using (var handler = lb.AddHandler((raw, msg) => { var response = msg as T; if ((response != null) && (validateResponse(response))) { // We've got the response we we're waiting for lock (waitLock) { result = response; Monitor.PulseAll(waitLock); } return(true); } return(false); })) { // Execute the request now Execute(lb); // Wait for a result lock (waitLock) { if (result == null) { Monitor.Wait(waitLock, timeout); } } } return(result); }
/// <summary> /// Default ctor /// </summary> public LocoNet(LocoBuffer lb, LocoNetConfiguration configuration) { this.lb = lb; this.configuration = configuration; state = new LocoNetState(lb); unknownLocoIoDetector = new UnknownLocoIODetector(this); }
/// <summary> /// Default ctor /// </summary> internal AsyncLocoBuffer(Control ui, LocoBuffer lb) { this.ui = ui; this.lb = lb; var thread = new Thread(Run); thread.Start(); }
/// <summary> /// Read the given set of SV values into configs. /// </summary> public void Read(LocoBuffer lb, IEnumerable<SVConfig> configs) { var list = configs.ToList(); list.Sort(); foreach (var iterator in configs) { var config = iterator; byte value; config.Valid = TryReadSV(lb, config.Index, out value); config.Value = value; } }
/// <summary> /// Default ctor /// </summary> public LocoBufferCommandStationState(ILocoBufferCommandStation entity, RailwayState railwayState, string[] addressSpaces) : base(entity, railwayState, addressSpaces) { var splb = new SerialPortLocoBuffer(); splb.PortName = entity.ComPortName; lb = splb; lb.PreviewMessage += MessageProcessor; client = new Client(lb, railwayState, this, railwayState.Dispatcher, Log); client.Idle += (s, x) => { networkIdle = true; RefreshIdle(); }; }
/// <summary> /// Write a single SV variable at the given index with the given value. /// </summary> internal bool ChangeAddress(LocoBuffer lb, int address, int subAddress) { var cmd = new PeerXferRequest1 { Command = PeerXferRequest.Commands.Write, SvAddress = 1, DestinationLow =this.address.Address, SubAddress = this.address.SubAddress, Data1 = (byte)address, }; var result = cmd.ExecuteAndWaitForResponse<PeerXferResponse>( lb, x => ((x.SvAddress == 1) && (x.OriginalCommand == PeerXferRequest.Commands.Write)), timeout); if (result == null) throw new TimeoutException("Program index 1 failed"); cmd = new PeerXferRequest1 { Command = PeerXferRequest.Commands.Write, SvAddress = 2, DestinationLow = this.address.Address, SubAddress = this.address.SubAddress, Data1 = (byte)subAddress, }; result = cmd.ExecuteAndWaitForResponse<PeerXferResponse>( lb, x => ((x.SvAddress == 2) && (x.OriginalCommand == PeerXferRequest.Commands.Write)), timeout); if (result == null) throw new TimeoutException("Program index 2 failed"); return true; }
/// <summary> /// Set the speed of a switch. /// </summary> /// <param name="value">Between 1 and 4</param> internal void SetSpeed(LocoBuffer lb, int value) { if ((value < 1) || (value > 4)) { throw new ArgumentException("Value must be between 1 and 4"); } EnterProgrammingMode(lb); SendNibble(lb, 0x05); // Command SendNibble(lb, SpeedMasks[value - 1] & 0x07); // LSB SendNibble(lb, (SpeedMasks[value - 1] >> 3) & 0x07); // MSB }
/// <summary> /// Create and start a new processor /// </summary> public ReceiveProcessor(LocoBuffer lb) { this.lb = lb; this.thread = new Thread(OnRun); this.thread.Start(); }
/// <summary> /// Change the type of locobuffer. /// </summary> private void OnChangeLocoBufferType(object sender, EventArgs e) { if (rbSerialPort.Checked) { if (!(LocoBuffer is SerialPortLocoBuffer)) LocoBuffer = new SerialPortLocoBuffer(); } else if (rbTcp.Checked) { if (!(LocoBuffer is TcpLocoBuffer)) LocoBuffer = new TcpLocoBuffer(); } else if (rbUdp.Checked) { if (!(LocoBuffer is UdpLocoBuffer)) LocoBuffer = new UdpLocoBuffer(); } }
/// <summary> /// Execute the message on the given buffer /// </summary> public abstract void Execute(LocoBuffer lb);
/// <summary> /// Set all bits to 0. /// </summary> internal void BitsToZero(LocoBuffer lb) { if (programmingMode) { throw new InvalidOperationException("Only valid in normal mode"); } SetB4(lb, false); SetB3(lb, false); SetB2(lb, false); SetB1(lb, false); }
/// <summary> /// Send a 3-bits nibble. /// </summary> private void SendNibble(LocoBuffer lb, int value) { // Lower b4 first SetB4(lb, false); // Set b1 SetB1(lb, (value & 0x01) != 0); // Set b2 SetB2(lb, (value & 0x02) != 0); // Set b3 SetB3(lb, (value & 0x04) != 0); // Raise B4 to transmit SetB4(lb, true); // Wait a while Thread.Sleep(20); // Lower B4 to avoid duplication SetB4(lb, false); // Wait a while Thread.Sleep(5); }
/// <summary> /// Execute the message on the given buffer /// </summary> public override void Execute(LocoBuffer lb) { lb.Send(this, CreateMessage()); }
/// <summary> /// Write a single SV variable at the given index with the given value. /// </summary> internal bool WriteSV(LocoBuffer lb, int index, byte value) { var cmd = new PeerXferRequest1 { Command = PeerXferRequest.Commands.Write, SvAddress = index, DestinationLow = address.Address, SubAddress = address.SubAddress, Data1 = value, }; var result = cmd.ExecuteAndWaitForResponse<PeerXferResponse>( lb, x => (address.Equals(x.Source) && (x.SvAddress == index) && (x.OriginalCommand == PeerXferRequest.Commands.Write)), timeout); return (result != null) && (result.Data1 == value); }
/// <summary> /// Write the given set of SV values /// </summary> internal void Write(LocoBuffer lb, IEnumerable<SVConfig> configs) { var list = configs.ToList(); list.Sort(); foreach (var config in configs) { var ok = false; for (int attempt = 0; !ok && (attempt < ATTEMPTS); attempt++) { // Write ok = WriteSV(lb, config.Index, config.Value); // Wait a while if (!ok) { Thread.Sleep(100); } } if (!ok) { throw new ProgramException(string.Format("Failed to write SV {0}", config.Index)); } } }
/// <summary> /// Read a single SV variable at the given index. /// </summary> internal bool TryReadSV(LocoBuffer lb, int index, out byte value) { var cmd = new PeerXferRequest1 { Command = PeerXferRequest.Commands.Read, SvAddress = index, DestinationLow = address.Address, SubAddress = address.SubAddress, }; var result = cmd.ExecuteAndWaitForResponse<PeerXferResponse>( lb, x => (address.Equals(x.Source) && (x.SvAddress == index) && (x.OriginalCommand == PeerXferRequest.Commands.Read)), timeout); if (result != null) { value = result.Data1; return true; } value = 0; return false; }
/// <summary> /// Set the target turnout /// </summary> internal void SetTarget(LocoBuffer lb) { EnterProgrammingMode(lb); SendNibble(lb, 0x01); // Command SendNibble(lb, Turnout - 1); // Turnout encoded as 0-3 }
/// <summary> /// Execute the given request. /// </summary> private static void Execute(LocoBuffer lb, Request request) { request.Execute(lb); }
/// <summary> /// Default ctor /// </summary> internal HandlerRegistration(LocoBuffer lb, MessageHandler handler) { this.lb = lb; this.handler = handler; }
private void SetB4(LocoBuffer lb, bool on) { Execute(lb, new SwitchRequest { Address = Address4, Direction = on, Output = true }); }
/// <summary> /// Default ctor /// </summary> /// <param name="lb"></param> internal LocoNetState(LocoBuffer lb) { this.lb = lb; lb.PreviewMessage += ProcessMessage; StartIdleDetection(); }
/// <summary> /// Execute this request. /// </summary> internal void Execute(Control ui, LocoBuffer lb) { try { request(lb); OnCompleted(ui, null); } catch (Exception ex) { OnCompleted(ui, ex); } }
/// <summary> /// Go into programming mode. /// </summary> internal void EnterProgrammingMode(LocoBuffer lb) { if (!programmingMode) { // Turn all bits off SetB4(lb, false); SetB3(lb, false); SetB2(lb, false); SetB1(lb, false); Thread.Sleep(1000); // Turn bit 1 on SetB1(lb, true); Thread.Sleep(6); // Turn bit 2 on SetB2(lb, true); Thread.Sleep(6); // Turn bit 3 on SetB3(lb, true); Thread.Sleep(6); // Turn bit 4 on SetB4(lb, true); Thread.Sleep(6); // Turn bit 1 off SetB1(lb, false); Thread.Sleep(6); // Turn bit 2 off SetB2(lb, false); Thread.Sleep(6); // Turn bit 3 off SetB3(lb, false); Thread.Sleep(6); // Turn bit 4 off SetB4(lb, false); Thread.Sleep(6); programmingMode = true; } }
/// <summary> /// Default ctor /// </summary> internal HandlerRegistration(LocoBuffer lb, MessageHandler handler) { this.lb = lb; this.handler = handler; }
/// <summary> /// Pass the given locobuffer on to all components. /// </summary> internal void Setup(LocoBuffer lb, LocoNetConfiguration configuration) { // Allow for null arguments lb = lb ?? ConfiguredLocoBuffer; configuration = configuration ?? Configuration; if ((ConfiguredLocoBuffer != lb) || (Configuration != configuration)) { CloseLocoBuffer(); locoNet = new LocoNet(lb, configuration); asyncLb = new AsyncLocoBuffer(ui, lb); lb.SendMessage += LbForwardSendMessage; lb.PreviewMessage += LbForwardPreviewMessage; var lnState = locoNet.State; lnState.StateChanged += LnStateStateChanged; lnState.LocoIOQuery += LnStateLocoIoQuery; lnState.LocoIOFound += LnStateLocoIoFound; lnState.Idle += LnStateIdle; LocoNetChanged.Fire(this); } }
/// <summary> /// Set the duration from left to right /// </summary> internal void ExitProgrammingMode(LocoBuffer lb) { if (programmingMode) { SendNibble(lb, 0x07); // Command programmingMode = false; // Reset all 4 bits SetB4(lb, false); SetB3(lb, false); SetB2(lb, false); SetB1(lb, false); } }
public override void Execute(LocoBuffer lb) { lb.Send(this, 0x82, 0); }
/// <summary> /// Create and start a new processor /// </summary> public ReceiveProcessor(LocoBuffer lb) { this.lb = lb; this.thread = new Thread(OnRun); this.thread.Start(); }
/// <summary> /// Set the direction of the relays. /// </summary> /// <param name="leftLsb">If true, left is the LSB and right is MSB, otherwise left is MSB and right is LSB</param> internal void SetRelaisPosition(LocoBuffer lb, bool leftLsb) { EnterProgrammingMode(lb); SendNibble(lb, 0x04); // Command SendNibble(lb, leftLsb ? 0 : 1); }
/// <summary> /// Read all settings /// </summary> internal void ReadAll(LocoBuffer lb, LocoNetAddress address) { // Create a set of all SV's that are relevant /*var configs = LocoIOConfig.GetAllSVs(); // Create the programmer var programmer = new Programmer(lb, address); // Read all SV's programmer.Read(configs); // Get all properly read configs var validConfigs = configs.Where(x => x.Valid).ToArray(); */ }
/// <summary> /// Set the right edge position in degrees /// </summary> /// <param name="value">Maximum right position (in time units) from 1 - 100</param> internal void SetRightDegrees(LocoBuffer lb, int value) { EnterProgrammingMode(lb); SendNibble(lb, 0x03); // Command SendNibble(lb, (value >> 1) & 0x07); // value bit 4,3,2 SendNibble(lb, (value >> 4) & 0x07); // value bit 7,6,5 }