This commit is contained in:
shuai.li
2026-07-21 11:11:01 +08:00
commit a420e9ae74
124 changed files with 16517 additions and 0 deletions
+291
View File
@@ -0,0 +1,291 @@
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();
// }
//}
}