ln.ethercat/ln.ethercat.service/api/v1/EthercatWebSocket.cs

271 lines
10 KiB
C#

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<EthercatWebSocket> activeWebSockets = new List<EthercatWebSocket>();
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<SDODescriptor> subscribedSDOs = new HashSet<SDODescriptor>();
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<UInt16>(jsonValue["Slave"].ToNative());
index = Cast.To<UInt16>(jsonValue["Index"].ToNative());
subindex = Cast.To<byte>(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<SDOAddr> 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<SDOAddr> 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());
}
}
}