using System; using System.Collections.Generic; using System.IO; using ln.http.websocket; using ln.json; using ln.json.mapping; using ln.logging; using ln.type; namespace ln.ethercat.service.api.v1 { public class EthercatWebSocket : WebSocketResponse { /************** Static ***************************************************************************/ static List activeWebSockets = new List(); static bool broadcastActive; public static void SendProcessData(ECMaster ecMaster) { lock (activeWebSockets) { if (broadcastActive) return; broadcastActive = true; } try{ JSONArray jsonPDOList = new JSONArray(); foreach (PDO pdo in ecMaster.GetPDOMap()) { if (JSONMapper.DefaultMapper.Serialize(pdo.SDOValue, out JSONValue jsonValue) && jsonValue is JSONObject jsonPDOValue) { jsonPDOValue.Add("Value", pdo.SDOValue.GetValue()); jsonPDOList.Add(jsonPDOValue); } } JSONObject message = Message("pdo", jsonPDOList); string messageText = message.ToString(); JSONArray slaveStates = new JSONArray(); for (int slave=1; slave <= ecMaster.CountSlaves; slave++) { slaveStates.Add(new JSONObject() .Add("id", new JSONNumber(slave)) .Add("state", new JSONString(ecMaster.ReadSlaveState(slave).ToString())) ); } JSONObject stateMessage = Message("state", new JSONObject() .Add("state", ecMaster.EthercatState.ToString()) .Add("slaves", slaveStates) ); string stateMessageText = stateMessage.ToString(); EthercatWebSocket[] sockets; lock(activeWebSockets) sockets = activeWebSockets.ToArray(); foreach (EthercatWebSocket webSocket in sockets) { if (webSocket.State != WebSocketState.OPEN) { lock (activeWebSockets) activeWebSockets.Remove(webSocket); } else { webSocket.Send(messageText); webSocket.Send(stateMessageText); webSocket.SendSubscribedSDOs(); } } } catch (Exception e) { Logging.Log(e); } finally { broadcastActive = false; } } public static JSONObject Message(string eventName, JSONValue value) => new JSONObject() .Add("event", eventName) .Add("value", value); public static JSONObject Message(long id, string eventName, JSONValue value) => Message(eventName, value) .Add("id", id); public static JSONObject Message(string eventName, object value){ if (JSONMapper.DefaultMapper.Serialize(value, out JSONValue jsonValue)) return Message(eventName, jsonValue); throw new NotSupportedException("the value {0} could not be serialized"); } public static JSONObject Message(long id, string eventName, object value) => Message(eventName, value) .Add("id", id); /************** Instance ***************************************************************************/ HashSet subscribedSDOs = new HashSet(); EthercatService EthercatService; public EthercatWebSocket(EthercatService ethercatService) { EthercatService = ethercatService; OnWebSocketStateChanged += StateChanged; } void StateChanged(WebSocketResponse sender, WebSocketState newState) { switch (newState) { case WebSocketState.OPEN: Logging.Log(LogLevel.DEBUG, "EthercatWebSocket -> active"); lock(activeWebSockets) activeWebSockets.Add(this); break; default: Logging.Log(LogLevel.DEBUG, "EthercatWebSocket -> inactive"); lock(activeWebSockets) activeWebSockets.Remove(this); break; } } public override void Received(string textMessage) { base.Received(textMessage); JSONValue jsonTextValue = JSONParser.Parse(textMessage); if (jsonTextValue is JSONObject jsonMessage) { string eventName = jsonMessage["event"].ToNative().ToString(); switch (eventName) { case "subscribe": if (JSONMapper.DefaultMapper.Deserialize(jsonMessage["value"], out SDOAddr[] addresses)) { Subscribe(addresses); } break; case "unsubscribe": if (JSONMapper.DefaultMapper.Deserialize(jsonMessage["value"], out addresses)) { Unsubscribe(addresses); } break; case "action": break; case "sdowrite": if (jsonMessage["value"] is JSONObject jsonValue) { UInt16 slave_id, index; byte subindex; object value; slave_id = Cast.To(jsonValue["Slave"].ToNative()); index = Cast.To(jsonValue["Index"].ToNative()); subindex = Cast.To(jsonValue["SubIndex"].ToNative()); value = jsonValue["Value"].ToNative(); if (EthercatService.ECMaster.GetSDOValue(slave_id, index, subindex, out SDOValue sdoValue)) { sdoValue.SetValue(value); } else { Logging.Log(LogLevel.DEBUG, "EthercatWebSocket: event sdowrite: could not find SDOValue {0}:{1:X4}.{2}", slave_id, index, subindex); } } break; } } } public void Subscribe(IEnumerable addresses) { lock(subscribedSDOs) foreach (SDOAddr address in addresses) { if ( EthercatService.ECMaster.GetSlave(address.Slave, out ECSlave slave) && slave.GetDescriptor(address.Index, out SDODescriptor descriptor) ) { subscribedSDOs.Add(descriptor); Logging.Log("EthercatWebSocket: subscribed: {0}", address); } } Logging.Log("EthercatWebSocket: subscribed now: {0}", subscribedSDOs.Count); } public void Unsubscribe(IEnumerable addresses) { lock(subscribedSDOs) foreach (SDOAddr address in addresses) { if ( EthercatService.ECMaster.GetSlave(address.Slave, out ECSlave slave) && slave.GetDescriptor(address.Index, out SDODescriptor descriptor) ) { subscribedSDOs.Remove(descriptor); Logging.Log("EthercatWebSocket: unsubscribed: {0}", address); } } Logging.Log("EthercatWebSocket: subscribed now: {0}", subscribedSDOs.Count); } public void SendSubscribedSDOs() { JSONArray jsonSDOList = new JSONArray(); lock(subscribedSDOs) foreach (SDODescriptor descriptor in subscribedSDOs) { if ( JSONMapper.DefaultMapper.Serialize(descriptor, out JSONValue jsonValue) && jsonValue is JSONObject jsonDescriptor ) { jsonSDOList.Add(jsonDescriptor); JSONArray jsonValues = new JSONArray(); jsonDescriptor["Values"] = jsonValues; byte maxValueIndex = 0; foreach (SDOValue sdoValue in descriptor.GetValues()) { if (JSONMapper.DefaultMapper.Serialize(sdoValue, out JSONValue jsonSDOValue) && jsonSDOValue is JSONObject jsonSDOValueObject) { try{ if (sdoValue.SubIndex <= maxValueIndex) { if (sdoValue.GetRawValue(out byte[] rawValue)) { ECDataTypeConverter.FromEthercat(sdoValue.DataType, rawValue, out object value); jsonSDOValueObject.Add("Value", value); if ((descriptor.MaxSubIndex > 0) && (sdoValue.SubIndex == 0)) { //Logging.Log(LogLevel.DEBUG, "--> {0}:{1:X4}.{2} = {3}", descriptor.SlaveId, descriptor.Index, sdoValue.SubIndex, jsonSDOValueObject["Value"].ToString()); maxValueIndex = rawValue[0]; } } } } catch (IOException) { jsonSDOValueObject.Add("Value", "-"); } jsonValues.Add(jsonSDOValue); } } } } JSONObject jsonMessage = Message("sdo", jsonSDOList); Send(jsonMessage.ToString()); } } }