more work on twins
This commit is contained in:
Родитель
d259bcab52
Коммит
184cce7ce5
|
@ -9,7 +9,6 @@
|
|||
<ProjectReference Include="..\Jacdac.NET\Jacdac.NET.csproj" />
|
||||
<ProjectReference Include="..\Jacdac.Transports.Spi\Jacdac.Transports.Spi.csproj" />
|
||||
<ProjectReference Include="..\Jacdac.Transports.WebSockets\Jacdac.Transports.WebSockets.csproj" />
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace Jacdac.NET.Playground
|
|||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
NETPlatform.Init();
|
||||
Console.WriteLine("jacdac: connecting...");
|
||||
ServiceTwins twins = null;
|
||||
var bus = new JDBus(null);
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
|
@ -25,6 +25,10 @@ namespace Jacdac.NET.Playground
|
|||
Console.WriteLine("adding devtools connection");
|
||||
bus.AddTransport(new WebSocketTransport());
|
||||
break;
|
||||
case "twins":
|
||||
Console.WriteLine("tracking twins");
|
||||
twins = new ServiceTwins();
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (var transport in bus.Transports)
|
||||
|
@ -46,6 +50,12 @@ namespace Jacdac.NET.Playground
|
|||
foreach (var service in services)
|
||||
{
|
||||
Console.WriteLine(service);
|
||||
if (twins != null)
|
||||
{
|
||||
var spec = twins.ResolveSpecification(service.ServiceClass);
|
||||
if (spec != null)
|
||||
Console.WriteLine(spec);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Jacdac.NET.Playground": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "devtools twins",
|
||||
"hotReloadEnabled": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,15 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Jacdac\*.cs">
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Jacdac\Servers\*.cs">
|
||||
<Link>Servers\%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Jacdac\Constants\*.cs">
|
||||
<Link>Constants\%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
</Compile>
|
||||
<None Include="..\jacdac.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
|
@ -26,10 +35,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DeviceId.Windows" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
using DeviceId;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Jacdac.NET
|
||||
namespace Jacdac
|
||||
{
|
||||
public static class NETPlatform
|
||||
public partial class Platform
|
||||
{
|
||||
public static void Init()
|
||||
static Platform()
|
||||
{
|
||||
var deviceId = new DeviceIdBuilder()
|
||||
.AddMachineName()
|
||||
|
@ -25,4 +28,59 @@ namespace Jacdac.NET
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ServiceTwins
|
||||
{
|
||||
static ServiceTwins()
|
||||
{
|
||||
SpecificationReader = ServiceTwinReader;
|
||||
SpecificationResolver = WebGet;
|
||||
}
|
||||
|
||||
static ServiceTwinSpec ServiceTwinReader(byte[] buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
var s = System.Text.UTF8Encoding.UTF8.GetString(buffer);
|
||||
return JsonSerializer.Deserialize<ServiceTwinSpec>(buffer, new JsonSerializerOptions
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
IncludeFields = true
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] WebGet(string url)
|
||||
{
|
||||
var req = HttpWebRequest.Create(url) as HttpWebRequest;
|
||||
{
|
||||
req.KeepAlive = false;
|
||||
req.ReadWriteTimeout = 2000;
|
||||
req.Headers[HttpRequestHeader.Accept] = "application/json";
|
||||
//req.HttpsAuthentCerts = certx509;
|
||||
using (var res = req.GetResponse() as HttpWebResponse)
|
||||
{
|
||||
if (res.StatusCode == HttpStatusCode.OK)
|
||||
using (var stream = res.GetResponseStream())
|
||||
{
|
||||
var mem = new MemoryStream();
|
||||
var read = 0;
|
||||
var buf = new byte[512];
|
||||
do
|
||||
{
|
||||
read = stream.Read(buf, 0, buf.Length);
|
||||
mem.Write(buf, 0, read);
|
||||
} while (read > 0);
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
<ProjectReference Include="..\Jacdac.NET\Jacdac.NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -7,6 +7,7 @@ using Jacdac;
|
|||
using System;
|
||||
using Jacdac.Servers;
|
||||
using GHIElectronics.TinyCLR.Devices.Jacdac.Transport;
|
||||
using Jacdac.Transports;
|
||||
|
||||
namespace Jacdac_RgbLed
|
||||
{
|
||||
|
@ -17,7 +18,7 @@ namespace Jacdac_RgbLed
|
|||
new Program().Start();
|
||||
}
|
||||
|
||||
ServiceTwins serviceTwins;
|
||||
// ServiceTwins serviceTwins;
|
||||
public void Start()
|
||||
{
|
||||
// Display enable
|
||||
|
@ -39,7 +40,7 @@ namespace Jacdac_RgbLed
|
|||
var ssidStorage = sdStorage.MountKeyStorage("wifi.json");
|
||||
var serviceStorage = sdStorage.MountKeyStorage("servicestwins.json");
|
||||
var settingsStorage = sdStorage.MountKeyStorage("settings.json");
|
||||
this.serviceTwins = new ServiceTwins(serviceStorage);
|
||||
// this.serviceTwins = new ServiceTwins(serviceStorage);
|
||||
|
||||
var rtc = new RealTimeClockServer(() => DateTime.Now, new RealTimeClockServerOptions { Variant = RealTimeClockVariant.Crystal });
|
||||
var wifiServer = new WifiServer(ssidStorage);
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
<Link>Constants\%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UartTransport.cs" />
|
||||
<Compile Include="TinyCLRPlatform.cs" />
|
||||
<Compile Include="Transports\UartTransport.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
using GHIElectronics.TinyCLR.Data.Json;
|
||||
using GHIElectronics.TinyCLR.Devices.Jacdac.Transport;
|
||||
using GHIElectronics.TinyCLR.Native;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace Jacdac
|
||||
{
|
||||
public partial class Platform
|
||||
{
|
||||
static Platform()
|
||||
{
|
||||
Platform.Crc16 = JacdacSerialWireController.Crc;
|
||||
var id = DeviceInformation.GetUniqueId();
|
||||
// TODO: compress device id into 8 bytes
|
||||
var jid = Util.Slice(id, 0, 8);
|
||||
Platform.DeviceId = jid;
|
||||
for (var i = 8; i < id.Length; ++i)
|
||||
{
|
||||
jid[i % jid.Length] |= (byte)(id[i] << 4);
|
||||
}
|
||||
Platform.DeviceId = jid;
|
||||
Platform.DeviceDescription = DeviceInformation.DeviceName;
|
||||
var version = DeviceInformation.Version;
|
||||
var major = (ushort)((version >> 48) & 0xFFFF);
|
||||
var minor = (ushort)((version >> 32) & 0xFFFF);
|
||||
var build = (ushort)((version >> 16) & 0xFFFF);
|
||||
var revision = (ushort)((version >> 0) & 0xFFFF);
|
||||
Platform.FirmwareVersion = major + "." + minor + "." + build + "." + revision;
|
||||
Platform.RealTimeClock = RealTimeClockVariant.Crystal;
|
||||
Platform.CreateClock = () =>
|
||||
{
|
||||
var start = DateTime.Now;
|
||||
return () => DateTime.Now - start;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ServiceTwins
|
||||
{
|
||||
static ServiceTwins()
|
||||
{
|
||||
SpecificationReader = ServiceTwinReader;
|
||||
SpecificationResolver = WebGet;
|
||||
}
|
||||
|
||||
static ServiceTwinSpec ServiceTwinReader(byte[] buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = System.Text.UTF8Encoding.UTF8.GetString(buffer);
|
||||
return (ServiceTwinSpec)JsonConverter.DeserializeObject(text, typeof(ServiceTwinSpec),
|
||||
(string instancePath, JToken token, Type baseType, string fieldName, int length) =>
|
||||
{
|
||||
if (instancePath == "/")
|
||||
return new ServiceTwinSpec();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] WebGet(string url)
|
||||
{
|
||||
//var certx509 = new X509Certificate[] { new X509Certificate(certificates) };
|
||||
using (var req = HttpWebRequest.Create(url) as HttpWebRequest)
|
||||
{
|
||||
req.KeepAlive = false;
|
||||
req.ReadWriteTimeout = 2000;
|
||||
req.Headers.Add("Accept", "application/json");
|
||||
//req.HttpsAuthentCerts = certx509;
|
||||
using (var res = req.GetResponse() as HttpWebResponse)
|
||||
{
|
||||
if (res.StatusCode == HttpStatusCode.OK)
|
||||
using (var stream = res.GetResponseStream())
|
||||
{
|
||||
var mem = new MemoryStream();
|
||||
var read = 0;
|
||||
var buf = new byte[512];
|
||||
do
|
||||
{
|
||||
read = stream.Read(buf, 0, buf.Length);
|
||||
mem.Write(buf, 0, buf.Length);
|
||||
} while (read != 0);
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
using GHIElectronics.TinyCLR.Data.Json;
|
||||
using GHIElectronics.TinyCLR.Native;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using GHIElectronics.TinyCLR.Devices.Jacdac.Transport;
|
||||
|
||||
namespace Jacdac.Transports
|
||||
{
|
||||
public sealed partial class UartTransport : Jacdac.Transport
|
||||
{
|
||||
public readonly GHIElectronics.TinyCLR.Devices.Jacdac.Transport.JacdacSerialWireController controller;
|
||||
|
||||
public UartTransport(GHIElectronics.TinyCLR.Devices.Jacdac.Transport.JacdacSerialWireController controller)
|
||||
: base("uart")
|
||||
{
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public override event FrameReceivedEvent FrameReceived
|
||||
{
|
||||
add
|
||||
{
|
||||
this.controller.PacketReceived += (JacdacSerialWireController sender, PacketReceivedEventArgs packet) =>
|
||||
{
|
||||
var frame = packet.Data;
|
||||
value(this, frame);
|
||||
};
|
||||
}
|
||||
remove
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// not supported
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override event TransportErrorReceivedEvent ErrorReceived
|
||||
{
|
||||
add
|
||||
{
|
||||
this.controller.ErrorReceived += (JacdacSerialWireController sender, ErrorReceivedEventArgs args) =>
|
||||
{
|
||||
value(this, new TransportErrorReceivedEventArgs((TransportError)(uint)args.Error, args.Timestamp, args.Data));
|
||||
};
|
||||
}
|
||||
remove
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// not supported
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InternalConnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.controller.Enable();
|
||||
this.SetConnectionState(ConnectionState.Connected);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.SetConnectionState(ConnectionState.Disconnected);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InternalDisconnect()
|
||||
{
|
||||
this.controller.Disable();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
this.controller.Dispose();
|
||||
}
|
||||
|
||||
public override void SendFrame(byte[] data)
|
||||
{
|
||||
TransportStats.FrameSent++;
|
||||
this.controller.Write(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
using GHIElectronics.TinyCLR.Data.Json;
|
||||
using GHIElectronics.TinyCLR.Native;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using GHIElectronics.TinyCLR.Devices.Jacdac.Transport;
|
||||
|
||||
namespace Jacdac
|
||||
{
|
||||
public sealed class UartTransport : Transport
|
||||
{
|
||||
static UartTransport()
|
||||
{
|
||||
Platform.Crc16 = JacdacSerialWireController.Crc;
|
||||
var id = DeviceInformation.GetUniqueId();
|
||||
// TODO: compress device id into 8 bytes
|
||||
var jid = Util.Slice(id, 0, 8);
|
||||
Platform.DeviceId = jid;
|
||||
for (var i = 8; i < id.Length; ++i)
|
||||
{
|
||||
jid[i % jid.Length] |= (byte)(id[i] << 4);
|
||||
}
|
||||
Platform.DeviceId = jid;
|
||||
Platform.DeviceDescription = DeviceInformation.DeviceName;
|
||||
var version = DeviceInformation.Version;
|
||||
var major = (ushort)((version >> 48) & 0xFFFF);
|
||||
var minor = (ushort)((version >> 32) & 0xFFFF);
|
||||
var build = (ushort)((version >> 16) & 0xFFFF);
|
||||
var revision = (ushort)((version >> 0) & 0xFFFF);
|
||||
Platform.FirmwareVersion = major + "." + minor + "." + build + "." + revision;
|
||||
Platform.RealTimeClock = RealTimeClockVariant.Crystal;
|
||||
Platform.CreateClock = () =>
|
||||
{
|
||||
var start = DateTime.Now;
|
||||
return () => DateTime.Now - start;
|
||||
};
|
||||
Platform.ServiceTwinReader = (byte[] buffer) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = System.Text.UTF8Encoding.UTF8.GetString(buffer);
|
||||
return (ServiceTwinSpec)JsonConverter.DeserializeObject(text, typeof(ServiceTwinSpec),
|
||||
(string instancePath, JToken token, Type baseType, string fieldName, int length) =>
|
||||
{
|
||||
if (instancePath == "/")
|
||||
return new ServiceTwinSpec();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Platform.WebGet = (string url) =>
|
||||
{
|
||||
//var certx509 = new X509Certificate[] { new X509Certificate(certificates) };
|
||||
using (var req = HttpWebRequest.Create(url) as HttpWebRequest)
|
||||
{
|
||||
req.KeepAlive = false;
|
||||
req.ReadWriteTimeout = 2000;
|
||||
//req.HttpsAuthentCerts = certx509;
|
||||
using (var res = req.GetResponse() as HttpWebResponse)
|
||||
{
|
||||
if (res.StatusCode == HttpStatusCode.OK)
|
||||
using (var stream = res.GetResponseStream())
|
||||
{
|
||||
var mem = new MemoryStream();
|
||||
var read = 0;
|
||||
var buf = new byte[512];
|
||||
do
|
||||
{
|
||||
read = stream.Read(buf, 0, buf.Length);
|
||||
mem.Write(buf, 0, buf.Length);
|
||||
} while (read != 0);
|
||||
return mem.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
public readonly GHIElectronics.TinyCLR.Devices.Jacdac.Transport.JacdacSerialWireController controller;
|
||||
|
||||
public UartTransport(GHIElectronics.TinyCLR.Devices.Jacdac.Transport.JacdacSerialWireController controller)
|
||||
: base("uart")
|
||||
{
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public override event FrameReceivedEvent FrameReceived
|
||||
{
|
||||
add
|
||||
{
|
||||
this.controller.PacketReceived += (JacdacSerialWireController sender, PacketReceivedEventArgs packet) =>
|
||||
{
|
||||
var frame = packet.Data;
|
||||
value(this, frame);
|
||||
};
|
||||
}
|
||||
remove
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// not supported
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override event TransportErrorReceivedEvent ErrorReceived
|
||||
{
|
||||
add
|
||||
{
|
||||
this.controller.ErrorReceived += (JacdacSerialWireController sender, ErrorReceivedEventArgs args) =>
|
||||
{
|
||||
value(this, new TransportErrorReceivedEventArgs((TransportError)(uint)args.Error, args.Timestamp, args.Data));
|
||||
};
|
||||
}
|
||||
remove
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// not supported
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InternalConnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.controller.Enable();
|
||||
this.SetConnectionState(ConnectionState.Connected);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.SetConnectionState(ConnectionState.Disconnected);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InternalDisconnect()
|
||||
{
|
||||
this.controller.Disable();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
this.controller.Dispose();
|
||||
}
|
||||
|
||||
public override void SendFrame(byte[] data)
|
||||
{
|
||||
TransportStats.FrameSent++;
|
||||
this.controller.Write(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
<ProjectReference Include="..\Jacdac.NET\Jacdac.NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
<ProjectReference Include="..\Jacdac.NET\Jacdac.NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jacdac.NET\Jacdac.NET.csproj" />
|
||||
<ProjectReference Include="..\Jacdac.Transports.Hf2\Jacdac.Transports.Hf2.csproj" />
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Jacdac.NET\Jacdac.NET.csproj" />
|
||||
<ProjectReference Include="..\Jacdac\Jacdac.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Jacdac
|
|||
public SetStatusLightHandler SetStatusLight = Platform.SetStatusLight;
|
||||
}
|
||||
|
||||
public sealed class JDBus : JDNode
|
||||
public sealed partial class JDBus : JDNode
|
||||
{
|
||||
// updated concurrently, locked by this
|
||||
private JDDevice[] devices;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Jacdac
|
||||
{
|
||||
public sealed class ControlServer : JDServiceServer
|
||||
public sealed partial class ControlServer : JDServiceServer
|
||||
{
|
||||
private SetStatusLightHandler setStatusLight;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Threading;
|
|||
|
||||
namespace Jacdac
|
||||
{
|
||||
public sealed class JDDevice : JDNode
|
||||
public sealed partial class JDDevice : JDNode
|
||||
{
|
||||
private JDBus bus;
|
||||
public readonly string DeviceId;
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections;
|
|||
|
||||
namespace Jacdac
|
||||
{
|
||||
public sealed class JDDeviceServer
|
||||
public sealed partial class JDDeviceServer
|
||||
{
|
||||
public readonly JDBus Bus;
|
||||
public readonly string DeviceId;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace Jacdac
|
||||
{
|
||||
public sealed class JDEvent : JDServiceNode
|
||||
public sealed partial class JDEvent : JDServiceNode
|
||||
{
|
||||
private Packet _lastReportPkt;
|
||||
public uint Count = 0;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<TargetFramework>net5.0</TargetFramework>
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<Description>Jacdac runtime for .NET</Description>
|
||||
<Copyright>Microsoft Corporation</Copyright>
|
||||
<PackageProjectUrl>https://aka.ms/jacdac</PackageProjectUrl>
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Jacdac
|
|||
public delegate short McuTemperatureCalculator();
|
||||
public delegate void SetStatusLightHandler(byte red, byte green, byte blue, byte speed);
|
||||
|
||||
public static class Platform
|
||||
public static partial class Platform
|
||||
{
|
||||
public static byte[] DeviceId;
|
||||
public static string FirmwareVersion;
|
||||
|
@ -30,8 +30,6 @@ namespace Jacdac
|
|||
return crc;
|
||||
};
|
||||
public static McuTemperatureCalculator McuTemperature;
|
||||
public static ServiceTwinSpecReader ServiceTwinReader;
|
||||
public static HttpWebRequestGet WebGet;
|
||||
|
||||
public static ControlAnnounceFlags StatusLight = ControlAnnounceFlags.StatusLightNone;
|
||||
public static SetStatusLightHandler SetStatusLight = null;
|
||||
|
@ -45,6 +43,4 @@ namespace Jacdac
|
|||
void Delete(string key);
|
||||
void Clear();
|
||||
}
|
||||
|
||||
public delegate byte[] HttpWebRequestGet(string url);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections;
|
|||
|
||||
namespace Jacdac
|
||||
{
|
||||
public sealed class JDService : JDNode
|
||||
public sealed partial class JDService : JDNode
|
||||
{
|
||||
JDDevice _device;
|
||||
public readonly byte ServiceIndex;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Jacdac
|
|||
public string InstanceName;
|
||||
}
|
||||
|
||||
public abstract class JDServiceServer : JDNode
|
||||
public abstract partial class JDServiceServer : JDNode
|
||||
{
|
||||
public byte ServiceIndex;
|
||||
public JDDeviceServer Device;
|
||||
|
|
|
@ -20,6 +20,12 @@ namespace Jacdac
|
|||
public ServiceTwinRegisterFlag flags;
|
||||
public string packf;
|
||||
public string[] fields;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var c = this.code.ToString("x2");
|
||||
return $"{this.name} ({c})";
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
@ -28,49 +34,79 @@ namespace Jacdac
|
|||
public uint serviceClass;
|
||||
public string name;
|
||||
public ServiceTwinRegisterSpec[] registers;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sc = this.serviceClass.ToString("x8");
|
||||
return $"{this.name} (0x{sc})";
|
||||
}
|
||||
}
|
||||
|
||||
public delegate ServiceTwinSpec ServiceTwinSpecReader(byte[] buffer);
|
||||
public delegate byte[] ServiceTwinSpecResolver(string url);
|
||||
|
||||
public sealed class ServiceTwins
|
||||
public sealed partial class ServiceTwins : JDNode
|
||||
{
|
||||
public string Root = "https://microsoft.github.io/jacdac-docs/";
|
||||
public readonly IKeyStorage Storage;
|
||||
public readonly ServiceTwinSpecReader SpecificationReader;
|
||||
public static ServiceTwinSpecReader SpecificationReader;
|
||||
public static ServiceTwinSpecResolver SpecificationResolver;
|
||||
private ServiceTwinSpec[] specifications;
|
||||
|
||||
public ServiceTwins(IKeyStorage storage)
|
||||
public ServiceTwins(IKeyStorage storage = null)
|
||||
{
|
||||
Debug.Assert(SpecificationReader != null);
|
||||
Debug.Assert(SpecificationResolver != null);
|
||||
|
||||
this.Storage = storage;
|
||||
this.SpecificationReader = Platform.ServiceTwinReader;
|
||||
this.specifications = new ServiceTwinSpec[0];
|
||||
}
|
||||
|
||||
public ServiceTwinSpec ResolveSpecification(uint serviceClass)
|
||||
{
|
||||
var spec = this.ReadFromStorage(serviceClass);
|
||||
if (spec == null)
|
||||
spec = this.DownloadSpecification(serviceClass);
|
||||
return spec;
|
||||
lock (this)
|
||||
{
|
||||
// in memory cache, need limit?
|
||||
var specifications = this.specifications;
|
||||
foreach (var specification in specifications)
|
||||
if (specification.serviceClass == serviceClass)
|
||||
return specification;
|
||||
|
||||
// look cached spec
|
||||
var spec = this.ReadFromStorage(serviceClass);
|
||||
if (spec == null)
|
||||
spec = this.DownloadSpecification(serviceClass);
|
||||
if (spec != null)
|
||||
{
|
||||
var newSpecs = new ServiceTwinSpec[specifications.Length + 1];
|
||||
specifications.CopyTo(newSpecs, 0);
|
||||
newSpecs[newSpecs.Length - 1] = spec;
|
||||
this.specifications = newSpecs;
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
private ServiceTwinSpec ReadFromStorage(uint serviceClass)
|
||||
{
|
||||
Debug.WriteLine($"twins: read {serviceClass} from storage");
|
||||
var key = serviceClass.ToString("x8");
|
||||
var buffer = this.Storage?.Read(key);
|
||||
if (buffer == null) return null;
|
||||
else return this.SpecificationReader(buffer);
|
||||
else return SpecificationReader(buffer);
|
||||
}
|
||||
|
||||
private ServiceTwinSpec DownloadSpecification(uint serviceClass)
|
||||
{
|
||||
var key = serviceClass.ToString("x8");
|
||||
var url = $"http://microsoft.github.io/jacdac-docs/services/twin/x{serviceClass.ToString("x8")}.json";
|
||||
var url = $"http://microsoft.github.io/jacdac-docs/services/twin/x{serviceClass.ToString("x")}.json";
|
||||
Debug.WriteLine($"fetch {url}");
|
||||
try
|
||||
{
|
||||
var buffer = Platform.WebGet(url);
|
||||
var buffer = SpecificationResolver(url);
|
||||
if (buffer != null)
|
||||
{
|
||||
var spec = this.SpecificationReader(buffer);
|
||||
var spec = SpecificationReader(buffer);
|
||||
this.Storage?.Write(key, buffer);
|
||||
return spec;
|
||||
}
|
||||
|
|
|
@ -19,17 +19,18 @@ This layer is still under construction.
|
|||
This repository contains a C# implementation of the Jacdac protocol for various .NET runtime, including desktop or TinyClR.
|
||||
To avoid mscorlib issues, each platform has a different set of assemblies where C# files are simply shared as links.
|
||||
|
||||
- `Jacdac`, core Jacdac library, .NET5
|
||||
- `Jacdac.NET`, HF2 protocol layer and .NET famework specific platform, .NET5
|
||||
- `Jacdac`, C# Jacdac library, .NET5. This package serves as a placeholder for C# files and
|
||||
and is not referenced anywhere.
|
||||
- `Jacdac.NET`, .NET famework specific platform, .NET5
|
||||
- `Jacdac.NET.Playground`, .NET5 test application using jacdac development server
|
||||
- `Jacdac.Transports.WebSockets`, WebSocket transport, .NET5
|
||||
- `Jacdac.Transports.Spi`, SPI transport layer for SPI Jacdapter using .NET IoT, .NET5
|
||||
- `Jacdac.TinyCLR`, mirror of `Jacdac` library, TinyCLR
|
||||
- `Jacdac.TinyCLR.Playground`, TinyCLR test application
|
||||
- `Jacdac.Tests`, unit tests, .NET6
|
||||
|
||||
- `Jacdac.Transports.Hf2`, HF2 protocol layer, .NET6, under construction
|
||||
- `Jacdac.Transports.Usb`, Usb transport, .NET6, under construction
|
||||
- `Jacdac.Transports.Spi`, SPI transport layer for SPI Jacdapter using .NET IoT, .NET5, under construction
|
||||
|
||||
## Developer setup
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче