public void Broadcast(ADMMessage message) { if (message == null) { return; } MessageTags.Release(message.Tag); message.Target = null; //clear the target as it may have been used internally but now this is a broadcast so it's not intended for any specific target if (_listener != null && message.CanBroadcast) { switch (message.Type) { case Chetch.Messaging.MessageType.ERROR: _listener(message, this); break; default: if (State == ADMState.DEVICE_READY || State == ADMState.DEVICE_CONNECTED) { _listener(message, this); } break; } } }
virtual protected void OnADMDevicesConnected(ArduinoDeviceManager adm, ADMMessage message) { _devicesConnected[adm.PortAndNodeID] = true; bool startSampler = false; if (String.IsNullOrEmpty(RequiredBoards)) { startSampler = true; } else { String[] ar = RequiredBoards.Split(','); startSampler = true; for (int i = 0; i < ar.Length; i++) { ArduinoDeviceManager amg = GetADM(ar[i]); if (amg == null || amg.State != ADMState.DEVICE_CONNECTED) { startSampler = false; break; } } } if (startSampler) { Sampler.Start(); Tracing?.TraceEvent(TraceEventType.Information, 0, "Started sampler with {0} subjects and tick time of {1}", Sampler.SubjectCount, Sampler.TimerInterval); } String msg = String.Format("All {0} added devices connected for {1} ", adm.DeviceCount, adm.BoardID); Broadcast(ADMEvent.DEVICES_CONNECTED, msg); }
public byte Ping() { var message = new ADMMessage(MessageTags.CreateTag()); message.Type = Messaging.MessageType.PING; message.TargetID = 0; SendMessage(message); return(message.Tag); }
public byte RequestStatus(byte boardID = 0) { var message = new ADMMessage(MessageTags.CreateTag()); message.Type = Messaging.MessageType.STATUS_REQUEST; message.TargetID = boardID; SendMessage(message); return(message.Tag); }
public byte Initialise() { ADMMessage message = new ADMMessage(MessageTags.CreateTag()); message.TargetID = 0; message.Type = Messaging.MessageType.INITIALISE; SendMessage(message); return(message.Tag); }
private void TryHandleADMMessage(ADMMessage message, ArduinoDeviceManager adm) { try { HandleADMMessage(message, adm); } catch (Exception e) { Tracing?.TraceEvent(TraceEventType.Error, 100, "HandleADMMessage Error handling {0}: {1}", message.Type, e.Message); } }
virtual public void HandleMessage(ADMMessage message) { switch (message.Type) { case Messaging.MessageType.CONFIGURE_RESPONSE: IsConnected = true; OnConnect(message); break; default: break; } }
public void PrepareForBroadcast(ArduinoDeviceManager adm) { ADMMessage message = (ADMMessage)Message; message.AddValue("BoardID", adm.BoardID); ArduinoDevice dev = null; if (message.TargetID > 0) { dev = adm.GetDeviceByBoardID(message.TargetID); } else if (message.Sender != null && message.Sender != String.Empty) { dev = adm.GetDevice(message.Sender); } message.AddValue(DEVICE_ID, dev != null ? dev.ID : ""); message.AddValue(DEVICE_NAME, dev != null ? dev.Name : ""); }
public void Configure() { if (_devices.Count == 0) { State = ADMState.DEVICE_CONNECTED; } else { //send configuration/setup data to board foreach (ArduinoDevice device in _devices.Values) { var message = new ADMMessage(); message.LittleEndian = LittleEndian; message.Type = Messaging.MessageType.CONFIGURE; device.AddConfig(message); SendMessage(message); } } }
virtual public void AddConfig(ADMMessage message) { //add board ID, device category and device name message.TargetID = BoardID; message.AddArgument((byte)Category); message.AddArgument(Name); #if DEBUG System.Diagnostics.Debug.Print(String.Format("Adding config for device {0} ... ", ID)); #endif if (Mgr.Sampler != null && SampleInterval > 0 && SampleSize > 0) { Mgr.Sampler.Add(this, SampleInterval, SampleSize, SamplingOptions, SampleIntervalDeviation); #if DEBUG System.Diagnostics.Debug.Print(String.Format("Adding to sampler with interval {0} and sample size {1}", SampleInterval, SampleSize)); #endif } }
public byte SendCommand(byte targetID, ArduinoCommand command, List <Object> extraArgs = null, byte tag = 0) { var message = new ADMMessage(); message.LittleEndian = LittleEndian; message.Type = Messaging.MessageType.COMMAND; message.TargetID = targetID; message.Tag = tag == 0 ? MessageTags.CreateTag() : tag; message.CommandID = command.ID; List <Object> allArgs = command.Arguments; if (extraArgs != null && extraArgs.Count > 0) { allArgs.AddRange(extraArgs); } foreach (Object arg in allArgs) { byte[] b; if (arg is String) { b = Chetch.Utilities.Convert.ToBytes((String)arg); } else if (arg.GetType().IsValueType) { b = Chetch.Utilities.Convert.ToBytes((ValueType)arg, LittleEndian); } else { throw new Exception("Unable to process type " + arg.GetType()); } message.AddArgument(b); } return(SendMessage(message)); }
public byte SendMessage(ADMMessage message) { if (message == null) { return(0); } if (Monitor.TryEnter(SendMessageLock, SEND_MESSAGE_LOCK_TIMEOUT)) { try { bool ready2send; long msSinceLastSent = -1; //loop waiting for a message response do { msSinceLastSent = (DateTime.Now.Ticks - LastMessageSentOn.Ticks) / TimeSpan.TicksPerMillisecond; if (LastMessageSent == null || MessageReceivedSuccess) { ready2send = true; } else { ready2send = msSinceLastSent > MESSAGE_RECEIVED_TIMEOUT; if (!ready2send) { _sleep(10); //crappy idea to reduce load on cpu } else { //so here we have waited long enough for the previous sent message which has failed to arrive //so we proceed with sending anyway Tracing?.TraceEvent(TraceEventType.Warning, 0, "SendMessage {0}: Sending {1} timed out waiting to receive message {2} tag {3}", PortAndNodeID, message.Type, LastMessageSent.Type, LastMessageSent.Tag); } } } while (!ready2send); //store old values before sending (rollback if exception thrown) //This unusual approach is because it appeared like messages were being received before the SendString could exit ADMMessage lastMessageSent = LastMessageSent; DateTime lastMessageSentOn = LastMessageSentOn; try { lock (MessageStatsLock) { MessagesSent++; LastMessageSent = message; LastMessageSentOn = DateTime.Now; MessageReceivedSuccess = false; } if (message.Tag == 0) { message.Tag = MessageTags.CreateTag(); } message.SenderID = BoardID; //Console.WriteLine("-------------> {0}: Sending message {1} tag {2} target {3}." , PortAndNodeID, message.Type, message.Tag, message.TargetID); SendString(message.Serialize()); } catch (Exception e) { lock (MessageStatsLock) //rollback { MessagesSent--; LastMessageSent = lastMessageSent; LastMessageSentOn = lastMessageSentOn; } String errMsg = String.Format("{0} SendMessage: sending {1} (Tag={2}) produced exception {3} {4}", PortAndNodeID, message.Type, message.Tag, e.GetType(), e.Message); Tracing?.TraceEvent(TraceEventType.Error, 0, errMsg); throw e; } } finally { Monitor.Exit(SendMessageLock); } } //end attempt to try get lock else { //we waited too long to get the lock... throw new SendFailedException("ArduinoDeviceManager::SendMessage ... waited to long to obtain lock"); } return(message.Tag); }
abstract protected void AddADMDevices(ArduinoDeviceManager adm, ADMMessage message);
private void HandleReceivedADMMessage(ADMMessage message) { try { //do some general checking //TODO: check BoardID matches to SenderID lock (MessageStatsLock) { LastMessageReceived = message; LastMessageReceivedOn = DateTime.Now; MessageReceivedSuccess = message.Tag == LastMessageSent.Tag; MessagesReceived++; } //Console.WriteLine("<--------- {0}: Received message {1} tag {2} target {3} from sender {4}", PortAndNodeID, message.Type, message.Tag, message.TargetID, message.SenderID); switch (message.Type) { case Messaging.MessageType.INITIALISE_RESPONSE: message.AddValue("LittleEndian", message.ArgumentAsBool(0)); LittleEndian = message.GetBool("LittleEndian"); message.AddValue("FreeMemory", message.ArgumentAsInt(1)); BoardID = message.SenderID; message.AddValue("MaxDevices", message.ArgumentAsInt(2)); MaxDevices = message.GetInt("MaxDevices"); message.AddValue("LEDBI", message.ArgumentAsInt(3)); LEDBIPin = message.GetInt("LEDBI"); break; case Messaging.MessageType.STATUS_RESPONSE: try { if (message.TargetID == 0) { message.AddValue("FreeMemory", message.ArgumentAsInt(0)); message.AddValue("BoardType", message.ArgumentAsString(1)); message.AddValue("Initialised", message.ArgumentAsBool(2)); message.AddValue("DeviceCount", message.ArgumentAsInt(3)); } if (State == ADMState.CONNECTED) { State = ADMState.DEVICE_READY; } } catch (Exception e) { Tracing?.TraceEvent(TraceEventType.Error, 4000, "STATUS_RESPONSE error: {0}, {1}", e.GetType(), e.Message); throw new ArduinoException(PortAndNodeID, e.Message, e); } //record this LastStatusResponseMessage = message; LastStatusResponseOn = DateTime.Now; break; case Messaging.MessageType.PING_RESPONSE: //record this LastPingResponseMessage = message; LastPingResponseOn = DateTime.Now; break; case Messaging.MessageType.CONFIGURE_RESPONSE: break; case Messaging.MessageType.ERROR: //record last error message if (message.Arguments.Count > 0) { message.AddValue("ErrorCode", (ErrorCode)message.ArgumentAsByte(0)); } else { message.AddValue("ErrorCode", ErrorCode.ERROR_HOST_GENERATED); } LastErrorMessage = message; LastErrorOn = DateTime.Now; break; } if (State == ADMState.DEVICE_READY || State == ADMState.DEVICE_CONNECTED) { //direct messages to devices var dev = GetTargetedDevice(message); if (dev != null) { #if DEBUG Debug.Print(String.Format("Handling message {0} for device {1} ... connected: {2}, memory: {3}", message.Type, dev.ID, dev.IsConnected, message.HasValue("FM") ? message.GetValue("FM") : "N/A")); #endif try { dev.HandleMessage(message); } catch (Exception e) { Tracing?.TraceEvent(TraceEventType.Error, 4000, "Handling message for device {0} produced exception {1}: {2}", dev.ID, e.GetType(), e.Message); throw new ArduinoException(dev.ID, e.Message, e); } } //we do this test after handling message because the message maybe a CONFIGURE_RESPONSE message which will then set the 'connected' status of the device if (message.Type == Messaging.MessageType.CONFIGURE_RESPONSE && DevicesConnected) { State = ADMState.DEVICE_CONNECTED; } } } catch (Exception e) { byte tag = message != null ? message.Tag : (byte)0; message = new ADMMessage(); message.Type = Messaging.MessageType.ERROR; message.Value = e.Message; message.AddValue("ErrorCode", ErrorCode.ERROR_HOST_GENERATED); if (e is ArduinoException) { ArduinoException ae = (ArduinoException)e; message.AddValue("ErrorSource", ae.Source); } message.Tag = tag; } Broadcast(message); }
/// <summary> /// Handle messages that harve arrived from the board and successfully processed by Firmata /// </summary> /// <param name="sender"></param> /// <param name="eventArgs"></param> private void HandleFirmataMessageReceived(Object sender, FirmataMessageEventArgs eventArgs) { var fmessage = eventArgs.Value; ADMMessage message = null; try { switch (fmessage.Type) { case Solid.Arduino.Firmata.MessageType.FirmwareResponse: break; case Solid.Arduino.Firmata.MessageType.StringData: StringData sd = (StringData)fmessage.Value; try { String serialized = sd.Text; message = ADMMessage.Deserialize <ADMMessage>(serialized, MessageEncoding.BYTES_ARRAY); } catch (Exception e) { String sbytes = BitConverter.ToString(Chetch.Utilities.Convert.ToBytes(sd.Text)); Tracing?.TraceEvent(TraceEventType.Error, 4000, "Deserializing {0} produced exception {1}: {2}", sbytes, e.GetType(), e.Message); throw e; } break; case Solid.Arduino.Firmata.MessageType.PinStateResponse: break; case Solid.Arduino.Firmata.MessageType.DigitalPortState: DigitalPortState portState = (DigitalPortState)fmessage.Value; String s = BitConverter.ToString(BitConverter.GetBytes(portState.Pins)); int pinsChanged; if (_portStates.ContainsKey(portState.Port)) { pinsChanged = portState.Pins ^ _portStates[portState.Port].Pins; } else { pinsChanged = 255; } _portStates[portState.Port] = portState; for (int i = 0; i < 8; i++) { int bit2check = (int)System.Math.Pow(2, i); if ((bit2check & pinsChanged) == 0) { continue; } bool state = portState.IsSet(i); int pinNumber = GetPinForPort(portState.Port, i); //TODO: this might need to be board dependent var devs = GetDevicesByPin(pinNumber); if (devs != null) { foreach (var dev in devs) { dev.HandleDigitalPinStateChange(pinNumber, state); } } } //String s1 = System.Convert.ToString(portState.Pins, 2); //String s2 = System.Convert.ToString(pinsChanged, 2); //Debug.Print("Pins/2change: " + s1 + "/" + s2); break; case Solid.Arduino.Firmata.MessageType.CapabilityResponse: break; default: break; } } catch (Exception e) { byte tag = message != null ? message.Tag : (byte)0; message = new ADMMessage(); message.Type = Messaging.MessageType.ERROR; message.Value = e.Message; message.Tag = tag; } if (message != null) { Task.Run(() => { HandleReceivedADMMessage(message); }); } }
public ArduinoDevice GetTargetedDevice(ADMMessage message) { var boardID = message.TargetID; return(GetDeviceByBoardID(boardID)); }
public byte AssignID(byte idx) { ID = ADMMessage.CreateCommandID((byte)Type, idx); return(ID); }
virtual protected void HandleADMMessage(ADMMessage message, ArduinoDeviceManager adm) { switch (message.Type) { case MessageType.ERROR: ErrorCode errCode = message.HasValue("ErrorCode") ? message.GetEnum <ErrorCode>("ErrorCode") : ErrorCode.ERROR_UNKNOWN; Tracing?.TraceEvent(TraceEventType.Error, 100, "ADM {0} produced error: {1}", adm.BoardID, errCode); switch (errCode) { case ErrorCode.ERROR_ADM_NOT_INITIALISED: ReconnectADM(adm); break; default: //currently do nothing break; } break; case MessageType.WARNING: Tracing?.TraceEvent(TraceEventType.Warning, 100, "ADM {0} produced warning: {1}", adm.BoardID, message.Value); break; case MessageType.STATUS_RESPONSE: if (!PortSharing && !IsRequiredBoard(adm.BoardID)) { Tracing?.TraceEvent(TraceEventType.Warning, 100, "ADM {0} is not one of the required boards ({1}). Disconnecting from port {2}...", adm.BoardID, RequiredBoards, adm.Port); DisconnectADM(adm.Port); break; } if (adm.State == ADMState.DEVICE_READY) { Tracing?.TraceEvent(TraceEventType.Verbose, 100, "ADM: Ready to add devices to {0} on port {1} ...", adm.BoardID, adm.PortAndNodeID); AddADMDevices(adm, message); Tracing?.TraceEvent(TraceEventType.Verbose, 100, "ADM: {0} devices added to {1} on port {2}. Now configure board", adm.DeviceCount, adm.BoardID, adm.PortAndNodeID); adm.Configure(); } else if (adm.State == ADMState.DEVICE_CONNECTED) { if (message.HasValue("Initialised") && !message.GetBool("Initialised")) { //Console.WriteLine("Whoa ... {0} has reset without us knowing", adm.PortAndNodeID); } } break; case MessageType.CONFIGURE_RESPONSE: String key = adm.PortAndNodeID; if (adm.State == ADMState.DEVICE_CONNECTED && !_devicesConnected[key]) { Tracing?.TraceEvent(TraceEventType.Verbose, 100, "ADM: All {0} devices now configured and connected to board {1} on port {2}", adm.DeviceCount, adm.BoardID, adm.PortAndNodeID); OnADMDevicesConnected(adm, message); } break; case MessageType.PING_RESPONSE: break; } if (message.Tag > 0) { ADMRequest req = GetADMRequest(adm, message.Tag); if (req != null) { if (req.HasExpired()) { Tracing?.TraceEvent(TraceEventType.Warning, 0, "ADM request for tag {0} and target {1} has expired so not returning message of type {2}", message.Tag, req.Target, message.Type); return; } else { message.Target = req.Target; } } } var schema = new ADMService.MessageSchema(message); schema.PrepareForBroadcast(adm); //notify other clients listening to this client Broadcast(ADMEvent.MESSAGE, message); }
//called after the device has been configured on the board virtual protected void OnConnect(ADMMessage message) { //hook }
virtual protected void Broadcast(ADMMessage message) { message.Sender = ID; Mgr.Broadcast(message); }