292 lines
11 KiB
C#
292 lines
11 KiB
C#
using CartActivator;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Newtonsoft.Json;
|
|
using FundamentalLib;
|
|
|
|
|
|
namespace MedullaAdapter
|
|
{
|
|
// todo: currently use this ladderlogic to act interaction with Medulla.
|
|
// todo: directly integrate into CartActivator.
|
|
|
|
// MCU->Medulla is intervally exchanged information.
|
|
public class MCUInterface<T> : LadderLogic<T> where T : DiverCartDefinition
|
|
{
|
|
|
|
/// ////////////////////////////// IMPLEMENT THESE ////////////////////////////////////////////
|
|
|
|
public static void SetMCUProgram(string mcu_device_url, byte[] program)
|
|
{
|
|
List<byte[]> SplitArrayIntoChunks(byte[] array, int chunkSize)
|
|
{
|
|
List<byte[]> chunks = new List<byte[]>();
|
|
|
|
for (int i = 0; i < array.Length; i += chunkSize)
|
|
{
|
|
int currentChunkSize = Math.Min(chunkSize, array.Length - i);
|
|
byte[] chunk = new byte[currentChunkSize];
|
|
Array.Copy(array, i, chunk, 0, currentChunkSize);
|
|
chunks.Add(chunk);
|
|
}
|
|
return chunks;
|
|
}
|
|
//todo: modify this.
|
|
var codeList = SplitArrayIntoChunks(program, 1024);
|
|
int i = 0;
|
|
foreach (var codePack in codeList)
|
|
{
|
|
var downloadCode =
|
|
new DownloadCodePack(program.Length, 1024 * i, codePack.Length, codePack).GetPack();
|
|
Console.WriteLine(string.Join(" ", downloadCode.Select(p => $"{p:X2}")));
|
|
cart.Embedded.SendMessage(downloadCode);
|
|
Console.WriteLine($"send bytes length:{downloadCode.Length}");
|
|
i++;
|
|
Thread.Sleep(50);
|
|
//while (true)
|
|
//{
|
|
// var receive = cart.Embedded.GetMessage();
|
|
// if (receive == null) continue;
|
|
// if (receive[5] == 0x90 && (receive[6] == 0x05 || receive[6]==0x06)) break;
|
|
//}
|
|
}
|
|
var controlPack2 = new ControlPack(0x01).GetPack();
|
|
cart.Embedded.SendMessage(controlPack2);
|
|
Console.WriteLine("下发代码");
|
|
//MCUTestRunner.DebugSetMCUProgram(program, (bs) => NotifyLowerData("default", bs));
|
|
}
|
|
|
|
public static void SendUpperData(string mcu_device_url, byte[] data)
|
|
{
|
|
//todo: this is for VM data exchange, contains upperIO/lowerIO modifications.
|
|
var upperPack = new UpperIOPack(data, data.Length).GetPack();
|
|
cart.Embedded.SendMessage(upperPack);
|
|
//MCUTestRunner.DebugSendUpper(data);
|
|
}
|
|
|
|
|
|
/// ////////////////////////////// INTERFACES ////////////////////////////////////////////
|
|
|
|
public static void NotifyPrint(string mcu_device_url, string message)
|
|
{
|
|
Console.WriteLine($"{mcu_device_url}:{message}");
|
|
}
|
|
|
|
// whenever a lower io data is uploaded, call this.
|
|
public static void NotifyLowerData(string mcu_device_url, byte[] lowerIOData)
|
|
{
|
|
using var ms = new MemoryStream(lowerIOData);
|
|
using var br = new BinaryReader(ms);
|
|
if (mcu_logics.TryGetValue(mcu_device_url, out var tup))
|
|
{
|
|
Hedingben.ToastText($"recv iter {br.ReadInt32()} lowerIO data from {mcu_device_url}, operation {tup.name}", $"DIVER-{tup.name}");
|
|
while (ms.Position < lowerIOData.Length)
|
|
{
|
|
var cid = br.ReadInt16();
|
|
if (cid < 0 || cid > tup.fields.Length) throw new Exception("invalid Cartfield id!");
|
|
// if it's upperio skip, otherwise write data.
|
|
var typeid = br.ReadByte();
|
|
if (tup.fields[cid].typeid != typeid)
|
|
throw new Exception($"??? typeid not match for {tup.fields[cid].field}({cid}), expected {tup.fields[cid].typeid} got {typeid}");
|
|
|
|
object value;
|
|
switch (tup.fields[cid].typeid)
|
|
{
|
|
case 0:
|
|
value = br.ReadBoolean();
|
|
break;
|
|
case 1:
|
|
value = br.ReadByte();
|
|
break;
|
|
case 2:
|
|
value = br.ReadSByte();
|
|
break;
|
|
case 3:
|
|
value = br.ReadChar();
|
|
break;
|
|
case 4:
|
|
value = br.ReadInt16();
|
|
break;
|
|
case 5:
|
|
value = br.ReadUInt16();
|
|
break;
|
|
case 6:
|
|
value = br.ReadInt32();
|
|
break;
|
|
case 7:
|
|
value = br.ReadUInt32();
|
|
break;
|
|
case 8:
|
|
value = br.ReadSingle();
|
|
break;
|
|
default:
|
|
throw new Exception($"Unsupported type ID: {tup.fields[cid].typeid}");
|
|
}
|
|
|
|
if (tup.fields[cid].isUpper) continue;
|
|
tup.fields[cid].fi.SetValue(cart, value);
|
|
}
|
|
|
|
// ok to send current data.
|
|
using var sends = new MemoryStream();
|
|
using var bw = new BinaryWriter(sends);
|
|
bw.Write(tup.iterations++);
|
|
for (var cid = 0; cid < tup.fields.Length; cid++)
|
|
{
|
|
bw.Write((short)cid);
|
|
bw.Write((byte)tup.fields[cid].typeid);
|
|
var val = tup.fields[cid].fi.GetValue(cart);
|
|
switch (tup.fields[cid].typeid)
|
|
{
|
|
case 0:
|
|
bw.Write((bool)val);
|
|
break;
|
|
case 1:
|
|
bw.Write((byte)val);
|
|
break;
|
|
case 2:
|
|
bw.Write((sbyte)val);
|
|
break;
|
|
case 3:
|
|
bw.Write((char)val);
|
|
break;
|
|
case 4:
|
|
bw.Write((short)val);
|
|
break;
|
|
case 5:
|
|
bw.Write((ushort)val);
|
|
break;
|
|
case 6:
|
|
bw.Write((int)val);
|
|
break;
|
|
case 7:
|
|
bw.Write((uint)val);
|
|
break;
|
|
case 8:
|
|
bw.Write((float)val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SendUpperData(mcu_device_url, sends.ToArray());
|
|
}
|
|
else
|
|
{
|
|
Hedingben.ToastText($"warning: {mcu_device_url} received lowerIOData but not registered","DIVERWarning");
|
|
}
|
|
}
|
|
|
|
public static void Start(T c)
|
|
{
|
|
cart = c;
|
|
|
|
var logics = typeof(T).Assembly.GetTypes()
|
|
.Where(p => p.GetCustomAttribute<LogicRunOnMCUAttribute>() != null).ToArray();
|
|
foreach (var logic in logics)
|
|
{
|
|
var attr = logic.GetCustomAttribute<LogicRunOnMCUAttribute>();
|
|
Console.WriteLine($"Set logic {logic.Name} to run on MCU-VM @ device {attr.mcu_url}");
|
|
|
|
byte[] ReadAllBytes(Stream stream)
|
|
{
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
stream.CopyTo(ms);
|
|
return ms.ToArray();
|
|
}
|
|
}
|
|
var bytes = ReadAllBytes(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{logic.Name}.bin"));
|
|
SetMCUProgram(attr.mcu_url, bytes);
|
|
var json = UTF8Encoding.UTF8.GetString(ReadAllBytes(Assembly.GetExecutingAssembly()
|
|
.GetManifestResourceStream($"{logic.Name}.bin.json")));
|
|
Console.WriteLine(json);
|
|
var fields = JsonConvert.DeserializeObject<PField[]>(json);
|
|
if (mcu_logics.ContainsKey(attr.mcu_url))
|
|
throw new Exception($"Already have logic for {attr.mcu_url}: LadderLogic {logic.Name}");
|
|
mcu_logics[attr.mcu_url] = new LogicInfo() { fields = fields, name = logic.Name };
|
|
foreach (var pField in fields)
|
|
{
|
|
pField.fi = typeof(T).GetField(pField.field);
|
|
if (pField.fi == null)
|
|
throw new Exception($"field {pField.field} doesn't exist in cart object?");
|
|
pField.isUpper = pField.fi.IsDefined(typeof(AsUpperIO));
|
|
// todo: check type.
|
|
}
|
|
}
|
|
}
|
|
|
|
/// ///////////////////////////////// DONT CARE /////////////////////////////////////
|
|
private static T cart;
|
|
|
|
class PField
|
|
{
|
|
public string field;
|
|
public FieldInfo fi;
|
|
public bool isUpper;
|
|
public int typeid, offset;
|
|
}
|
|
|
|
class LogicInfo
|
|
{
|
|
public string name;
|
|
public PField[] fields;
|
|
public int iterations;
|
|
}
|
|
private static Dictionary<string, LogicInfo> mcu_logics = new();
|
|
public override void Operation(int iteration)
|
|
{
|
|
// just send LIO.
|
|
}
|
|
}
|
|
|
|
//unsafe class MCUTestRunner
|
|
//{
|
|
|
|
// public delegate void NotifyLowerDelegate(byte* changedStates, int length);
|
|
// [DllImport("MCURuntime.dll", CallingConvention = CallingConvention.Cdecl)]
|
|
// public static extern void set_lowerio_cb(NotifyLowerDelegate callback);
|
|
|
|
// private static NotifyLowerDelegate DNotifyStateChanged = StateChanged;
|
|
|
|
// [DllImport("MCURuntime.dll")]
|
|
// static extern void test(byte* bin, int len);
|
|
// [DllImport("MCURuntime.dll")]
|
|
// static extern void put_upper(byte* bin, int len);
|
|
|
|
// private static Action<byte[]> lo_notifier;
|
|
// private static void StateChanged(byte* changedstates, int length)
|
|
// {
|
|
// byte[] byteArray = new byte[length];
|
|
// Marshal.Copy((IntPtr)changedstates, byteArray, 0, length);
|
|
// lo_notifier(byteArray);
|
|
// }
|
|
|
|
// public static void DebugSendUpper(byte[] data)
|
|
// {
|
|
// fixed (byte* ptr = data)
|
|
// {
|
|
// put_upper(ptr, data.Length);
|
|
// }
|
|
// }
|
|
// public static void DebugSetMCUProgram(byte[] program, Action<byte[]> notifier)
|
|
// {
|
|
// lo_notifier = notifier;
|
|
// set_lowerio_cb(DNotifyStateChanged);
|
|
// new Thread(() =>
|
|
// {
|
|
// var allb = new byte[10240]; //10K runtime
|
|
// Array.Copy(program, allb, program.Length);
|
|
// fixed (byte* ptr = allb)
|
|
// {
|
|
// test(ptr, 10240);
|
|
// }
|
|
// }).Start();
|
|
// }
|
|
//}
|
|
}
|