/// <summary> /// Process HBus ack messages /// </summary> /// <param name="sender"></param> /// <param name="ack"></param> /// <param name="port"></param> /// <returns></returns> private bool OnAckReceived(object sender, Message ack, int port) { try { Event evt = null; //if (Status.NodeStatus != NodeStatusValues.Active) return false; if (ack.MessageType == MessageTypes.NackResponse) { var err = ack.Data.Length > 1 ? ack.Data[0] << 1 | ack.Data[1] : 0; Log.Debug(string.Format("HBus: nack from {0}:{1} with error {2}", ack.Source, port, err)); return false; } Log.Debug(string.Format("HBus: ack from {0}:{1}", ack.Source, port)); switch (ack.Command) { //case NodeCommands.CMD_GET_PIN_INFO: // var pp = new Pin(); // var pi = PinSerializer.DeSerialize(ack.Data, ref pp); // break; case NodeCommands.CMD_READ_PIN: var pe = new PinEvent(ack.Data); evt = new Event { Name = "pin-read", Source = pe.Pin, Channel = "hbus", Value = pe.Value, Status = pe.IsActive ? "active" : "inactive", Timestamp = DateTime.Now }; break; case NodeCommands.CMD_GET_DEVICE_STATUS: var ds = new DeviceStatus(ack.Data); evt = new Event { Name = "device-status", Source = ds.Device, Channel = "hbus", Status = ds.Status, Timestamp = DateTime.Now }; break; //case NodeCommands.CMD_GET_DEVICE_INFO: // var dd = new Device(); // var di = DeviceSerializer.DeSerialize(ack.Data, ref dd); // break; //case NodeCommands.CMD_GET_SENSOR_INFO: // break; case NodeCommands.CMD_READ_SENSOR: var sr = new SensorRead(ack.Data); evt = new Event { Name = "sensor-read", Source = sr.Name, Channel = "hbus", Value = sr.Value, Unit = "", //sr.Unit, //TODO: add to HBus protocol Timestamp = DateTime.Now }; break; } if (evt != null) //Send event to subscribers Send(evt, this); return true; } catch (Exception ex) { Log.Error(string.Format("HBus: error occurred with ack {0} from {1}", ack.Command, ack.Source), ex); //Propagate errors to observers Error(ex, this); } return false; }
/// <summary> /// Execute node command /// </summary> /// <param name="source">Source of command</param> /// <param name="command">HBus command</param> /// <param name="datain">Command data</param> /// <returns>true if command is executed</returns> public bool Execute(Address source, byte command, byte[] datain) { try { byte index; int value; byte delay; byte width; string name; Pin pin; Sensor sensor; Device device; var stack = new SimpleStack(datain); var dataOut = new List<byte>(); var done = false; switch (command) { #region Bus commands case NodeCommands.CMD_PING: dataOut.AddRange(FixedString.ToArray(Name, HBusSettings.NameLength)); _bus.Payload = dataOut.ToArray(); done = true; break; #endregion #region Node commands case NodeCommands.CMD_RESET: index = stack.PopByte(); //1 = full reset Reset(index == 1); done = true; break; case NodeCommands.CMD_START: Start(); done = true; break; case NodeCommands.CMD_STOP: Stop(); done = true; break; case NodeCommands.CMD_FACTORY_DEFAULT: LoadConfiguration(true); done = true; break; case NodeCommands.CMD_READ_CONFIG: LoadConfiguration(false); done = true; break; case NodeCommands.CMD_WRITE_CONFIG: SaveConfiguration(); done = true; break; case NodeCommands.CMD_ADD_NODE_LISTENER: //index = stack.PopByte(); //mask //Add pin to subscriptions if (!_nodeSubscribers.ContainsKey(source)) { _nodeSubscribers.Add(source, 0); SubscribeAll(); done = true; } break; case NodeCommands.CMD_DELETE_NODE_LISTENER: if (_nodeSubscribers.ContainsKey(source)) { _nodeSubscribers.Remove(source); UnsubscribeAll(); done = true; } break; #endregion #region information commands case NodeCommands.CMD_READ_ALL: value = stack.PopByte(); //mask UpdateNodeStatus((byte)value); _bus.Payload = Status.ToArray(); done = true; break; case NodeCommands.CMD_GET_INFO: UpdateNodeInfo(); var array = NodeSerializer.Serialize(this); _bus.Payload = array; done = true; break; case NodeCommands.CMD_GET_NAME_INFO: //Subnode info name = stack.PopName(); var node = GetSubnode(name); if (node != null) { _bus.Payload = node.ToArray(); done = true; } break; #endregion #region General pin commands case NodeCommands.CMD_ACTIVATE: name = stack.PopName(); pin = GetPin(name); if (pin != null) { pin.Activate(); done = true; } break; case NodeCommands.CMD_DEACTIVATE: name = stack.PopName(); pin = GetPin(name); if (pin != null) { pin.Deactivate(); done = true; } break; case NodeCommands.CMD_SET_PIN: pin = new Pin(_hal, _scheduler); PinSerializer.DeSerialize(datain, ref pin); //pin = new Pin(datain, _hal, _scheduler); var oldPin = Pins.FirstOrDefault(p => p.Index == pin.Index); if (oldPin != null) Pins.Remove(oldPin); Pins.Add(pin); done = true; break; case NodeCommands.CMD_CONNECT: //var wire = new Wire(datain, this, _bus); var wire = new Wire(); WireSerializer.DeSerialize(datain, ref wire); wire.Input = Pins.FirstOrDefault(p => p.Name == wire.Input.Name); var oldWire = Wires.FirstOrDefault(w => w.Index == wire.Index); if (oldWire != null) Wires.Remove(oldWire); Wires.Add(wire); done = true; break; case NodeCommands.CMD_ADD_PIN_LISTENER: //Device name name = stack.PopName(); pin = GetPin(name); if (pin != null) { //Add pin to subscriptions if (!_pinSubscribers.ContainsKey(source + "." + name)) _pinSubscribers.Add(source + "." + name, pin); done = true; } break; case NodeCommands.CMD_DELETE_PIN_LISTENER: //Device name name = stack.PopName(); pin = GetPin(name); if (pin != null) { //Add pin to subscriptions if (_pinSubscribers.ContainsKey(source + "." + name)) _pinSubscribers.Remove(source + "." + name); done = true; } break; case NodeCommands.CMD_PUSH_PIN_EVENT: if (OnPinEvent != null) { OnPinEvent(source, new PinEvent(datain)); } done = true; break; #endregion #region Pins digital write commands case NodeCommands.CMD_CHANGE_ALL_DIGITAL: value = stack.PopByte(); foreach (var p in Pins) { p.Change(value); } done = true; break; case NodeCommands.CMD_CHANGE_DIGITAL: index = stack.PopByte(); value = stack.PopByte(); pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.Change(value); done = true; } break; case NodeCommands.CMD_TOGGLE_DIGITAL: index = stack.PopByte(); pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.Toggle(); done = true; } break; case NodeCommands.CMD_TIMED_DIGITAL: index = stack.PopByte(); width = stack.PopByte(); value = stack.PopByte(); pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.TimedOutput(width, value); done = true; } break; case NodeCommands.CMD_DELAY_DIGITAL: index = stack.PopByte(); delay = stack.PopByte(); value = stack.PopByte(); pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.DelayOutput(delay, value); done = true; } break; case NodeCommands.CMD_DELAY_TOGGLE_DIGITAL: index = stack.PopByte(); delay = stack.PopByte(); pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.DelayToggle(delay); done = true; } break; case NodeCommands.CMD_PULSE_DIGITAL: index = stack.PopByte(); delay = stack.PopByte(); width = stack.PopByte(); value = stack.PopByte(); pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.PulsedOutput(delay, width, value); done = true; } break; case NodeCommands.CMD_CYCLE_DIGITAL: index = stack.PopByte(); delay = stack.PopByte(); width = stack.PopByte(); value = stack.PopByte(); //cycles pin = GetPin(index, PinTypes.Output); if (pin != null) { pin.CycledOutput(delay, width, value); done = true; } break; #endregion #region Pins analog/pwm write commands case NodeCommands.CMD_CHANGE_PWM: index = stack.PopByte(); delay = stack.PopByte(); //high pulse width = stack.PopByte(); //total pulse pin = GetPin(index, PinTypes.Pwm); if (pin != null) { pin.ChangePwm(delay, width); done = true; } break; case NodeCommands.CMD_DELTA_PWM: index = stack.PopByte(); value = stack.PopInt16(); pin = GetPin(index, PinTypes.Pwm); if (pin != null) { pin.ChangeDelta(value); done = true; } break; case NodeCommands.CMD_FADE_PWM: index = stack.PopByte(); //type = (PinTypes)stack.PopByte(); var startValue = stack.PopUInt16(); var endValue = stack.PopUInt16(); value = stack.PopByte(); //steps delay = stack.PopByte(); pin = GetPin(index, PinTypes.Pwm); if (pin != null) { pin.Fade(startValue, endValue, (byte)value, delay); done = true; } break; case NodeCommands.CMD_CHANGE_PIN: name = stack.PopName(); value = stack.PopInt32(); pin = GetPin(name); if (pin != null) { pin.Change(value); done = true; } break; #endregion #region Pins read commands case NodeCommands.CMD_GET_PIN_INFO: index = stack.PopByte(); value = stack.PopByte(); pin = GetPin(index, (PinTypes)value); if (pin != null) { _bus.Payload = PinSerializer.Serialize(pin); done = true; } break; case NodeCommands.CMD_GET_CONNECT_INFO: index = stack.PopByte(); wire = Wires.FirstOrDefault(w => w.Index == index); if (wire != null) { array = WireSerializer.Serialize(wire); _bus.Payload = array; done = true; } break; case NodeCommands.CMD_READ_PIN: name = stack.PopName(); pin = GetPin(name); if (pin != null) { //Get pin value var evt = new PinEvent(name, pin.Read(), pin.IsActive()); _bus.Payload = evt.ToArray(); done = true; } break; case NodeCommands.CMD_READ_LAST_INPUT: dataOut.AddRange(FixedString.ToPaddedArray(Status.LastActivatedInput, HBusSettings.NameLength, ' ')); _bus.Payload = dataOut.ToArray(); done = true; break; case NodeCommands.CMD_READ_LAST_ACTIVE: dataOut.AddRange(FixedString.ToPaddedArray(Status.LastActivatedOutput, HBusSettings.NameLength, ' ')); _bus.Payload = dataOut.ToArray(); done = true; break; #endregion #region Device commands case NodeCommands.CMD_GET_DEVICE_INFO: index = stack.PopByte(); device = GetDevice(index); if (device != null) { array = DeviceSerializer.Serialize(device); _bus.Payload = array; done = true; } break; case NodeCommands.CMD_GET_DEVICE_STATUS: name = stack.PopName(); device = GetDevice(name); if (device != null) { var status = new DeviceStatus(device.Index, device.Name, device.Status); _bus.Payload = status.ToArray(); done = true; } break; case NodeCommands.CMD_EXECUTE_DEVICE_ACTION: //Device name var action = new DeviceAction(datain); device = GetDevice(action.Device); //Execute action if (device != null) { device.ExecuteAction(action); done = true; } break; case NodeCommands.CMD_ADD_DEVICE_LISTENER: //Device name name = stack.PopName(); device = GetDevice(name); //Execute action if (device != null) { if (!_deviceSubscribers.ContainsKey(source + "." + name)) _deviceSubscribers.Add(source + "." + name, device); done = true; } break; case NodeCommands.CMD_DELETE_DEVICE_LISTENER: //Device name name = stack.PopName(); device = GetDevice(name); //Execute action if (device != null) { if (_deviceSubscribers.ContainsKey(source + "." + name)) _deviceSubscribers.Remove(source + "." + name); done = true; } break; case NodeCommands.CMD_PUSH_DEVICE_EVENT: if (OnDeviceEvent != null) { var evt = new DeviceEvent(datain); OnDeviceEvent(source, evt); done = true; } break; #endregion #region Sensor commands case NodeCommands.CMD_GET_SENSOR_INFO: index = stack.PopByte(); sensor = GetSensor(index); if (sensor != null) { array = SensorSerializer.Serialize(sensor); _bus.Payload = array; done = true; } break; case NodeCommands.CMD_READ_SENSOR: //Sensor name name = stack.PopName(); sensor = GetSensor(name); if (sensor != null) { _bus.Payload = sensor.Read().ToArray(); done = true; } break; case NodeCommands.CMD_RESET_SENSOR: //Sensor name name = stack.PopName(); sensor = GetSensor(name); if (sensor != null) { sensor.Reset(); done = true; } break; case NodeCommands.CMD_ADD_SENSOR_LISTENER: //Sensor name name = stack.PopName(); var interval = stack.PopByte(); //interval var expire = stack.PopUInt16(); //Expires sensor = GetSensor(name); if (sensor != null) { if (_sensorSubscribers.All(s => s.Sensor != sensor)) _sensorSubscribers.Add(new SensorSubscriber(source, sensor, interval, expire)); done = true; } break; case NodeCommands.CMD_DELETE_SENSOR_LISTENER: //Sensor name name = stack.PopName(); sensor = GetSensor(name); if (sensor != null) { var sub = _sensorSubscribers.FirstOrDefault(s => s.Address == source); if (sub.Sensor != null) _sensorSubscribers.Remove(sub); done = true; } break; case NodeCommands.CMD_PUSH_SENSOR_READ: if (OnSensorRead != null) { OnSensorRead(source, new SensorRead(datain)); } done = true; break; #endregion #region Obolete / unsupported commands //case NodeCommands.CMD_MULTI_ACTIVATE: // //delay = stack.PopByte(); // //var names = stack.PopNames(); // //MultiActivateOutput(names, delay); // SetError(NodeErrorCodes.CommandNotSupported); // break; //case NodeCommands.CMD_READ_KEY: // //value = GetKeyPressed(); // //_bus.Payload = new[] { (byte)value }; // SetError(NodeErrorCodes.CommandNotSupported); // break; #endregion default: SetError(NodeErrorCodes.CommandNotSupported); break; } return done; } catch (Exception ex) { SetError(NodeErrorCodes.GenericError); Log.Error(string.Format("error occurred while processing command {0} for main node {1}", command, Name), ex); } return false; }