271 lines
10 KiB
C#
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());
|
|
}
|
|
|
|
}
|
|
} |