using CANFDApiProxy.Interfaces; using CANFDApiProxy.Messages; using CANFDApiProxy.Requests; using CsvHelper.Configuration; using DTS.Common.Classes.DASFactory; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading; using System.Threading.Tasks; namespace CANFDApiProxy { public sealed class CANFD : ICANFDApi { private static readonly Lazy lazy = new Lazy(() => new CANFD()); public static CANFD API { get { return lazy.Value; } } private CANFD() { } public async Task GetUsbTree(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.UsbTree, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetBattery(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Battery, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } /// /// gets results of BIST end point on unit /// can throw units /// public async Task GetBIST(string deviceHost, CancellationToken cancellationToken) { var request = new DiagnosticsMessageRequest() { format = "csv" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Diagnostics, request, cancellationToken); var config = new CsvConfiguration(CultureInfo.InvariantCulture) { PrepareHeaderForMatch = args => args.Header.ToLower(), }; using (var reader = new StringReader(jsonResponse.ToString())) { using (var csv = new CsvHelper.CsvReader(reader, config)) { var records = csv.GetRecords().ToArray(); return records; } } } public async Task GetCalibrationDate(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.CalibrationDate, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetSerial(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Serial, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetLEDs(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.LEDs, cancellationToken); var canInternal = JsonConvert.DeserializeObject(jsonResponse); var ledsMessage = new LEDsMessage(); List leds = new List { new LED("can1",canInternal.can1.blue, canInternal.can1.green, canInternal.can1.red), new LED("can2",canInternal.can2.blue, canInternal.can2.green, canInternal.can2.red), new LED("can3",canInternal.can3.blue, canInternal.can3.green, canInternal.can3.red), new LED("can4",canInternal.can4.blue, canInternal.can4.green, canInternal.can4.red) }; ledsMessage.LEDs = leds; ledsMessage.Status = canInternal.status; ledsMessage.Battery = canInternal.battery; ledsMessage.Pwr = canInternal.pwr; ledsMessage.Sts = canInternal.sts; return ledsMessage; } public async Task GetCANInfo(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.CANInfo, cancellationToken); var canInternal = JsonConvert.DeserializeObject(jsonResponse); var canInfoMessage = new CANInfoMessage(); List list = new List { new CANInfo("can1", canInternal.can1.info), new CANInfo("can2", canInternal.can2.info), new CANInfo("can3", canInternal.can3.info), new CANInfo("can4", canInternal.can4.info)}; canInfoMessage.CANInfoList = list; return canInfoMessage; } public async Task GetCANState(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.CANState, cancellationToken); var canInternal = JsonConvert.DeserializeObject(jsonResponse); var canMessage = new CANStateMessage(); List list = new List { new CANState("can1", canInternal.can1.state,canInternal.can1.last_updated ), new CANState("can2", canInternal.can2.state,canInternal.can2.last_updated ), new CANState("can3", canInternal.can3.state,canInternal.can3.last_updated ), new CANState("can4", canInternal.can4.state,canInternal.can4.last_updated )}; canMessage.CANStateList = list; return canMessage; } public async Task GetCANStats(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.CANStats, cancellationToken); var canInternal = JsonConvert.DeserializeObject(jsonResponse); var canMessage = new CANStatsMessage(); List list = new List { new CANStats("can1", canInternal.can1.std_data,canInternal.can1.std_remote,canInternal.can1.ext_data,canInternal.can1.ext_remote,canInternal.can1.err_frame,canInternal.can1.bus_load,canInternal.can1.overruns, canInternal.can1.last_updated ), new CANStats("can2", canInternal.can2.std_data,canInternal.can2.std_remote,canInternal.can2.ext_data,canInternal.can2.ext_remote,canInternal.can2.err_frame,canInternal.can2.bus_load,canInternal.can2.overruns, canInternal.can2.last_updated ), new CANStats("can3", canInternal.can3.std_data,canInternal.can3.std_remote,canInternal.can3.ext_data,canInternal.can3.ext_remote,canInternal.can3.err_frame,canInternal.can3.bus_load,canInternal.can3.overruns, canInternal.can3.last_updated ), new CANStats("can4", canInternal.can4.std_data,canInternal.can4.std_remote,canInternal.can4.ext_data,canInternal.can4.ext_remote,canInternal.can4.err_frame,canInternal.can4.bus_load,canInternal.can4.overruns, canInternal.can4.last_updated )}; canMessage.CANStatsList = list; return canMessage; } public async Task GetCANConfig(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.CANConfig, cancellationToken); var canInternal = JsonConvert.DeserializeObject(jsonResponse); var canMessage = new CANConfigMessage(); List list = new List { new CANConfig("can1", canInternal.can1.base_or_arb_bitrate,canInternal.can1.base_or_arb_sjw, canInternal.can1.data_bitrate, canInternal.can1.data_sjw,canInternal.can1.filetype, canInternal.can1.included, canInternal.can1.is_fd ), new CANConfig("can2", canInternal.can2.base_or_arb_bitrate,canInternal.can2.base_or_arb_sjw, canInternal.can2.data_bitrate, canInternal.can2.data_sjw,canInternal.can2.filetype, canInternal.can2.included, canInternal.can2.is_fd ), new CANConfig("can3", canInternal.can3.base_or_arb_bitrate,canInternal.can3.base_or_arb_sjw, canInternal.can3.data_bitrate, canInternal.can3.data_sjw,canInternal.can3.filetype, canInternal.can3.included, canInternal.can3.is_fd ), new CANConfig("can4", canInternal.can4.base_or_arb_bitrate,canInternal.can4.base_or_arb_sjw, canInternal.can4.data_bitrate, canInternal.can4.data_sjw,canInternal.can4.filetype, canInternal.can4.included, canInternal.can4.is_fd )}; canMessage.CANConfigList = list; canMessage.Pipe = canInternal.pipe; return canMessage; } public async Task GetDeviceInfo(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.DeviceInfo, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetNtp(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Ntp, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetPower(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Power, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetServices(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Services, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetNetwork(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Network, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetClocks(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Clocks, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetEventPin(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.EventPin, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetRecording(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.Recording, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task GetUsbStats(string deviceHost, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.GetResourceAsync(deviceHost, CommandName.UsbStats, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetSerial(string deviceHost, SerialRequest serialRequest, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Serial, serialRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetPowerOff(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "off" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Power, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetPowerReboot(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "reboot" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Power, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetCANConfig(string deviceHost, CANConfigRequest canConfigRequest, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.CANConfig, canConfigRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetLEDs(string deviceHost, LedName led, LedCmd cmd, LedColor color, CancellationToken cancellationToken) { var request = new LEDsRequest { cmd = cmd.ToString(), color = color.ToString(), led = led.ToString() }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.LEDs, request, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetClocks(string deviceHost, DateTime dateTime, CancellationToken cancellationToken) { var request = new ClocksRequest { cmd = "set", time = dateTime.ToString("yyyy-MM-dd HH:mm:ss") }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Clocks, request, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SyncClocks(string deviceHost, CancellationToken cancellationToken) { var request = new ClocksRequest { cmd = "sync" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Clocks, request, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetRecordingStart(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "start" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Recording, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetRecordingTriggerCheck_Quick(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "triggercheck_quick" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Recording, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetRecordingStop(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "stop" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Recording, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetNetwork(string deviceHost, NetworkRequest networkRequest, CancellationToken cancellationToken) { var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.Network, networkRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetEventPinArm(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "arm" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.EventPin, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } public async Task SetEventPinDisarm(string deviceHost, CancellationToken cancellationToken) { var powerRequest = new CanPostRequest { cmd = "disarm" }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.EventPin, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } /// /// Delete the file or directory from the device /// /// device ip address /// usb path of the file or folder which you want to delete from the device /// /// status message /// exception on invalid arguments public async Task Delete(string deviceHost, string usbPath, CancellationToken cancellationToken) { VerifyUsbPathIsNotNull(usbPath); return await DeleteAsync(deviceHost, usbPath, cancellationToken); } private static void VerifyUsbPathIsNotNull(string usbPath) { if (string.IsNullOrEmpty(usbPath)) { throw new ArgumentException("usbPAth cannot be null or empty", "usbPath"); } } private static async Task DeleteAsync(string deviceHost, string usbPath, CancellationToken cancellationToken) { var powerRequest = new FileRequest { cmd = "delete", path = usbPath }; var jsonResponse = await RESTWrapper.PostResourceAsync(deviceHost, CommandName.File, powerRequest, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } /// /// Dwonload from file or directory, by specifying the usb path to file or directory. /// for directory the REST api returns the zip file of the directory. /// /// device ip address /// usb path of the download file or directory like /media/usb0/Logs/2025-07-30_15-44/ServiceLogs.1.log or /media/usb0/Logs/2025-07-30_15-44 /// local destination directory /// timeout for download /// token to cancel the download /// /// error of not valid arguments public async Task Download(string deviceHost, string usbPath, string destinationDirectory, TimeSpan timeOut, CancellationToken cancellationToken) { VerifyUsbPathIsNotNull(usbPath); VerifyDestinationIsNotNull(destinationDirectory); VerifyDestinationExist(destinationDirectory); await DownloadProcess(deviceHost, usbPath, destinationDirectory, timeOut, cancellationToken); } private async Task DownloadProcess(string deviceHost, string usbPath, string destinationDirectory, TimeSpan timeOut, CancellationToken cancellationToken) { var oldTimeout = RESTWrapper.Timeout; try { RESTWrapper.Timeout = timeOut; string filePath = BuildFilePath(usbPath, destinationDirectory); var downloadRequest = new FileRequest { cmd = "download", path = usbPath }; var response = await RESTWrapper.SendResourceReadAsStreamAsync(deviceHost, CommandName.File, downloadRequest, timeOut, cancellationToken); await RESTWrapper.WriteStreamToFileAsync(response, filePath); } finally { RESTWrapper.Timeout = oldTimeout; } } private static void VerifyDestinationExist(string destinationDirectory) { if (!Directory.Exists(destinationDirectory)) { throw new ArgumentException($"directory {destinationDirectory} does not exist", "destinationDirectory"); } } private static void VerifyDestinationIsNotNull(string destinationDirectory) { if (string.IsNullOrEmpty(destinationDirectory)) { throw new ArgumentException("destinationDirectory cannot be null or empty", "destinationDirectory"); } } /// /// upload the specified source file to device /// /// device ip address /// ubpath for upload like /media/usb0/Uploads /// file path that you want to upload to device /// timeout /// token to cancel upload /// /// public async Task Upload(string deviceHost, string uploadUsbPath, string sourcefile, TimeSpan timeOut, CancellationToken cancellationToken) { VerifyUploadUsbPathIsNotEmpty(uploadUsbPath); VerifySourceIsNotEmpty(sourcefile); VerifySourceExist(sourcefile); return await UploadProcess(deviceHost, uploadUsbPath, sourcefile, timeOut, cancellationToken); } private static async Task UploadProcess(string deviceHost, string uploadUsbPath, string sourcefile, TimeSpan timeOut, CancellationToken cancellationToken) { var oldTimeout = RESTWrapper.Timeout; try { RESTWrapper.Timeout = timeOut; MultipartFormDataContent multipart = new MultipartFormDataContent(); HttpContent cmd = new StringContent("upload"); HttpContent path = new StringContent(uploadUsbPath); multipart.Add(cmd, "cmd"); multipart.Add(path, "path"); byte[] data = File.ReadAllBytes(sourcefile); HttpContent fileContent = new StreamContent(new MemoryStream(data)); multipart.Add(fileContent, "file", Path.GetFileName(sourcefile)); var jsonResponse = await RESTWrapper.PostResourceReadAsStringAsync(deviceHost, CommandName.File, multipart, timeOut, cancellationToken); var response = JsonConvert.DeserializeObject(jsonResponse); return response; } finally { RESTWrapper.Timeout = oldTimeout; } } private static void VerifySourceExist(string sourcefile) { if (!File.Exists(sourcefile)) { throw new ArgumentException($"file {sourcefile} does not exist", "sourcefile"); } } private static void VerifySourceIsNotEmpty(string sourcefile) { if (string.IsNullOrEmpty(sourcefile)) { throw new ArgumentException("sourcefile cannot be null or empty", "sourcefile"); } } private static void VerifyUploadUsbPathIsNotEmpty(string uploadUsbPath) { if (string.IsNullOrEmpty(uploadUsbPath)) { throw new ArgumentException("uploadUsbPath cannot be null or empty", "uploadUsbPath"); } } private bool IsDirectory(string fileOrDirectory) { var file = Path.GetExtension(fileOrDirectory); return string.IsNullOrEmpty(file); } private string BuildFilePath(string usbPath, string destinationDirectory) { var pathSegments = usbPath.Split('/').ToList(); string fileName; if (IsDirectory(pathSegments.Last())) { fileName = $"{pathSegments.Last()}.zip"; } else { fileName = pathSegments.Last(); } var filePath = Path.Combine(destinationDirectory, fileName); return filePath; } } }