diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index ac9854a3..5111a13d 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -14,28 +14,28 @@ jobs: steps: - name: Checkout Meadow.Logging - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: WildernessLabs/Meadow.Logging path: Meadow.Logging ref: develop - name: Checkout Meadow.Units - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: WildernessLabs/Meadow.Units path: Meadow.Units ref: develop - name: Checkout Meadow.Contracts - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: WildernessLabs/Meadow.Contracts path: Meadow.Contracts ref: develop - name: Checkout Meadow.CLI - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: Meadow.CLI @@ -45,11 +45,8 @@ jobs: dotnet-version: 8.0.x - - name: Build CLI v1 - run: dotnet build -c Release Meadow.CLI/MeadowCLI.sln - - name: Build CLI v2 - run: dotnet build -c Release Meadow.CLI/Source/v2/Meadow.CLI.v2.sln + run: dotnet build -c Release Meadow.CLI/Source/Meadow.CLI.sln - name: Unit Test CLI v2 run: dotnet test -c Release --no-build --no-restore --filter "FullyQualifiedName~.Unit.Tests" .\Meadow.CLI\Source\v2\Meadow.CLI.v2.sln diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index c5b159a6..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "TestApp", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/TestApp/bin/Debug/net5.0/TestApp.dll", - "args": [], - "cwd": "${workspaceFolder}", - "stopAtEntry": false, - "console": "internalConsole" - }, - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/Meadow.CLI/bin/Debug/meadow", - "args": ["device provision"], - "cwd": "${workspaceFolder}/Meadow.CLI", - "console": "internalConsole", - "stopAtEntry": false - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command:pickProcess}" - } - ] -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 13e267e4..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "command": "dotnet", - "type": "process", - "args": [ - "build", - "${workspaceFolder}/Meadow.CLI/Meadow.CLI.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "${workspaceFolder}/Meadow.CLI/Meadow.CLI.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "watch", - "command": "dotnet", - "type": "process", - "args": [ - "watch", - "run", - "${workspaceFolder}/Meadow.CLI/Meadow.CLI.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/CLICommands.md b/CLICommands.md deleted file mode 100644 index 352a127f..00000000 --- a/CLICommands.md +++ /dev/null @@ -1,135 +0,0 @@ -# MeadowCLI Commands - -## Command Summary - -This section contains an abbreviated list of necessary commands - -Note: All commands require the name of the serial port. Once provided it will be cached by Meadow.CLI. While not shown below, the serial port format is `--SerialPort [NameOfSerialPort]` or `-s [NameOfSerialPort]`. Like all commands the serial port can appear anywhere within the command line. - -`Meadow.CLI --help arg` -`Meadow.CLI --Dfu | -d --OsFile [Meadow.OS.bin]` -`Meadow.CLI --ClearCache` -`Meadow.CLI --ListPorts` -`Meadow.CLI --KeepAlive` or `Meadow.CLI --AnyOtherCmd --KeepAlive` - -`Meadow.CLI --MonoDisable` -`Meadow.CLI --MonoEnable` -`Meadow.CLI --MonoRunState` -`Meadow.CLI --MonoFlash` -`Meadow.CLI --MonoUpdateRt` - -`Meadow.CLI --WriteFile | -w file[,file,...] [targetFileName[,targetFileName,...]]` -`Meadow.CLI --DeleteFile | -d file[,file,...]` -`Meadow.CLI --ListFiles` -`Meadow.CLI --ListFilesAndCrcs` -`Meadow.CLI --RenewFileSys` - -`Meadow.CLI --GetDeviceInfo` -`Meadow.CLI --GetDeviceName` -`Meadow.CLI --ResetMeadow | -r` -`Meadow.CLI --EraseFlash` -`Meadow.CLI --VerifyErasedFlash` - -`Meadow.CLI --Esp32ReadMac` -`Meadow.CLI --Esp32Restart` -`Meadow.CLI --Esp32WriteFile --McuDestAddr [Address] --File [FilePathAndName]` - -`Meadow.CLI --SetTraceLevel | -t --TraceLevel 0, 1, 2, 3` -`Meadow.CLI --TraceEnable` -`Meadow.CLI --TraceDisable` -`Meadow.CLI --Uart1Trace` -`Meadow.CLI --Uart1Apps` - -`Meadow.CLI --StartDebugging` - -## Full Command Listing - -This section contains a detailed list of all commands - -### Meadow.CLI commands - -`Meadow.CLI --help arg` - Outputs a list of all CLI commands, some of which are not be useful. -`Meadow.CLI --ClearCache --SerialPort [NameOfSerialPort]` - Clears the cache holding saved serial port name -`Meadow.CLI --ListPorts --SerialPort [NameOfSerialPort]` - Displays a list of available serial port -`Meadow.CLI --Dfu | -d --OsFile [Meadow.OS.bin] --SerialPort [NameOfSerialPort]` - Adds or Update the Meadow.OS on the Meadow F7 -`EnterDfuMode` - *Not implemented in Meadow.OS* -`UserFile` - *Obsolute* The original `nuttx_user.bin` file, is now named `Meadow.OS.Runtime.bin` and is written to Meadow file system using `WriteFile` and then moved to flash memory using the `MonoFlash` command. -The `KeepAlive` command prevents MeadowCLI from terminating until the 'Enter' or 'return' key is pressed. This command can be use alone or in conjunction with other commands. -`MeadowCLI.exe --KeepAlive --SerialPort [NameOfSerialPort]` -`MeadowCLI.exe --ListFilesAndCrcs --KeepAlive --SerialPort [NameOfSerialPort]` - -### Mono Related Commands - -The Mono runtime can be prevented from running and re-enabled using the following 2 commands. Both commands automatically restart Meadow. -`MeadowCLI.exe --MonoDisable --SerialPort [NameOfSerialPort]` - Disables Mono from running -`MeadowCLI.exe --MonoEnable --SerialPort [NameOfSerialPort]` - Enables Mono to run -`MeadowCLI.exe --MonoRunState --SerialPort [NameOfSerialPort]` - Reports if the Mono runtime will run after Meadow is restarted. -`Meadow.CLI --MonoFlash --SerialPort [NameOfSerialPort] --KeepAlive` - copies the Meadow.OS.Runtime.bin file from the Meadow's file system to flash where is will be executed. Once this command is executed the Meadow.OS.Runtime.bin file can be deleted from the Meadow file system. Suggestion: use with the `--KeepAlive` -`MeadowCLI.exe --MonoUpdateRt --SerialPort [NameOfSerialPort]` - Combines `--WriteFile` with `--MonoFlash` into a single command. - -### Meadow File System - -`MeadowCLI.exe --WriteFile | -w file1[,file2,...] [file1TargetFileName[,file2TargetFileName,...]] --SerialPort [NameOfSerialPort]` - Writes a single file or multiple files to the Meadow file system. To write multiple files to the Meadow file system the files to be written are listed comma seperated. Optional it is possible to define the target file name in a comma seperated list for each file. -`MeadowCLI --DeleteFile | -d file[,file,...] --SerialPort [NameOfSerialPort]` - Deletes one ore multiple files from the Meadow file system. To delete multiple files from the Meadow file system the files to be deleted are listed comma seperated. -`MeadowCLI.exe --ListFiles --SerialPort [NameOfSerialPort]` -Lists all the files in the Meadow file system. -`MeadowCLI.exe --ListFilesAndCrcs --SerialPort [NameOfSerialPort] --KeepAlive` - List all the files in the Meadow file system and includes each files CRC checksum and size. This command can take several seconds for each file. Suggestion: use with the `--KeepAlive` -`MeadowCLI.exe --RenewFileSys --SerialPort [NameOfSerialPort]` - Quickly recreate the Meadow file system. - -## Utility Commands - -`MeadowCLI.exe --GetDeviceInfo --SerialPort [NameOfSerialPort]` - Outputs Meadow OS version and other device information. -`MeadowCLI.exe --GetDeviceName --SerialPort [NameOfSerialPort]` - Reads the device name from an internal configuration file. -`MeadowCLI.exe --ResetMeadow --SerialPort [NameOfSerialPort]` - Restarts the Meadow.OS -`MeadowCLI.exe --EraseFlash --SerialPort [NameOfSerialPort] --KeepAlive` - Completely erase the Meadow external 32 MB flash.This includes the Meadow file system. Suggestion: use with the `--KeepAlive` since command takes signficant time to execute. -`Meadow.CLI --VerifyErasedFlash --SerialPort [NameOfSerialPort] --KeepAlive` - Verifies that the Meadow's 32 MB flash has been completely erased. An erased flash's memory is one where all memory locations are set to 0xff. Suggestion: use with the `--KeepAlive` since command takes signficant time to execute. - -## ESP32 Commands - -`Meadow.CLI --Esp32ReadMac --SerialPort [NameOfSerialPort]` - Reads the MAC Address of the ESP32 co-processor. -`Meadow.CLI --Esp32Restart --SerialPort [NameOfSerialPort]` - Restarts the Esp32. The Esp32Restart command is required to restart the ESP32. memory. Restarting Meadow, even with the RST button, will not restart the ESP32. This command must be used after a file has been written to the ESP32's flash for the ESP32 to utilized the file. -`Meadow.CLI --Esp32WriteFile --SerialPort [NameOfSerialPort] --McuDestAddr [DestAddress] --File [NameOfFile]` - Moves a file from the host PC/Mac into the ESP32's initernal memory. -Multiple files can be combined in a CSV format as shown below. -Example: -`Meadow.CLI --Esp32WriteFile --SerialPort [NameOfSerialPort] --File "0x8000, C:\WildernessLabs\ESP32Files\partition-table.bin, 0x1000, C:\WildernessLabs\ESP32Files\bootloader.bin, 0x10000, C:\WildernessLabs\ESP32Files\blink.bin"` -Note: There is no ESP32 file `delete` command because files in the ESP32 do not have names. - -## Diagnostic - -You can set the debug trace level to values 0, 1, 2, or 3. The default is 0 which show only significant information and 3 provides a lot of information, trace level 2 is generally the most useful. -`MeadowCLI.exe --SetTraceLevel --TraceLevel | -t 0, 1, 2, 3 --SerialPort [NameOfSerialPort]` -`Meadow.CLI --TraceEnable` - Routes Meadow OS trace information to Meadow.CLI (default) -`Meadow.CLI --TraceDisable` - Stop routing Meadow OS trace information to Meadow.CLI -`Meadow.CLI --Uart1Trace` - Routes Meadow OS trace information to COM1 (UART1) Tx=D12, RX=D13 -`Meadow.CLI --Uart1Apps` - Frees COM1 for Meadow application use (default) -`Meadow.CLI --StartDebugging --VSDebugPort 4024` - Starts the remote debugging servers in Meadow.CLI and in Meadow.OS, allowing Visual Studio remote debugging of the .Net code running in Meadow. This command will also restart Meadow. -Note: port 4024 is the default port for Visual Studio 2019 - -## Persisted Commands - -The following commands are maintained by Meadow when the Meadow is restarted. However, no command is persisted if the Meadow is power cycled. After a power cycle the following default values will apply. -`SetTraceLevel` - Default is a Trace Level of 0. -`MonoEnable & MonoDisable` - Default is mono enable. -`TraceEnable & TraceDisable` - Enables / disables trace to Meadow.CLI - Default is not to send trace to MeadowCLI. -`Uart1Trace & Uart1App` - Switches the function of Uart1 to/from the application from/to debugging. - Default is Uart1 available for application. -`StartDebugging` - Default is remote debugging disabled. - -## Extraneous Commands - -Used only for Meadow.OS development and may not be implemented or work as expected in release versions of Meadow.OS. -`Meadow.CLI --NshEnable --SerialPort Com26` -`Meadow.CLI --SetDeveloper1-4 --DeveloperValue 1-65535` -`Meadow.CLI --QspiWrite --SerialPort Com26 --DeveloperValue 65534` -`Meadow.CLI --QspiRead --SerialPort Com26 --DeveloperValue 65534` -`Meadow.CLI --QspiInit --SerialPort Com26 --DeveloperValue 65534` - -The following are not longer supported. -`Meadow.CLI --PartitionFileSystem` -`Meadow.CLI --MountFileSystem` -`Meadow.CLI --InitializeFileSystem` -`Meadow.CLI --CreateFileSystem` -`Meadow.CLI --FormatFileSystem` -`Meadow.CLI --Partition` -`Meadow.CLI --NumberOfPartitions` - -The following have not been implemented -`Meadow.CLI --EnterDfuMode` diff --git a/Meadow.CLI.Core/CloudServices/CloudServiceBase.cs b/Meadow.CLI.Core/CloudServices/CloudServiceBase.cs deleted file mode 100644 index 195ebc45..00000000 --- a/Meadow.CLI.Core/CloudServices/CloudServiceBase.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.CloudServices -{ - public abstract class CloudServiceBase - { - readonly IdentityManager _identityManager; - - protected CloudServiceBase(IdentityManager identityManager) - { - _identityManager = identityManager; - } - - protected async Task GetAuthenticatedHttpClient(CancellationToken cancellationToken = default) - { - var authToken = await _identityManager.GetAccessToken(cancellationToken); - if (string.IsNullOrEmpty(authToken)) - { - throw new MeadowCloudAuthException(); - } - - HttpClient client = new(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken); - - return client; - } - } -} diff --git a/Meadow.CLI.Core/CloudServices/CollectionService.cs b/Meadow.CLI.Core/CloudServices/CollectionService.cs deleted file mode 100644 index b9e42de1..00000000 --- a/Meadow.CLI.Core/CloudServices/CollectionService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Meadow.CLI.Core.CloudServices.Messages; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.CloudServices; - -public class CollectionService : CloudServiceBase -{ - readonly IConfiguration _config; - - public CollectionService(IConfiguration config, IdentityManager identityManager) : base(identityManager) - { - _config = config; - } - - public async Task> GetOrgCollections(string orgId, string host, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var result = await httpClient.GetStringAsync($"{host}/api/orgs/{orgId}/collections"); - return JsonSerializer.Deserialize>(result) ?? new List(); - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/CloudServices/CommandService.cs b/Meadow.CLI.Core/CloudServices/CommandService.cs deleted file mode 100644 index dc306b95..00000000 --- a/Meadow.CLI.Core/CloudServices/CommandService.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.CloudServices -{ - public class CommandService : CloudServiceBase - { - readonly IConfiguration _config; - readonly IdentityManager _identityManager; - - public CommandService(IConfiguration config, IdentityManager identityManager) : base(identityManager) - { - _config = config; - _identityManager = identityManager; - } - - public async Task PublishCommandForCollection( - string collectionId, - string commandName, - JsonDocument? arguments = null, - int qualityOfService = 0, - string? host = null, - CancellationToken cancellationToken = default) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var payload = new - { - commandName, - args = arguments, - qos = qualityOfService - }; - var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); - var response = await httpClient.PostAsync($"{host}/api/collections/{collectionId}/commands", content, cancellationToken); - - if (!response.IsSuccessStatusCode) - { - var message = await response.Content.ReadAsStringAsync(); - throw new MeadowCloudException(message); - } - } - - public async Task PublishCommandForDevices( - string[] deviceIds, - string commandName, - JsonDocument? arguments = null, - int qualityOfService = 0, - string? host = null, - CancellationToken cancellationToken = default) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var payload = new - { - deviceIds, - commandName, - args = arguments, - qos = qualityOfService - }; - var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); - var response = await httpClient.PostAsync($"{host}/api/devices/commands", content, cancellationToken); - - if (!response.IsSuccessStatusCode) - { - var message = await response.Content.ReadAsStringAsync(); - throw new MeadowCloudException(message); - } - } - } -} diff --git a/Meadow.CLI.Core/CloudServices/DeviceService.cs b/Meadow.CLI.Core/CloudServices/DeviceService.cs deleted file mode 100644 index 982df002..00000000 --- a/Meadow.CLI.Core/CloudServices/DeviceService.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.CloudServices -{ - public class DeviceService : CloudServiceBase - { - readonly IConfiguration _config; - - public DeviceService(IConfiguration config, IdentityManager identityManager) : base(identityManager) - { - _config = config; - } - - public async Task<(bool isSuccess, string message)> AddDevice(string orgId, string id, string publicKey, string collectionId, string name, string host, CancellationToken cancellationToken = default) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - dynamic payload = new - { - orgId, - id, - publicKey, - collectionId, - name - }; - - var json = JsonSerializer.Serialize(payload); - - var content = new StringContent(json, Encoding.UTF8, "application/json"); - - var response = await httpClient.PostAsync($"{host}/api/devices", content, cancellationToken); - - if (response.IsSuccessStatusCode) - { - return (response.IsSuccessStatusCode, string.Empty); - } - else - { - var message = await response.Content.ReadAsStringAsync(); - return (false, message); - } - } - } -} diff --git a/Meadow.CLI.Core/CloudServices/Messages/Collection.cs b/Meadow.CLI.Core/CloudServices/Messages/Collection.cs deleted file mode 100644 index a204e812..00000000 --- a/Meadow.CLI.Core/CloudServices/Messages/Collection.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core.CloudServices.Messages; - -public class Collection -{ - [JsonPropertyName("id")] - public string Id { get; set; } = default!; - [JsonPropertyName("orgId")] - public string OrgId { get; set; } = default!; - [JsonPropertyName("name")] - public string Name { get; set; } = default!; - [JsonPropertyName("lastPublishedPackageId")] - public string LastPublishedPackageId { get; set; } = default!; - [JsonPropertyName("lastPublishedDate")] - public DateTime? LastPublishedDate { get; set; } = default!; -} \ No newline at end of file diff --git a/Meadow.CLI.Core/CloudServices/Messages/Package.cs b/Meadow.CLI.Core/CloudServices/Messages/Package.cs deleted file mode 100644 index 1078cb29..00000000 --- a/Meadow.CLI.Core/CloudServices/Messages/Package.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core.CloudServices.Messages -{ - public class Package - { - [JsonPropertyName("id")] - public string Id { get; set; } = default!; - [JsonPropertyName("orgId")] - public string OrgId { get; set; } = default!; - [JsonPropertyName("publishedDate")] - public DateTime? PublishedDate { get; set; } = default!; - [JsonPropertyName("name")] - public string Name { get; set; } = default!; - [JsonPropertyName("description")] - public string Description { get; set; } = default!; - } -} diff --git a/Meadow.CLI.Core/CloudServices/Messages/User.cs b/Meadow.CLI.Core/CloudServices/Messages/User.cs deleted file mode 100644 index 3db2aedf..00000000 --- a/Meadow.CLI.Core/CloudServices/Messages/User.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Meadow.CLI.Core.CloudServices.Messages; - -public class User -{ - public string Id { get; set; } - public string Email { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public string FullName { get; set; } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/CloudServices/Messages/UserOrg.cs b/Meadow.CLI.Core/CloudServices/Messages/UserOrg.cs deleted file mode 100644 index 191fa6cb..00000000 --- a/Meadow.CLI.Core/CloudServices/Messages/UserOrg.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core.CloudServices.Messages -{ - public class UserOrg - { - [JsonPropertyName("id")] - public string Id { get; set; } - [JsonPropertyName("name")] - public object Name { get; set; } - [JsonPropertyName("defaultCollectionId")] - public string DefaultCollectionId { get; set; } - } - -} diff --git a/Meadow.CLI.Core/CloudServices/PackageService.cs b/Meadow.CLI.Core/CloudServices/PackageService.cs deleted file mode 100644 index 7536df42..00000000 --- a/Meadow.CLI.Core/CloudServices/PackageService.cs +++ /dev/null @@ -1,144 +0,0 @@ -using Meadow.CLI.Core.CloudServices.Messages; -using Meadow.CLI.Core.DeviceManagement.Tools; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.CloudServices -{ - public class PackageService : CloudServiceBase - { - readonly IConfiguration _config; - private string _info_json = "info.json"; - - public PackageService(IConfiguration config, IdentityManager identityManager) : base(identityManager) - { - _config = config; - } - - public async Task UploadPackage(string mpakPath, string orgId, string description, string host, - CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - if (!File.Exists(mpakPath)) - { - throw new ArgumentException($"Invalid path: {mpakPath}"); - } - - var fi = new FileInfo(mpakPath); - - var osVersion = GetPackageOsVersion(fi.FullName); - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - using var multipartFormContent = new MultipartFormDataContent(); - - var fileStreamContent = new StreamContent(File.OpenRead(mpakPath)); - fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); - - var crcFileHash = await CrcTools.CalculateCrc32FileHash(mpakPath); - - dynamic payload = new - { - orgId, - description = description ?? "", - crc = crcFileHash ?? "", - fileSize = fi.Length, - osVersion - }; - var json = JsonSerializer.Serialize(payload); - - multipartFormContent.Add(fileStreamContent, name: "file", fileName: fi.Name); - multipartFormContent.Add(new StringContent(json), "json"); - - var response = await httpClient.PostAsync($"{host}/api/packages", multipartFormContent); - if (response.IsSuccessStatusCode) - { - var package = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync()); - return package!; - } - else - { - var message = await response.Content.ReadAsStringAsync(); - throw new MeadowCloudException($"{response.StatusCode} {message}"); - } - } - - private string GetPackageOsVersion(string packagePath) - { - var result = string.Empty; - - var tempFolder = System.IO.Path.GetTempPath(); - var tempInfoJson = Path.Combine(tempFolder, $"{Guid.NewGuid().ToString("N")}.zip"); - - using ZipArchive zip = ZipFile.Open(packagePath, ZipArchiveMode.Read); - foreach (ZipArchiveEntry entry in zip.Entries) - { - if (entry.Name == _info_json) - { - entry.ExtractToFile(tempInfoJson); - } - } - - if (File.Exists(tempInfoJson)) - { - var content = File.ReadAllText(tempInfoJson); - var packageInfo = JsonSerializer.Deserialize(content); - result = packageInfo.OsVersion; - File.Delete(tempInfoJson); - } - - return result; - } - - public async Task PublishPackage(string packageId, string collectionId, string metadata, string host, - CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var payload = new { metadata, collectionId }; - var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); - var response = - await httpClient.PostAsync($"{host}/api/packages/{packageId}/publish", content, cancellationToken); - - if (!response.IsSuccessStatusCode) - { - var message = await response.Content.ReadAsStringAsync(); - throw new MeadowCloudException(message); - } - } - - public async Task> GetOrgPackages(string orgId, string host, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var result = await httpClient.GetStringAsync($"{host}/api/orgs/{orgId}/packages"); - - return JsonSerializer.Deserialize>(result) ?? new List(); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/CloudServices/UserService.cs b/Meadow.CLI.Core/CloudServices/UserService.cs deleted file mode 100644 index 967d799e..00000000 --- a/Meadow.CLI.Core/CloudServices/UserService.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Meadow.CLI.Core.CloudServices.Messages; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.CloudServices -{ - public class UserService : CloudServiceBase - { - readonly IConfiguration _config; - - public UserService(IConfiguration config, IdentityManager identityManager) : base(identityManager) - { - _config = config; - } - - public async Task> GetUserOrgs(string host, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var response = await httpClient.GetAsync($"{host}/api/users/me/orgs", cancellationToken); - - if (response.IsSuccessStatusCode) - { - var message = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize>(message) ?? new List(); - } - else - { - return new List(); - } - } - - public async Task GetMe(string host, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var httpClient = await GetAuthenticatedHttpClient(cancellationToken); - - var response = await httpClient.GetAsync($"{host}/api/users/me"); - - if (response.IsSuccessStatusCode) - { - var message = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(message, new JsonSerializerOptions() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - PropertyNameCaseInsensitive = true - }); - } - else - { - return null; - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Common/DownloadFileStream.cs b/Meadow.CLI.Core/Common/DownloadFileStream.cs deleted file mode 100644 index 71ed17f5..00000000 --- a/Meadow.CLI.Core/Common/DownloadFileStream.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.IO; - -namespace Meadow.CLI.Core.Common -{ - public class DownloadFileStream : Stream, IDisposable - { - private readonly ILogger _logger; - private readonly Stream _stream; - - private long _position; - private DateTimeOffset _lastLog; - private long _lastPosition; - - public DownloadFileStream(Stream stream, ILogger logger) - { - _stream = stream; - _logger = logger; - _lastLog = DateTimeOffset.Now; - } - - public override bool CanRead => _stream.CanRead; - public override bool CanSeek => false; - public override bool CanWrite => false; - public override long Length => _stream.Length; - public override long Position { get => _position; set => throw new NotImplementedException(); } - - public override void Flush() - { - throw new NotImplementedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - var b = _stream.Read(buffer, offset, count); - _position += b; - var now = DateTimeOffset.Now; - if (_lastLog.AddSeconds(5) < now) - { - LogPosition(); - _lastLog = now; - } - return b; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - _stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - - protected override void Dispose(bool disposing) - { - LogPosition(); - base.Dispose(disposing); - } - - private void LogPosition() - { - if (_position == _lastPosition) - { - return; - } - - if (_position < 1024) - { - _logger.LogInformation("Downloaded {position} bytes", _position); - _lastPosition = _position; - } - else if (_position < (1024 * 1024)) - { - _logger.LogInformation("Downloaded {position} KiB", Math.Round(_position / 1024M, 2, MidpointRounding.ToEven)); - _lastPosition = _position; - } - else - { - _logger.LogInformation("Downloaded {position} MiB", Math.Round(_position / 1024M / 1024M, 2, MidpointRounding.ToEven)); - _lastPosition = _position; - } - } - } -} diff --git a/Meadow.CLI.Core/Connections/IMeadowConnection.cs b/Meadow.CLI.Core/Connections/IMeadowConnection.cs deleted file mode 100644 index 2261941d..00000000 --- a/Meadow.CLI.Core/Connections/IMeadowConnection.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Meadow.CLI.Core.Devices; -using System; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core -{ - public delegate void ConnectionStateHandler(IMeadowConnection connection, bool newState); - public delegate void ConnectionPresenseHander(IMeadowConnection connection); - - public interface IMeadowConnection - { - public event ConnectionStateHandler ConnectionStateChanged; - - public string Name { get; } - public IMeadowDevice? Device { get; } - public bool IsConnected { get; } - public bool AutoReconnect { get; set; } - bool MonitorState { get; set; } - - Task WaitForConnection(TimeSpan timeout); - public void Connect(); - public void Disconnect(); - } -} diff --git a/Meadow.CLI.Core/Connections/MeadowConnection.cs b/Meadow.CLI.Core/Connections/MeadowConnection.cs deleted file mode 100644 index 34656f16..00000000 --- a/Meadow.CLI.Core/Connections/MeadowConnection.cs +++ /dev/null @@ -1,156 +0,0 @@ -using Meadow.CLI.Core.Devices; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Ports; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core -{ - public class MeadowSerialConnection : IMeadowConnection - { - public event ConnectionStateHandler ConnectionStateChanged = delegate { }; - - private const int DefaultBaudRate = 115200; - private const int DefaultTimeout = 5000; - private const int CommsTimeoutSeconds = 2; - - private readonly SerialPort _port; - private Task _connectionTask; - - public IMeadowDevice? Device { get; private set; } - public string Name { get; } - public ILogger? Logger { get; } - - public bool IsConnected => _port?.IsOpen ?? false; - public bool AutoReconnect { get; set; } = false; - public bool MonitorState { get; set; } = true; - - internal MeadowSerialConnection(string portName, ILogger? logger) - { - Logger = logger; - Name = portName; - _port = new SerialPort(Name, DefaultBaudRate, Parity.None, 8, StopBits.One); - _port.ReadTimeout = DefaultTimeout; - _port.WriteTimeout = DefaultTimeout; - - _connectionTask = Task.Factory.StartNew(ConnectionStateMonitorProc, TaskCreationOptions.LongRunning); - } - - public Task WaitForConnection(TimeSpan timeout) - { - var keepTrying = true; - - var tasks = new List(); - - if (timeout.TotalMilliseconds > 0) - { - tasks.Add(Task.Delay(timeout)); - } - - tasks.Add(Task.Run(async () => - { - while (keepTrying) - { - try - { - Connect(); - } - catch - { - } - if (IsConnected) return; - await Task.Delay(500); - } - })); - - Task.WaitAny(tasks.ToArray()); - - keepTrying = false; - - return Task.FromResult(IsConnected); - } - - public void Connect() - { - if (_port.IsOpen) - { - return; - } - - try - { - _port.Open(); - Device = new MeadowSerialDevice(Name, _port, Logger); - } - catch (FileNotFoundException fnf) - { - Logger?.LogTrace($"Unable to open serial port: {fnf.Message}"); - throw; - } - catch (Exception ex) - { - Logger?.LogTrace($"Unable to open serial port: {ex.Message}"); - throw; - } - } - - public void Disconnect() - { - if (!_port.IsOpen) - { - return; - } - - _port.Close(); - - Device = null; - } - - private async Task ConnectionStateMonitorProc() - { - var lastState = _port.IsOpen; - - while (true) - { - try - { - var nowState = _port.IsOpen; - if (lastState != nowState) - { - lastState = nowState; - - if (nowState && Device != null) - { - // wait a bit - the serial port can connect before the Meadow is ready - if (MonitorState) - { - await Task.Delay(1000); - _ = await Device.GetDeviceInfo(TimeSpan.FromSeconds(2)); - } - } - - ConnectionStateChanged.Invoke(this, nowState); - } - - if (!IsConnected && AutoReconnect) - { - Connect(); - } - } - catch (TimeoutException) - { - // this is a fallback - lastState = false; - } - catch (Exception ex) - { - lastState = false; - } - - await Task.Delay(1000); - } - } - - } -} diff --git a/Meadow.CLI.Core/Connections/MeadowConnectionManager.cs b/Meadow.CLI.Core/Connections/MeadowConnectionManager.cs deleted file mode 100644 index 2ad99add..00000000 --- a/Meadow.CLI.Core/Connections/MeadowConnectionManager.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core -{ - public class MeadowConnectionManager : IEnumerable - { - public event ConnectionPresenseHander ConnectionAdded = delegate { }; - public event ConnectionPresenseHander ConnectionRemoved = delegate { }; - - private Dictionary _connections = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - - public ILogger? Logger { get; } - - public MeadowConnectionManager(ILogger? logger) - { - Logger = logger; - Task.Run(ConnectionAvailabilityMonitorProc); - } - - public IMeadowConnection? this[string name] - { - get => _connections.ContainsKey(name) ? _connections[name] : null; - } - - public IMeadowConnection AddConnection(string serialPort) - { - if (_connections.ContainsKey(serialPort)) - { - return _connections[serialPort]; - } - - var connection = new MeadowSerialConnection(serialPort, Logger); - _connections.Add(serialPort, connection); - return connection; - } - - private async Task ConnectionAvailabilityMonitorProc() - { - while (true) - { - var allPorts = await MeadowDeviceManager.GetSerialPorts(); - - var added = allPorts.Except(_connections.Keys); - var removed = _connections.Keys.Except(allPorts); - - foreach (var a in added) - { - var connection = AddConnection(a); - ConnectionAdded?.Invoke(connection); - } - - foreach (var c in removed) - { - // should we remove this? when disconnected and reconnected, it shouldn't go away? Maybe after some time period? - // ConnectionRemoved?.Invoke(_connections[c]); - // _connections.Remove(c); - } - - await Task.Delay(1000); - } - } - - public IEnumerator GetEnumerator() - { - return _connections.Values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/Meadow.CLI.Core/Constants.cs b/Meadow.CLI.Core/Constants.cs deleted file mode 100644 index 2181cc76..00000000 --- a/Meadow.CLI.Core/Constants.cs +++ /dev/null @@ -1,16 +0,0 @@ - -[assembly: System.Reflection.AssemblyFileVersion(Meadow.CLI.Core.Constants.CLI_VERSION)] -[assembly: System.Reflection.AssemblyVersion(Meadow.CLI.Core.Constants.CLI_VERSION)] -[assembly: System.Reflection.AssemblyInformationalVersion(Meadow.CLI.Core.Constants.CLI_VERSION)] - -namespace Meadow.CLI.Core -{ - public static class Constants - { - public const string CLI_VERSION = "1.9.4.0"; - public const ushort HCOM_PROTOCOL_PREVIOUS_VERSION_NUMBER = 0x0007; - public const ushort HCOM_PROTOCOL_CURRENT_VERSION_NUMBER = 0x0008; // Used for transmission - public const string WILDERNESS_LABS_USB_VID = "2E6A"; - public const string MEADOW_CLOUD_HOST_CONFIG_NAME = "meadowCloudHost"; - } -} diff --git a/Meadow.CLI.Core/DeviceManagement/AssemblyManager.cs b/Meadow.CLI.Core/DeviceManagement/AssemblyManager.cs deleted file mode 100644 index 917cb577..00000000 --- a/Meadow.CLI.Core/DeviceManagement/AssemblyManager.cs +++ /dev/null @@ -1,213 +0,0 @@ -using Mono.Cecil; -using Mono.Collections.Generic; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.DeviceManagement -{ - //https://github.com/xamarin/xamarin-macios/blob/main/tools/mtouch/Assembly.mtouch.cs#L54 - - public static class AssemblyManager - { - private static readonly List dependencyMap = new(); - - private static string? meadowAssembliesPath = null; - - private const string IL_LINKER_DIR = "lib"; - - public static async Task?> TrimDependencies(string file, string path, List dependencies, IList? noLink, ILogger? logger, bool includePdbs, bool verbose = false, string? linkerOptions = null) - { - var prelink_dir = Path.Combine(path, "prelink_bin"); - var prelink_app = Path.Combine(prelink_dir, file); - var prelink_os = Path.Combine(prelink_dir, "Meadow.dll"); - - if (Directory.Exists(prelink_dir)) - { - Directory.Delete(prelink_dir, recursive: true); - } - - Directory.CreateDirectory(prelink_dir); - File.Copy(Path.Combine(path, file), prelink_app, overwrite: true); - - foreach (var dependency in dependencies) - { - File.Copy(dependency, - Path.Combine(prelink_dir, Path.GetFileName(Path.GetFileName(dependency))), - overwrite: true); - - if (includePdbs) - { - var pdbFile = Path.ChangeExtension(dependency, "pdb"); - if (File.Exists(pdbFile)) - { - File.Copy(pdbFile, - Path.Combine(prelink_dir, Path.GetFileName(pdbFile)), - overwrite: true); - } - } - } - - var postlink_dir = Path.Combine(path, "postlink_bin"); - if (Directory.Exists(postlink_dir)) - { - Directory.Delete(postlink_dir, recursive: true); - } - Directory.CreateDirectory(postlink_dir); - - var base_path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var illinker_path = Path.Combine(base_path, IL_LINKER_DIR, "illink.dll"); - var descriptor_path = Path.Combine(base_path, IL_LINKER_DIR, "meadow_link.xml"); - - if (linkerOptions != null) - { - var fi = new FileInfo(linkerOptions); - - if (fi.Exists) - { - logger?.LogInformation($"Using linker options from '{linkerOptions}'"); - } - else - { - logger?.LogWarning($"Linker options file '{linkerOptions}' not found"); - } - } - - // add in any run-time no-link arguments - var no_link_args = string.Empty; - if (noLink != null) - { - no_link_args = string.Join(" ", noLink.Select(o => $"-p copy \"{o}\"")); - logger?.LogInformation($"no-link args: '{no_link_args}'"); - } - - var monolinker_args = $"\"{illinker_path}\" -x \"{descriptor_path}\" {no_link_args} --skip-unresolved --deterministic --keep-facades true --ignore-descriptors true -b true -c link -o \"{postlink_dir}\" -r \"{prelink_app}\" -a \"{prelink_os}\" -d \"{prelink_dir}\""; - - Console.WriteLine("Trimming assemblies to reduce size (may take several seconds)..."); - - using (var process = new Process()) - { - process.StartInfo.FileName = "dotnet"; - process.StartInfo.Arguments = monolinker_args; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardError = true; - process.StartInfo.RedirectStandardOutput = true; - process.Start(); - - // To avoid deadlocks, read the output stream first and then wait - string stdOutReaderResult; - using (StreamReader stdOutReader = process.StandardOutput) - { - stdOutReaderResult = await stdOutReader.ReadToEndAsync(); - if (verbose) - { - Console.WriteLine("StandardOutput Contains: " + stdOutReaderResult); - } - - } - - string stdErrorReaderResult; - using (StreamReader stdErrorReader = process.StandardError) - { - stdErrorReaderResult = await stdErrorReader.ReadToEndAsync(); - if (!string.IsNullOrEmpty(stdErrorReaderResult)) - { - Console.WriteLine("StandardError Contains: " + stdErrorReaderResult); - } - } - - process.WaitForExit(60000); - if (process.ExitCode != 0) - { -#if DEBUG - Console.WriteLine($"Trimming failed - ILLinker execution error!\nProcess Info: {process.StartInfo.FileName} {process.StartInfo.Arguments} \nExit Code: {process.ExitCode}"); -#else - Console.WriteLine($"Trimming failed - ILLinker execution error!\nExit Code: {process.ExitCode}"); -#endif - return null; - } - } - - Console.WriteLine("Trimming complete"); - - return Directory.EnumerateFiles(postlink_dir); - } - - public static List GetDependencies(string file, string path, string osVersion) - { - meadowAssembliesPath = Path.Combine(DownloadManager.FirmwareDownloadsFilePathRoot, osVersion, "meadow_assemblies"); - - if (!Directory.Exists(meadowAssembliesPath)) - { //try crawling back to the last minor version ... ToDo osVersion should be a proper object - var lastMinorVersion = osVersion.Substring(0, osVersion.LastIndexOf('.')) + ".0"; - meadowAssembliesPath = Path.Combine(DownloadManager.FirmwareDownloadsFilePathRoot, lastMinorVersion, "meadow_assemblies"); - } - - if (!Directory.Exists(meadowAssembliesPath)) - { - throw new FileNotFoundException($"Unable to locate local Meadow assemblies for v{osVersion}. Run `meadow download os` to download the latest meadow OS and libraries."); - } - - dependencyMap.Clear(); - - var refs = GetAssemblyNameReferences(file, path); - - var dependencies = GetDependencies(refs, dependencyMap, path); - - return dependencies; - } - - private static (Collection?, string?) GetAssemblyNameReferences(string fileName, string path) - { - static string? ResolvePath(string fileName, string path) - { - string attempted_path = Path.Combine(path, fileName); - if (Path.GetExtension(fileName) != ".exe" && - Path.GetExtension(fileName) != ".dll") - { - attempted_path += ".dll"; - } - return File.Exists(attempted_path) ? attempted_path : null; - } - - //ToDo - is it ever correct to fall back to the root path without a version? - string? resolved_path = ResolvePath(fileName, meadowAssembliesPath) ?? ResolvePath(fileName, path); - - if (resolved_path is null) - return (null, null); - - Collection references; - - using (var definition = AssemblyDefinition.ReadAssembly(resolved_path)) - { - references = definition.MainModule.AssemblyReferences; - } - return (references, resolved_path); - } - - private static List GetDependencies((Collection?, string?) references, List dependencyMap, string folderPath) - { - if (dependencyMap.Contains(references.Item2)) - return dependencyMap; - - dependencyMap.Add(references.Item2); - - foreach (var ar in references.Item1) - { - var namedRefs = GetAssemblyNameReferences(ar.Name, folderPath); - - if (namedRefs.Item1 == null) - continue; - - GetDependencies(namedRefs, dependencyMap, folderPath); - } - - return dependencyMap; - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/DeviceManagement/DeviceInfoException.cs b/Meadow.CLI.Core/DeviceManagement/DeviceInfoException.cs deleted file mode 100644 index c26651bd..00000000 --- a/Meadow.CLI.Core/DeviceManagement/DeviceInfoException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Meadow.CLI.Core.DeviceManagement -{ - // TODO: Inherit from MeadowDeviceException - public class DeviceInfoException : Exception - { - public DeviceInfoException(Exception? innerException = null) : base("An exception occurred while retrieving the device info", innerException) - {} - } -} diff --git a/Meadow.CLI.Core/DeviceManagement/FileTransferResult.cs b/Meadow.CLI.Core/DeviceManagement/FileTransferResult.cs deleted file mode 100644 index d52165ec..00000000 --- a/Meadow.CLI.Core/DeviceManagement/FileTransferResult.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.DeviceManagement -{ - public class FileTransferResult - { - public FileTransferResult(long transferTime, long fileSize, uint checksum) - { - TransferTime = transferTime; - FileSize = fileSize; - Checksum = $"{checksum:x08}"; - } - /// - /// Gets the number of milliseconds it took to transfer the file to the device - /// - public long TransferTime {get;} - - /// - /// Get the number of bytes written - /// - public long FileSize {get;} - - /// - /// Get the CRC Checksum of the file - /// - public string Checksum {get;} - - public static FileTransferResult EmptyResult = new FileTransferResult(0, 0, 0); - } -} diff --git a/Meadow.CLI.Core/DeviceManagement/MeadowDataProcessor.cs b/Meadow.CLI.Core/DeviceManagement/MeadowDataProcessor.cs deleted file mode 100644 index 77253f8b..00000000 --- a/Meadow.CLI.Core/DeviceManagement/MeadowDataProcessor.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Concurrent; -using Meadow.CLI.Core.Internals.MeadowCommunication; - -namespace Meadow.CLI.Core.DeviceManagement -{ - public abstract class MeadowDataProcessor : IDisposable - { - public EventHandler? OnReceiveData; - public BlockingCollection DebuggerMessages = new BlockingCollection(); - public abstract void Dispose(); - } - - public class MeadowMessageEventArgs : EventArgs - { - public string Message { get; private set; } - public MeadowMessageType MessageType { get; private set; } - - public MeadowMessageEventArgs(MeadowMessageType messageType, string message = "") - { - Message = message; - MessageType = messageType; - } - } -} diff --git a/Meadow.CLI.Core/DeviceManagement/MeadowDeviceInfo.cs b/Meadow.CLI.Core/DeviceManagement/MeadowDeviceInfo.cs deleted file mode 100644 index 5ed7fee7..00000000 --- a/Meadow.CLI.Core/DeviceManagement/MeadowDeviceInfo.cs +++ /dev/null @@ -1,434 +0,0 @@ -using System; -using System.Collections.Generic; -using Meadow.CLI.Core.Internals.MeadowCommunication; - -namespace Meadow.CLI.Core.DeviceManagement -{ - public class MeadowDeviceInfo - { - /// - /// Name of the product (i.e. Meadow) key. - /// - private const string KN_PRODUCT = "product"; - - /// - /// Name of the model (e.g. F7V2) key. - /// - private const string KN_MODEL = "model"; - - /// - /// Name of the OS (Nuttx) version key. - /// - private const string KN_OS_VERSION = "osversion"; - - /// - /// Name of the processor type key. - /// - private const string KN_PROCESSOR_TYPE = "processortype"; - - /// - /// Name of the coprocessor type key. - /// - private const string KN_COPROCESSOR_TYPE = "coprocessortype"; - - /// - /// Name of the coprocessor version key. - /// - private const string KN_COPROCESSOR_VERSION = "coprocessorversion"; - - /// - /// Name of the runtime version key. - /// - private const string KN_RT_VERSION = "monoversion"; - - /// - /// Name of the processor ID key. - /// - private const string KN_PROCESSOR_ID = "processorid"; - - /// - /// Name of the hardware versiuon key. - /// - private const string KN_HARDWARE_VERSION = "hardware"; - - /// - /// Name of the device name key. - /// - private const string KN_DEVICE_NAME = "devicename"; - - /// - /// Name of the chip serial number key. - /// - private const string KN_SERIAL_NUMBER = "serialno"; - - /// - /// Name of the WiFi MAC address key. - /// - private const string KN_WIFI_MAC = "wifimac"; - - /// - /// Name of the soft access point MAC key - /// - private const string KN_SOFT_AP_MAC = "softapmac"; - - /// - /// String representation of an unknown MAC address. - /// - private const string UNKNOWN_MAC_ADDRESS = "00:00:00:00:00:00"; - - /// - /// Create a new device information object from the string returned from the board. - /// - /// - /// The device information is returned as a single string of key / value pairs. The pairs will be delimetered - /// by the ~ character. The key and value will be seperated by the | character. - /// - /// Full device information string returned from the board. - public MeadowDeviceInfo(string deviceInfoString) - { - _elements = new Dictionary(); - if (deviceInfoString.Contains("~")) - { - // - // Parse the post 0.6 device information string. - // - string[] elements = deviceInfoString.Split('~'); - - foreach (string element in elements) - { - if (element.Length > 0) - { - string[] keyValue = element.Split('|'); - if ((keyValue.Length == 2) && (keyValue[0].Length > 0) && (keyValue[1].Length > 0)) - { - _elements.Add(keyValue[0].ToLower(), keyValue[1]); - } - } - } - } - else - { - // - // Parse the pre OS version 0.6 device information string. - // - _elements.Add(KN_PRODUCT, deviceInfoString.Substring(0, deviceInfoString.IndexOf(' ')).Replace(" by Wilderness Labs", "")); - _elements.Add(KN_MODEL, ParseValue("Model: ", deviceInfoString)); - _elements.Add(KN_OS_VERSION, ParseValue("MeadowOS Version: ", deviceInfoString)); - _elements.Add(KN_PROCESSOR_TYPE, ParseValue("Processor: ", deviceInfoString)); - _elements.Add(KN_PROCESSOR_ID, ParseValue("Processor Id: ", deviceInfoString)); - _elements.Add(KN_SERIAL_NUMBER, ParseValue("Serial Number: ", deviceInfoString)); - _elements.Add(KN_COPROCESSOR_TYPE, ParseValue("CoProcessor: ", deviceInfoString)); - _elements.Add(KN_COPROCESSOR_VERSION, ParseValue("CoProcessor OS Version: ", deviceInfoString)); - _elements.Add(KN_HARDWARE_VERSION, ParseValue("H/W Version: ", deviceInfoString)); - _elements.Add(KN_DEVICE_NAME, ParseValue("Device Name: ", deviceInfoString)); - _elements.Add(KN_RT_VERSION, ParseValue("Runtime Version: ", deviceInfoString)); - } - } - - /// - /// Dictionary of the device information values from the Meadow board. - /// - private Dictionary _elements; - - /// - /// Product description. - /// - public string Product { get { return (_elements[KN_PRODUCT]); } } - - /// - /// Model of the board. - /// - public string Model { get { return (_elements[KN_MODEL]); } } - - /// - /// OS version and build date. - /// - public string MeadowOsVersion - { - get - { - try - { - if (_elements.ContainsKey(KN_OS_VERSION)) - { - var idx = _elements[KN_OS_VERSION].IndexOf('('); - - if (idx == -1) - { - // starting with 0.9.1 (??) there is no date info - return _elements[KN_OS_VERSION]; - } - - if (_elements[KN_OS_VERSION].Substring(idx + 1).StartsWith("0x")) - { - // version 0.9.x+ - // "0.9.0.2 built 22 Oct 2022 07:49:53 UTC (0xaef26433/)" - idx = _elements[KN_OS_VERSION].IndexOf("built"); - return _elements[KN_OS_VERSION].Substring(0, idx - 1); - } - - // version 0.6.x - return _elements[KN_OS_VERSION].Substring(0, idx - 1); - } - else - { - return "Unknown"; - } - } - catch - { - return "Unknown"; - } - } - } - - public string MeadowOsBuildDate - { - get - { - try - { - if (_elements.ContainsKey(KN_OS_VERSION)) - { - var idx = _elements[KN_OS_VERSION].IndexOf('('); - - if (idx >= 0) - { - if (_elements[KN_OS_VERSION].Substring(idx + 1).StartsWith("0x")) - { - // version 0.9.x+ - // "0.9.0.2 built 22 Oct 2022 07:49:53 UTC (0xaef26433/)" - var idx2 = _elements[KN_OS_VERSION].IndexOf("built"); - return _elements[KN_OS_VERSION].Substring(idx + 6, idx - idx2); - } - - // version 0.6.x - return _elements[KN_OS_VERSION].Substring(idx + 1, _elements[KN_OS_VERSION].Length - idx - 2); - } - } - - return "Unknown"; - } - catch - { - return "Unknown"; - } - } - } - - /// - /// Type of processor on the board. - /// - public string ProcessorType { get { return (_elements[KN_PROCESSOR_TYPE]); } } - - /// - /// Type of coprocessor on the board. - /// - public string CoProcessorType { get { return (_elements[KN_COPROCESSOR_TYPE]); } } - - /// - /// Coprocessor firmware version. - /// - public string CoProcessorOsVersion { get { return ValueOrDefault(KN_COPROCESSOR_VERSION, "Not available"); } } - - /// - /// Version of runtime deployed on the board. - /// - public string RuntimeVersion - { - get - { - try - { - if (_elements.ContainsKey(KN_RT_VERSION)) - { - var idx = _elements[KN_RT_VERSION].IndexOf('('); - - if (idx == -1) - { - // starting with 0.9.1 (??) there is no date info - return _elements[KN_RT_VERSION]; - } - - if (_elements[KN_RT_VERSION].Substring(idx + 1).StartsWith("0x")) - { - // version 0.9.x+ - // "0.9.0.2, built 22 Oct 2022 07:49:53 UTC (0xaef26433/)" - idx = _elements[KN_RT_VERSION].IndexOf("built"); - return _elements[KN_RT_VERSION].Substring(0, idx - 2); - } - - // version 0.6.x - return _elements[KN_RT_VERSION].Substring(0, idx - 1); - } - else - { - return "Unknown"; - } - } - catch - { - return "Unknown"; - } - } - } - - /// - /// ID of the STM32 processor. - /// - public string ProcessorId { get { return ValueOrDefault(KN_PROCESSOR_ID, string.Empty); } } - - /// - /// Hardware version. - /// - public string HardwareVersion { get { return ValueOrDefault(KN_HARDWARE_VERSION, string.Empty); } } - - /// - /// Name of the device from the config file (or the default value when no config file is on the board). - /// - public string DeviceName { get { return ValueOrDefault(KN_DEVICE_NAME, string.Empty); } } - - /// - /// STM32 serial number. - /// - public string SerialNumber { get { return ValueOrDefault(KN_SERIAL_NUMBER, string.Empty); } } - - /// - /// MAC address of the coprocessor. - /// - public string WiFiMacAddress { get { return ValueOrDefault(KN_WIFI_MAC, string.Empty); } } - - /// - /// MAC address of the coprocessor when it is used as an access point. - /// - public string SoftApMacAddress { get { return ValueOrDefault(KN_SOFT_AP_MAC, string.Empty); } } - - /// - /// Look up the specified key in the dictionary of values returned by the hardware. - /// - /// Key to look up. - /// Default value to be used if the key is not present. - /// Value if the key is found, the default value if the key is not present. - private string ValueOrDefault(string key, string defaultValue) - { - string result; - if (_elements.ContainsKey(key)) - { - result = _elements[key]; - } - else - { - result = defaultValue; - } - return result; - } - - /// - /// Create part of the device information string depending upon the presence (or not) of one - /// of the device information components. - /// - /// Name (description) that will appear in the device information output. - /// Value to to added (this may be an empty string). - /// String (possibly empty) to be added to the device information output. - private string AddOptionalValue(string name, string value) - { - string result = string.Empty; - - if (!string.IsNullOrEmpty(value)) - { - result = $"{name} {value}"; - } - return (result); - } - - /// - /// Generate a meaningful description of the hardware. - /// - /// - /// Format of the message: - /// - /// Meadow by Wilderness Labs - /// Board Information - Model: F7Micro, Hardware version: F7v2, Device name: MeadowF7V2 - /// Hardware Information - Processor type: STM32F777IIK6, ID: 32-00-1d-00-11-51-36-30-33-33-37-33, Serial number: 3354336F3036, Coprocessor type: ESP32 - /// Firmware Versions - OS: 0.5.3.0 (Oct 30 2021 10:21:54) Mono: 0.5.3.0, Coprocessor: 0.5.3.0 - /// MAC Address(es) - WiFi: 94:B9:7E:91:0F:78 - /// - /// - /// Meaningful description of the hardware. - public override string ToString() - { - string deviceInfo; - - if (Product.Contains(" by Wilderness Labs")) - { - deviceInfo = $"{Product}{Environment.NewLine}"; - } - else - { - deviceInfo = $"{Product} by Wilderness Labs{Environment.NewLine}"; - } - - deviceInfo += $"Board Information {Environment.NewLine}"; - deviceInfo += $" Model: {Model}{Environment.NewLine}"; - deviceInfo += AddOptionalValue(" Hardware version:", HardwareVersion) + Environment.NewLine; - deviceInfo += AddOptionalValue(" Device name:", DeviceName) + Environment.NewLine; - deviceInfo += Environment.NewLine; - deviceInfo += $"Hardware Information {Environment.NewLine}"; - deviceInfo += $" Processor type: {ProcessorType}{Environment.NewLine}"; - deviceInfo += AddOptionalValue(" ID:", ProcessorId) + Environment.NewLine; - deviceInfo += AddOptionalValue(" Serial number:", SerialNumber) + Environment.NewLine; - deviceInfo += $" Coprocessor type: {CoProcessorType}{Environment.NewLine}"; - - string macAddresses = string.Empty; - int macCount = 0; - if (!string.IsNullOrEmpty (WiFiMacAddress) && WiFiMacAddress != UNKNOWN_MAC_ADDRESS) { - macCount++; - macAddresses += $" WiFi: {WiFiMacAddress}{Environment.NewLine}"; - } - if (!string.IsNullOrEmpty (SoftApMacAddress) && SoftApMacAddress != UNKNOWN_MAC_ADDRESS) { - macCount++; - macAddresses += $" AP: {SoftApMacAddress}{Environment.NewLine}"; - } - if (macCount > 0) { - if (macCount > 1) { - deviceInfo += " MAC Addresses - " + Environment.NewLine; - } - else { - deviceInfo += " MAC Address - " + Environment.NewLine; - } - deviceInfo += $"{macAddresses}" + Environment.NewLine; - } - - deviceInfo += Environment.NewLine; - deviceInfo += $"Firmware Versions {Environment.NewLine}"; - deviceInfo += $" OS: {MeadowOsVersion}{Environment.NewLine}"; - deviceInfo += $" Mono: {RuntimeVersion}{Environment.NewLine}"; - deviceInfo += $" Coprocessor: {CoProcessorOsVersion}{Environment.NewLine}"; - deviceInfo += $" Protocol: {Command.HcomProtocolCommunicationVersion}{Environment.NewLine}"; - - return (deviceInfo); - } - - /// - /// Parse the device information string for a key and extract the value. - /// - /// Key to be searched for. - /// Device information string. - /// Value associated with the key. - private string ParseValue(string key, string source) - { - string result = string.Empty; - var start = source.IndexOf(key, StringComparison.Ordinal) + key.Length; - if (start >= 0) - { - var end = source.IndexOf(',', start); - if (end < 0) - { - end = source.Length; - } - result = source.Substring(start, end - start); - } - return (result); - } - } -} diff --git a/Meadow.CLI.Core/DeviceManagement/MeadowDeviceManager.cs b/Meadow.CLI.Core/DeviceManagement/MeadowDeviceManager.cs deleted file mode 100644 index e94f4c67..00000000 --- a/Meadow.CLI.Core/DeviceManagement/MeadowDeviceManager.cs +++ /dev/null @@ -1,387 +0,0 @@ -using Meadow.CLI.Core.Devices; -using Meadow.CLI.Core.Exceptions; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Ports; -using System.Linq; -using System.Management; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.DeviceManagement -{ - public class MeadowDeviceManager - { - internal const int PreviousMaxAllowableMsgPacketLength = 512; - static internal int MaxAllowableMsgPacketLength = 8192; - - static internal int MaxEstimatedSizeOfEncodedPayload = MaxAllowableMsgPacketLength + (MaxAllowableMsgPacketLength / 254) + 8; - - internal const int ProtocolHeaderSize = 12; - - static internal int MaxAllowableMsgPayloadLength = MaxAllowableMsgPacketLength - ProtocolHeaderSize; - - public const string NoDevicesFound = "No Devices Found"; - - static object lockObject = new object(); - static IMeadowDevice? meadow = null; - - // Avoid changing signature - public static async Task GetMeadowForSerialPort(string serialPort, bool verbose = true, ILogger? logger = null) - { - logger ??= NullLogger.Instance; - - try - { - if (meadow != null) - { - meadow.Dispose(); - meadow = null; - } - - await Task.Delay(1000); - - logger.LogInformation($"{Environment.NewLine}Connecting to Meadow on {serialPort}{Environment.NewLine}"); - - var createTask = Task.Run(() => meadow = new MeadowSerialDevice(serialPort, logger)); - var completedTask = await Task.WhenAny(createTask, Task.Delay(1000)); - - if (completedTask != createTask || meadow == null) - { - logger.LogTrace("Timeout while creating Meadow"); - try - { - await createTask; - } - catch (Exception ex) - { - logger.LogInformation(ex, "An error occurred while attempting to create Meadow"); - throw; - } - return null; - } - - await meadow.Initialize(CancellationToken.None); - - return meadow; - } - catch (FileNotFoundException fnfEx) - { - - LogUserError(verbose, logger); - - logger.LogDebug(fnfEx, "Failed to open Serial Port."); - return null; - } - catch (IOException ioEx) - { - LogUserError(verbose, logger); - - logger.LogDebug(ioEx, "Failed to open Serial Port."); - return null; - } - catch (UnauthorizedAccessException unAuthEx) when ( - unAuthEx.InnerException is IOException) - { - LogUserError(verbose, logger); - - logger.LogDebug(unAuthEx, "Failed to open Serial Port."); - return null; - } - catch (Exception ex) - { - // TODO: Remove exception catch here and let the caller handle it or wrap it up in our own exception type. - logger.LogError(ex, "Failed to connect to Meadow on {serialPort}", serialPort); - throw; - } - } - - private static void LogUserError(bool verbose, ILogger logger) - { - if (verbose) - { - // TODO: Move message to ResourceManager or other tool for localization - logger.LogError( - "Failed to open Serial Port. Please ensure you have exclusive access to the serial port and the specified port exists."); - } - } - - public async static Task> GetSerialPorts() - { - try - { - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return await GetMeadowSerialPortsForLinux(); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return await GetMeadowSerialPortsForOsx(); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - lock (lockObject) - { - return GetMeadowSerialPortsForWindows(); - } - } - else - { - throw new Exception("Unknown operating system."); - } - } - catch (Exception ex) - { - throw new DeviceNotFoundException($"Error Finding Meadow Devices on available Serial Ports: {ex.Message}"); - } - } - - public static async Task FindMeadowBySerialNumber( - string serialNumber, - ILogger logger, - int maxAttempts = 10, - CancellationToken cancellationToken = default) - { - var attempts = 0; - while (attempts < maxAttempts) - { - - var ports = await GetSerialPorts(); - foreach (var port in ports) - { - try - { - var device = await GetMeadowForSerialPort(port, false, logger); - - if (device == null) - continue; - - var deviceInfo = await device.GetDeviceInfo( - TimeSpan.FromSeconds(60), - cancellationToken); - - if (deviceInfo!.SerialNumber == serialNumber) - { - return device; - } - - device.Dispose(); - } - catch (UnauthorizedAccessException unauthorizedAccessException) - { - if (unauthorizedAccessException.InnerException is IOException) - { - // Eat it and retry - logger.LogDebug( - unauthorizedAccessException, - "This error can be safely ignored."); - } - else - { - logger.LogError( - unauthorizedAccessException, - "An unknown error has occurred while finding meadow"); - - throw; - } - } - catch (IOException ioException) - { - // Eat it and retry - logger.LogDebug( - ioException, - "This error can be safely ignored."); - } - catch (MeadowDeviceException meadowDeviceException) - { - // eat it for now - logger.LogDebug( - meadowDeviceException, - "This error can be safely ignored."); - } - } - - await Task.Delay(1000, cancellationToken); - - attempts++; - } - - throw new DeviceNotFoundException( - $"Could not find a connected Meadow with the serial number {serialNumber}"); - } - - public async static Task> GetMeadowSerialPortsForOsx(ILogger? logger = null) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) == false) - throw new PlatformNotSupportedException("This method is only supported on macOS"); - - return await Task.Run(() => - { - logger ??= NullLogger.Instance; - logger.LogDebug("Get Meadow Serial ports"); - var ports = new List(); - - var psi = new ProcessStartInfo - { - FileName = "/usr/sbin/ioreg", - UseShellExecute = false, - RedirectStandardOutput = true, - Arguments = "-r -c IOUSBHostDevice -l" - }; - - string output = string.Empty; - - using (var p = Process.Start(psi)) - { - if (p != null) - { - output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(); - } - } - - //split into lines - var lines = output.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - - var foundMeadow = false; - foreach (var line in lines) - { - if (line.Contains("Meadow F7 Micro")) - { - foundMeadow = true; - } - else if (line.IndexOf("+-o", StringComparison.Ordinal) == 0) - { - foundMeadow = false; - } - - //now find the IODialinDevice entry which contains the serial port name - if (foundMeadow && line.Contains("IODialinDevice")) - { - int startIndex = line.IndexOf("/"); - int endIndex = line.IndexOf("\"", startIndex + 1); - var port = line.Substring(startIndex, endIndex - startIndex); - logger.LogDebug($"Found Meadow at {port}", port); - - ports.Add(port); - foundMeadow = false; - } - } - logger.LogDebug("Found {count} ports", ports.Count); - - return ports; - }); - } - - public async static Task> GetMeadowSerialPortsForLinux(ILogger? logger = null) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) == false) - throw new PlatformNotSupportedException("This method is only supported on Linux"); - - return await Task.Run(() => - { - const string devicePath = "/dev/serial/by-id"; - logger ??= NullLogger.Instance; - var psi = new ProcessStartInfo() - { - FileName = "ls", - Arguments = $"-l {devicePath}", - UseShellExecute = false, - RedirectStandardOutput = true - }; - - using var proc = Process.Start(psi); - _ = proc?.WaitForExit(1000); - var output = proc?.StandardOutput.ReadToEnd(); - - return output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) - .Where(x => x.Contains("Wilderness_Labs")) - .Select( - line => - { - var parts = line.Split(new[] { "-> " }, StringSplitOptions.RemoveEmptyEntries); - var target = parts[1]; - var port = Path.GetFullPath(Path.Combine(devicePath, target)); - return port; - }).ToArray(); - }); - } - - public static IList GetMeadowSerialPortsForWindows(ILogger? logger = null) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false) - throw new PlatformNotSupportedException("This method is only supported on Windows"); - - logger ??= NullLogger.Instance; - - try - { - const string WildernessLabsPnpDeviceIDPrefix = @"USB\VID_" + Constants.WILDERNESS_LABS_USB_VID; - - // Win32_PnPEntity lives in root\CIMV2 - const string wmiScope = "root\\CIMV2"; - - // escape special characters in the device id prefix - string escapedPrefix = WildernessLabsPnpDeviceIDPrefix.Replace("\\", "\\\\").Replace("_", "[_]"); - - // our query for all ports that have a PnP device id starting with Wilderness Labs' USB VID. - string query = @$"SELECT Name, Caption, PNPDeviceID FROM Win32_PnPEntity WHERE PNPClass = 'Ports' AND PNPDeviceID like '{escapedPrefix}%'"; - - logger.LogDebug("Running WMI Query: {query}", query); - - List results = new(); - - // build the searcher for the query - using ManagementObjectSearcher searcher = new(wmiScope, query); - - // get the query results - foreach (ManagementObject moResult in searcher.Get()) - { - // Try Caption and if not Name, they both seems to contain the COM port - string portLongName = moResult["Caption"].ToString(); - if (string.IsNullOrEmpty(portLongName)) - portLongName = moResult["Name"].ToString(); - string pnpDeviceId = moResult["PNPDeviceID"].ToString(); - - // we could collect and return a fair bit of other info from the query: - - //string description = moResult["Description"].ToString(); - //string service = moResult["Service"].ToString(); - //string manufacturer = moResult["Manufacturer"].ToString(); - - var comIndex = portLongName.IndexOf("(COM") + 1; - var copyLength = portLongName.IndexOf(")") - comIndex; - var port = portLongName.Substring(comIndex, copyLength); - - // the meadow serial is in the device id, after - // the characters: USB\VID_XXXX&PID_XXXX\ - // so we'll just split is on \ and grab the 3rd element as the format is standard, but the length may vary. - var splits = pnpDeviceId.Split('\\'); - var serialNumber = splits[2]; - - logger.LogDebug($"Found Wilderness Labs device at `{port}` with serial `{serialNumber}`"); - results.Add($"{port}"); // removed serial number for consistency and will break fallback ({serialNumber})"); - } - - return results.ToArray(); - } - catch (Exception aex) - { - // eat it for now - logger.LogDebug(aex, "This error can be safely ignored."); - - // Since WMI Failed fall back to using SerialPort - var ports = SerialPort.GetPortNames(); - - //hack to skip COM1 - ports = ports.Where((source, index) => source != "COM1").Distinct().ToArray(); - - return ports; - } - } - } -} diff --git a/Meadow.CLI.Core/DeviceManagement/MeadowDeviceManagerException.cs b/Meadow.CLI.Core/DeviceManagement/MeadowDeviceManagerException.cs deleted file mode 100644 index d98ec734..00000000 --- a/Meadow.CLI.Core/DeviceManagement/MeadowDeviceManagerException.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Meadow.Hcom; -using System; - -namespace Meadow.CLI.Core.DeviceManagement -{ - public class MeadowDeviceManagerException : Exception - { - public MeadowDeviceManagerException(HcomMeadowRequestType hcomMeadowRequestType, Exception? innerException) : base(null, innerException) - { - HcomMeadowRequestType = hcomMeadowRequestType; - } - - public HcomMeadowRequestType HcomMeadowRequestType { get; set; } - - public override string ToString() - { - return $"A {GetType()} exception has occurred while making a {nameof(HcomMeadowRequestType)} of {HcomMeadowRequestType}."; - } - } -} diff --git a/Meadow.CLI.Core/Devices/FileData.cs b/Meadow.CLI.Core/Devices/FileData.cs deleted file mode 100644 index e1d8af52..00000000 --- a/Meadow.CLI.Core/Devices/FileData.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.IO; - -namespace Meadow.CLI.Core.Devices -{ - public record FileData - { - public string FullPath { get; private set; } = string.Empty; - public string FileName => Path.GetFileName(FullPath); - public uint Crc { get; private set; } - public int FileSize { get; private set; } - - public static bool TryParse(string info, out FileData data) - { - try - { - // example data: - // /meadow0/App.pdb [0x0c74a77c] 12 KB (9908 bytes) - var crcStart = info.IndexOf('[') + 1; - var crcLength = 10; // always 10, formatted hex - var sizeStart = info.IndexOf('(') + 1; - var sizeLength = info.IndexOf("bytes") - sizeStart; - - data = new FileData - { - FullPath = info.Substring(0, crcStart - 2).Trim(), - Crc = Convert.ToUInt32(info.Substring(crcStart, crcLength), 16), - FileSize = int.Parse(info.Substring(sizeStart, sizeLength)) - }; - return true; - } - catch - { - data = new FileData(); - return false; - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Devices/IMeadowDevice.cs b/Meadow.CLI.Core/Devices/IMeadowDevice.cs deleted file mode 100644 index ff72f5b3..00000000 --- a/Meadow.CLI.Core/Devices/IMeadowDevice.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Devices -{ - public interface IMeadowDevice : IDisposable - { - public ILogger Logger { get; } - public MeadowDataProcessor DataProcessor { get; } - public MeadowDeviceInfo? DeviceInfo { get; } - - public IList FilesOnDevice { get; } - public Task> GetFilesAndFolders(TimeSpan timeout, CancellationToken cancellationToken = default); - public Task> GetFilesAndCrcs(TimeSpan timeout, int partition = 0, CancellationToken cancellationToken = default); - public Task WriteFile(string filename, string path, TimeSpan timeout, CancellationToken cancellationToken = default); - public Task DeleteFile(string fileName, uint partition = 0, CancellationToken cancellationToken = default); - public Task EraseFlash(CancellationToken cancellationToken = default); - public Task VerifyErasedFlash(CancellationToken cancellationToken = default); - public Task FormatFileSystem(uint partition = 0, CancellationToken cancellationToken = default); - public Task RenewFileSystem(CancellationToken cancellationToken = default); - public Task UpdateMonoRuntime(string? fileName, uint partition = 0, CancellationToken cancellationToken = default); - public Task UpdateMonoRuntime(string? fileName, string? osVersion, uint partition = 0, CancellationToken cancellationToken = default); - public Task WriteFileToEspFlash(string? fileName, uint partition = 0, string? mcuDestAddress = null, CancellationToken cancellationToken = default); - - public Task FlashEsp(string? sourcePath, string? osVersion = null, CancellationToken cancellationToken = default); - - public Task GetDeviceInfo(TimeSpan timeout, CancellationToken cancellationToken = default); - public Task GetDeviceName(TimeSpan timeout, CancellationToken cancellationToken = default); - public Task GetMonoRunState(CancellationToken cancellationToken = default); - public Task MonoDisable(CancellationToken cancellationToken = default); - public Task MonoEnable(CancellationToken cancellationToken = default); - public Task ResetMeadow(CancellationToken cancellationToken = default); - public Task MonoFlash(CancellationToken cancellationToken = default); - public Task EnterDfuMode(CancellationToken cancellationToken = default); - public Task NshEnable(CancellationToken cancellationToken = default); - public Task NshDisable(CancellationToken cancellationToken = default); - public Task TraceEnable(CancellationToken cancellationToken = default); - public Task SetTraceLevel(uint traceLevel, CancellationToken cancellationToken = default); - public Task SetDeveloper(ushort level, uint userData, CancellationToken cancellationToken = default); - public Task Uart1Apps(CancellationToken cancellationToken = default); - public Task Uart1Trace(CancellationToken cancellationToken = default); - public Task TraceDisable(CancellationToken cancellationToken = default); - public Task QspiWrite(int value, CancellationToken cancellationToken = default); - public Task QspiRead(int value, CancellationToken cancellationToken = default); - public Task QspiInit(int value, CancellationToken cancellationToken = default); - public Task DeployApp(string applicationFilePath, string osVersion, bool includePdbs = false, bool verbose = false, IList? linkOptions = null, CancellationToken cancellationToken = default); - public Task ForwardVisualStudioDataToMono(byte[] debuggerData, uint userData, CancellationToken cancellationToken = default); - public Task StartDebugging(int port, CancellationToken cancellationToken); - public Task GetInitialBytesFromFile(string fileName, uint partition = 0, CancellationToken cancellationToken = default); - public Task RestartEsp32(CancellationToken cancellationToken = default); - public Task GetDeviceMacAddress(CancellationToken cancellationToken = default); - public Task Initialize(CancellationToken cancellationToken); - public bool IsDeviceInitialized(); - public Task IsFileOnDevice(string filename, CancellationToken cancellationToken = default); - - public Task GetRtcTime(CancellationToken cancellationToken = default); - public Task SetRtcTime(DateTimeOffset dateTime, CancellationToken cancellationToken = default); - - public Task CloudRegisterDevice(CancellationToken cancellationToken = default); - } -} diff --git a/Meadow.CLI.Core/Devices/MeadowDeviceEntity.cs b/Meadow.CLI.Core/Devices/MeadowDeviceEntity.cs deleted file mode 100644 index b91dd2ab..00000000 --- a/Meadow.CLI.Core/Devices/MeadowDeviceEntity.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Meadow.CLI.Core.Devices -{ - public class MeadowDeviceEntity - { - public MeadowDeviceEntity(string port, string? serialNumber) - { - if (string.IsNullOrWhiteSpace(port)) - throw new ArgumentNullException(nameof(port)); - if (string.IsNullOrWhiteSpace(serialNumber)) - throw new ArgumentNullException(nameof(serialNumber)); - Port = port; - SerialNumber = serialNumber; - } - - public string Port { get;set;} - public string? SerialNumber { get;set;} - - public override string ToString() - { - return $"Port: {Port}, SerialNumber: {SerialNumber}"; - } - } -} diff --git a/Meadow.CLI.Core/Devices/MeadowDeviceHelper.cs b/Meadow.CLI.Core/Devices/MeadowDeviceHelper.cs deleted file mode 100644 index cfda7164..00000000 --- a/Meadow.CLI.Core/Devices/MeadowDeviceHelper.cs +++ /dev/null @@ -1,485 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Devices -{ - //a simple model object that represents a meadow device including connection - public sealed class MeadowDeviceHelper : IDisposable - { - private IMeadowDevice _meadowDevice; - public TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60); - public readonly ILogger Logger; - public IMeadowDevice MeadowDevice => _meadowDevice; - - public MeadowDeviceHelper(IMeadowDevice meadow, ILogger logger) - { - _meadowDevice = meadow; - DeviceInfo = meadow.DeviceInfo ?? throw new ArgumentException( - "Device is not initialized, missing DeviceInfo", - nameof(meadow)); - Logger = logger; - } - - public MeadowDeviceInfo DeviceInfo { get; private set; } - - public Task> GetFilesAndCrcs(TimeSpan timeout, int partition = 0, CancellationToken cancellationToken = default) - { - return _meadowDevice.GetFilesAndCrcs(timeout, partition, cancellationToken); - } - - public Task> GetFilesAndFolders(TimeSpan timeout, CancellationToken cancellationToken = default) - { - return _meadowDevice.GetFilesAndFolders(timeout, cancellationToken); - } - - public Task WriteFile(string sourceFileName, string destinationFileName, TimeSpan timeout, CancellationToken cancellationToken = default) - { - return _meadowDevice.WriteFile(sourceFileName, destinationFileName, timeout, cancellationToken); - } - - public Task DeleteFile(string fileName, - uint partition = 0, - CancellationToken cancellationToken = default) - { - return _meadowDevice.DeleteFile(fileName, partition, cancellationToken); - } - - public Task EraseFlash(CancellationToken cancellationToken = default) - { - return _meadowDevice.EraseFlash(cancellationToken); - } - - public Task VerifyErasedFlash(CancellationToken cancellationToken = default) - { - return _meadowDevice.VerifyErasedFlash(cancellationToken); - } - - public Task FormatFileSystem(uint partition = 0, CancellationToken cancellationToken = default) - { - return _meadowDevice.FormatFileSystem(partition, cancellationToken); - } - - public Task RenewFileSystem(CancellationToken cancellationToken = default) - { - return _meadowDevice.RenewFileSystem(cancellationToken); - } - - public async Task UpdateMonoRuntime(string? fileName = null, string? osVersion = null, uint partition = 0, CancellationToken cancellationToken = default) - { - Logger.LogInformation("Starting Mono Runtime Update"); - Logger.LogDebug("Calling Mono Disable"); - await MonoDisable(cancellationToken: cancellationToken); - - await ReInitializeMeadow(cancellationToken); - - Trace.Assert(await GetMonoRunState(cancellationToken) == false, - "Meadow was expected to have Mono Disabled"); - - Logger.LogInformation("Updating Mono Runtime"); - - await _meadowDevice.UpdateMonoRuntime(fileName, osVersion, partition, cancellationToken); - } - - public Task WriteFileToEspFlash(string fileName, uint partition = 0, string? mcuDestAddress = null, CancellationToken cancellationToken = default) - { - return _meadowDevice.WriteFileToEspFlash( - fileName, - partition, - mcuDestAddress, - cancellationToken); - } - - public Task FlashEsp(string? sourcePath = null, string? osVersion = null, CancellationToken cancellationToken = default) - { - return _meadowDevice.FlashEsp(sourcePath, osVersion, cancellationToken); - } - - //Get's the OS version as a string, used by the download manager - public async Task GetOSVersion(TimeSpan timeout, CancellationToken cancellationToken = default) - { - var deviceInfo = await GetDeviceInfo(timeout, cancellationToken); - return deviceInfo.MeadowOsVersion.Split(' ')[0]; // we want the first part of e.g. '0.5.3.0 (Oct 13 2021 13:39:12)' - } - - public Task GetDeviceInfo(TimeSpan timeout, CancellationToken cancellationToken = default) - { - return _meadowDevice.GetDeviceInfo(timeout, cancellationToken); - } - - public Task GetDeviceName(TimeSpan timeout, CancellationToken cancellationToken = default) - { - return _meadowDevice.GetDeviceName(timeout, cancellationToken); - } - - public Task GetMonoRunState(CancellationToken cancellationToken = default) - { - return _meadowDevice.GetMonoRunState(cancellationToken); - } - - public async Task MonoDisable(bool force = false, CancellationToken cancellationToken = default) - { - var endTime = DateTime.UtcNow.Add(TimeSpan.FromSeconds(60)); - bool monoRunState = await GetMonoRunState(cancellationToken); - while ((monoRunState == true || force) - && endTime > DateTime.UtcNow) - { - Logger.LogDebug("Sending Mono Disable Request (Forced? {forced})", force); - await _meadowDevice.MonoDisable(cancellationToken); - - Logger.LogDebug("Waiting for Meadow to restart"); - await Task.Delay(3000, cancellationToken); - - Logger.LogDebug("Reinitialize the device"); - await ReInitializeMeadow(cancellationToken); - force = false; - - Logger.LogDebug("Check Mono state"); - monoRunState = await GetMonoRunState(cancellationToken); - } - - if (monoRunState) - { - throw new Exception("Failed to stop mono."); - } - } - - public async Task MonoEnable(bool force = false, CancellationToken cancellationToken = default) - { - var endTime = DateTime.UtcNow.Add(TimeSpan.FromSeconds(60)); - bool monoRunState = await GetMonoRunState(cancellationToken); - while ((monoRunState == false || force) - && endTime > DateTime.UtcNow) - { - Logger.LogDebug("Sending Mono Enable Request (Forced? {forced})", force); - await _meadowDevice.MonoEnable(cancellationToken); - - Logger.LogDebug("Waiting for Meadow to restart"); - await Task.Delay(1000, cancellationToken); - - Logger.LogDebug("Reinitialize the device"); - await ReInitializeMeadow(cancellationToken); - force = false; - - Logger.LogDebug("Check Mono state"); - monoRunState = await GetMonoRunState(cancellationToken); - } - - if (!monoRunState) - throw new Exception("Failed to enable mono."); - } - - public async Task ResetMeadow(CancellationToken cancellationToken = default) - { - await _meadowDevice.ResetMeadow(cancellationToken); - await Task.Delay(1000, cancellationToken); - await ReInitializeMeadow(cancellationToken); - } - - public Task MonoFlash(CancellationToken cancellationToken = default) - { - return _meadowDevice.MonoFlash(cancellationToken); - } - - public Task NshEnable(CancellationToken cancellationToken = default) - { - return _meadowDevice.NshEnable(cancellationToken); - } - - public Task NshDisable(CancellationToken cancellationToken = default) - { - return _meadowDevice.NshDisable(cancellationToken); - } - - public Task TraceEnable(CancellationToken cancellationToken = default) - { - return _meadowDevice.TraceEnable(cancellationToken); - } - - public Task SetTraceLevel(uint traceLevel, CancellationToken cancellationToken = default) - { - return _meadowDevice.SetTraceLevel(traceLevel, cancellationToken); - } - - public Task TraceDisable(CancellationToken cancellationToken = default) - { - return _meadowDevice.TraceDisable(cancellationToken); - } - - public Task SetDeveloper(ushort level, uint userData, CancellationToken cancellationToken = default) - { - return _meadowDevice.SetDeveloper(level, userData, cancellationToken); - } - - public Task Uart1Apps(CancellationToken cancellationToken = default) - { - return _meadowDevice.Uart1Apps(cancellationToken); - } - - public Task Uart1Trace(CancellationToken cancellationToken = default) - { - return _meadowDevice.Uart1Trace(cancellationToken); - } - - public Task QspiWrite(int value, CancellationToken cancellationToken = default) - { - return _meadowDevice.QspiWrite(value, cancellationToken); - } - - public Task QspiRead(int value, CancellationToken cancellationToken = default) - { - return _meadowDevice.QspiRead(value, cancellationToken); - } - - public Task QspiInit(int value, CancellationToken cancellationToken = default) - { - return _meadowDevice.QspiInit(value, cancellationToken); - } - - public async Task DeployApp(string fileName, bool includePdbs = false, CancellationToken cancellationToken = default, bool verbose = false, IList? noLink = null) - { - try - { - await MonoDisable(cancellationToken: cancellationToken); - - string osVersion = await GetOSVersion(TimeSpan.FromSeconds(30), cancellationToken); - - await _meadowDevice.DeployApp(fileName, osVersion, includePdbs, verbose, noLink, cancellationToken); - - await MonoEnable(true, cancellationToken: cancellationToken); - - await Task.Delay(2000, cancellationToken); - } - catch (Exception ex) - { - await MonoDisable(true, cancellationToken); - throw ex; - } - } - - public Task ForwardVisualStudioDataToMono(byte[] debuggerData, uint userData, CancellationToken cancellationToken = default) - { - return _meadowDevice.ForwardVisualStudioDataToMono( - debuggerData, - userData, - cancellationToken); - } - - /// - /// Start a session to debug an application on the Meadow - /// - /// The port to use for the debugging proxy - /// A for cancelling the operation - /// A running that is available for connections - public async Task StartDebuggingSession(int port, CancellationToken cancellationToken) - { - Logger.LogDebug($"StartDebugging on port: {port}"); - await _meadowDevice.StartDebugging(port, cancellationToken); - - //Logger.LogDebug("Waiting for Meadow to restart"); - //await Task.Delay(1000, cancellationToken); - - Logger.LogDebug("Reinitialize the device"); - await ReInitializeMeadow(cancellationToken); - - if (_meadowDevice == null) - throw new DeviceNotFoundException(); - - var endpoint = new IPEndPoint(IPAddress.Loopback, port); - var debuggingServer = new DebuggingServer(_meadowDevice, endpoint, Logger); - - Logger.LogDebug("Tell the Debugging Server to Start Listening"); - await debuggingServer.StartListening(cancellationToken); - return debuggingServer; - } - - public Task GetInitialBytesFromFile(string fileName, uint partition = 0, CancellationToken cancellationToken = default) - { - return _meadowDevice.GetInitialBytesFromFile(fileName, partition, cancellationToken); - } - - public Task RestartEsp32(CancellationToken cancellationToken = default) - { - return _meadowDevice.RestartEsp32(cancellationToken); - } - - public Task GetDeviceMacAddress(CancellationToken cancellationToken = default) - { - return _meadowDevice.GetDeviceMacAddress(cancellationToken); - } - - public bool IsDeviceInitialized() - { - return _meadowDevice.IsDeviceInitialized(); - } - - public async Task ReInitializeMeadow(CancellationToken cancellationToken = default) - { - var serialNumber = DeviceInfo.SerialNumber; - string? serialPort = null; - IMeadowDevice? meadow = null; - - if (_meadowDevice is MeadowSerialDevice device) - { - serialPort = device.SerialPort?.PortName; - } - - _meadowDevice?.Dispose(); - - await Task.Delay(1000, cancellationToken); - - //try the old port first, if we still have it - if (string.IsNullOrWhiteSpace(serialPort) == false) - { - meadow = await MeadowDeviceManager.GetMeadowForSerialPort(serialPort!, false, Logger); - } - - meadow ??= await MeadowDeviceManager.FindMeadowBySerialNumber( - serialNumber, - Logger, - cancellationToken: cancellationToken); - - - await Task.Delay(1000, cancellationToken); - - _meadowDevice = meadow ?? throw new Exception($"Meadow not found. Serial Number {serialNumber}"); - } - - public async Task WriteRuntimeAndEspBins(string? runtimePath = null, string? osVersion = null, bool skipRuntime = false, bool skipEsp = false, CancellationToken cancellationToken = default) - { - try - { - if (skipRuntime == false) - { - await MonoDisable(cancellationToken: cancellationToken); - - await Task.Delay(2000); - - await _meadowDevice.UpdateMonoRuntime( - runtimePath, - osVersion, - cancellationToken: cancellationToken); - - await Task.Delay(2000); - - await ReInitializeMeadow(cancellationToken); - - await Task.Delay(2000); - } - else - { - Logger.LogInformation("Skipping update of runtime." + Environment.NewLine); - } - - if (skipEsp == false) - { - await MonoDisable(cancellationToken: cancellationToken); - - //Trace.Assert(await GetMonoRunState(cancellationToken) == false, - // "Meadow was expected to have Mono Disabled"); - - Logger.LogInformation("Updating ESP"); - - await _meadowDevice.FlashEsp(DownloadManager.FirmwareDownloadsFilePath, osVersion, cancellationToken); - - // Reset the meadow again to ensure flash worked. - await _meadowDevice.ResetMeadow(cancellationToken); - - await Task.Delay(3000); - - await ReInitializeMeadow(cancellationToken); - } - else - { - Logger.LogInformation("Skipping ESP flash" + Environment.NewLine); - } - - //Logger.LogInformation("Enabling Mono and Resetting"); - //await MonoEnable(cancellationToken); - - // This is to ensure the ESP info has updated in HCOM on the Meadow - await Task.Delay(3000, cancellationToken); - - // TODO: Verify that the device info returns the expected version - var deviceInfo = await _meadowDevice - .GetDeviceInfo(TimeSpan.FromSeconds(60), cancellationToken); - - Logger.LogInformation($"Updated Meadow to OS: {deviceInfo.MeadowOsVersion}, " + - $"Mono: {deviceInfo.RuntimeVersion}, " + - $"Coprocessor: {deviceInfo.CoProcessorOsVersion}"); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error flashing OS to Meadow"); - } - } - - private void Dispose(bool disposing) - { - lock (Logger) - { - if (disposing) - { - _meadowDevice?.Dispose(); - } - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~MeadowDeviceHelper() - { - Dispose(false); - } - - private Dictionary deviceVersionTable = new() - { - { "F7v1", "F7FeatherV1" }, - { "F7v2", "F7FeatherV2" }, - }; - - public bool DeviceAndAppVersionsMatch(string executablePath, CancellationToken cancellationToken = default) - { - var deviceVersion = DeviceInfo.HardwareVersion; - var assembly = Assembly.LoadFrom(executablePath); - try - { - var baseType = assembly.GetTypes()[0].BaseType.ToString(); - string appVersion = string.Empty; - - // IIRC using Linq would be way slower. - foreach (var item in deviceVersionTable) - { - if (baseType.Contains(item.Value)) - { - appVersion = item.Value; - break; - } - } - - if (deviceVersionTable[deviceVersion] != appVersion) - { - Logger.LogInformation($"Current device version is: {deviceVersion}. Current application version is {appVersion}. Update your application version to {deviceVersionTable[deviceVersion]} to deploy to this Meadow device."); - return false; - } - } - finally - { - assembly = null; - } - - return true; - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Devices/MeadowLocalDevice.Comms.cs b/Meadow.CLI.Core/Devices/MeadowLocalDevice.Comms.cs deleted file mode 100644 index 189ac044..00000000 --- a/Meadow.CLI.Core/Devices/MeadowLocalDevice.Comms.cs +++ /dev/null @@ -1,450 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.DeviceManagement.Tools; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Internals.MeadowCommunication; -using Meadow.Hcom; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Devices -{ - public partial class MeadowLocalDevice - { - private const int PROGESS_INCREMENTS = 5; - private uint _packetCrc32; - private readonly SemaphoreSlim _comPortSemaphore = new SemaphoreSlim(1, 1); - private bool reUploadSkippedFiles = false; - private byte reUploadCounter = 0; - - public async Task SendTheEntireFile(FileCommand command, - bool lastInSeries, - CancellationToken cancellationToken) - { - _packetCrc32 = 0; - - try - { - var response = await SendCommand(command, cancellationToken); - - string responseMessage = string.Empty; - if (response.MessageType == MeadowMessageType.DownloadStartFail) - { - if (!string.IsNullOrEmpty(response.Message)) - { - throw new MeadowCommandException(command, $"Meadow rejected download request with the message: {responseMessage}", response); - } - throw new MeadowCommandException(command, $"Meadow rejected download request with an empty response message (DownloadStartFail)", response); - } - - switch (command.RequestType) - { - // if it's an ESP start file transfer and the download started ok. - case HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER - when response.MessageType == MeadowMessageType.DownloadStartOkay: - Logger?.LogDebug("ESP32 download request accepted"); - break; - // if it's an ESP file transfer start and it failed to start - case HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER - when response.MessageType == MeadowMessageType.DownloadStartFail: - Logger?.LogDebug("ESP32 download request rejected"); - throw new MeadowCommandException(command, - "Halting download due to an error while preparing Meadow for download", - response); - case HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER - when response.MessageType != MeadowMessageType.DownloadStartOkay: - throw response.MessageType switch - { - MeadowMessageType.DownloadStartFail => new MeadowCommandException(command, - "Halting download due to an error while preparing Meadow for download", - response), - MeadowMessageType.Concluded => new MeadowCommandException(command, - "Halting download due to an unexpectedly Meadow 'Concluded' received prematurely", - response), - _ => new MeadowCommandException(command, - $"Halting download due to an unexpected Meadow message type {response.MessageType} received", - response) - }; - } - - var fileBufOffset = 0; - ushort sequenceNumber = 1; - - Logger?.LogInformation($"Starting File Transfer... {Environment.NewLine} "); - - if (!InMeadowCLI) // In separate call as used for progress delimiter - { - Logger?.LogInformation("["); - } - - nextProgress = 0; - while (fileBufOffset <= command.FileSize - 1) // equal would mean past the end - { - int numBytesToSend; - if (fileBufOffset + MeadowDeviceManager.MaxAllowableMsgPacketLength - > command.FileSize - 1) - { - numBytesToSend = - command.FileSize - fileBufOffset; // almost done, last packet - } - else - { - numBytesToSend = MeadowDeviceManager.MaxAllowableMsgPacketLength; - } - - if (command.FileBytes == null) - { - throw new MeadowCommandException(command, "File bytes are missing for file command"); - } - - await BuildAndSendDataPacketRequest( - command.FileBytes, - fileBufOffset, - numBytesToSend, - sequenceNumber, - cancellationToken); - - var progress = (decimal)fileBufOffset / command.FileSize; - WriteProgress(progress); - - fileBufOffset += numBytesToSend; - - sequenceNumber++; - } - - // echo the device responses - //await Task.Delay(250, cancellationToken); // if we're too fast, we'll finish and the device will still echo a little - - //-------------------------------------------------------------- - // Build and send the correct trailer - // TODO: Move this into the Command object - var trailerCommand = command.RequestType switch - { - HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER => - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_END_FILE_TRANSFER) - .WithUserData(lastInSeries ? 1U : 0U) - .Build(), - HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME => - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_FILE_END) - .WithUserData(lastInSeries ? 1U : 0U) - .WithTimeout(TimeSpan.FromSeconds(60)) - .Build(), - HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER => - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_END_ESP_FILE_TRANSFER) - .WithTimeout(TimeSpan.FromSeconds(180)) - .WithUserData(lastInSeries ? 1U : 0U) - .Build(), - _ => throw new ArgumentOutOfRangeException( - nameof(command.RequestType), - "Cannot build trailer for unknown command") - }; - - await SendCommand(trailerCommand, cancellationToken); - - - // bufferOffset should point to the byte after the last byte - Debug.Assert(fileBufOffset == command.FileSize); - Logger?.LogTrace( - "Total bytes sent {count} in {packetCount} packets. PacketCRC:{_crc}", - fileBufOffset, - sequenceNumber, - $"{_packetCrc32:x08}"); - - if (!InMeadowCLI) // In separate call as used for progress delimiter - { - Logger?.LogInformation("]"); - } - Logger?.LogInformation($"{Environment.NewLine}Transfer Complete, wrote {fileBufOffset} bytes to Meadow" + Environment.NewLine); - } - catch (Exception ex) - { - Logger?.LogError($"{ex.Message}"); - throw; - } - } - - private int nextProgress; - - private void WriteProgress(decimal i) - { - var intProgress = Convert.ToInt32(i * 100); - - if (intProgress > nextProgress) - { - if (!InMeadowCLI || Debugger.IsAttached) // In separate call as used for progress delimiter - { - Logger?.LogInformation("="); - } - nextProgress += PROGESS_INCREMENTS; - } - } - - private async Task BuildAndSendDataPacketRequest(byte[] messageBytes, - int messageOffset, - int messageSize, - ushort sequenceNumber, - CancellationToken cancellationToken) - { - try - { - // Need to prepend the sequence number to the packet - var transmitSize = messageSize + sizeof(ushort); - byte[] fullMsg = new byte[transmitSize]; - - byte[] seqBytes = BitConverter.GetBytes(sequenceNumber); - Array.Copy(seqBytes, fullMsg, sizeof(ushort)); - Array.Copy(messageBytes, messageOffset, fullMsg, sizeof(ushort), messageSize); - - await EncodeAndSendPacket(fullMsg, 0, transmitSize, cancellationToken); - } - catch (Exception except) - { - Console.WriteLine($"An exception was caught: {except}"); - throw; - } - } - - private protected async Task SendCommand( - Command command, - CancellationToken cancellationToken = default, - [CallerMemberName] string? caller = null) - { - await _comPortSemaphore.WaitAsync(cancellationToken); - - try - { - Logger?.LogTrace($"{caller} is sending {command.RequestType}"); - - CommandResponse resp; - if (command.IsAcknowledged) - { - resp = await WaitForResponseMessageAsync(command, cancellationToken); - } - else - { - var messageBytes = command.ToMessageBytes(); - await EncodeAndSendPacket(messageBytes, 0, messageBytes.Length, cancellationToken); - resp = CommandResponse.Empty; - } - - Logger?.LogTrace( - "Returning to {caller} with {success} {message}", - caller, - resp.IsSuccess, - string.IsNullOrWhiteSpace(resp.Message) ? "[empty]" : resp.Message); - - return resp; - } - finally - { - _comPortSemaphore.Release(); - } - } - - - private async Task EncodeAndSendPacket(byte[] messageBytes, - int messageOffset, - int messageSize, - CancellationToken cancellationToken) - { - try - { - // For testing calculate the crc including the sequence number - _packetCrc32 = CrcTools.Crc32part(messageBytes, messageSize, 0, _packetCrc32); - - // Add 2, first to account for start delimiter and second for end - byte[] encodedBytes = - new byte[MeadowDeviceManager.MaxEstimatedSizeOfEncodedPayload + 2]; - - // Skip first byte so it can be a start delimiter - int encodedToSend = CobsTools.CobsEncoding( - messageBytes, - messageOffset, - messageSize, - ref encodedBytes, - 1); - - // Verify COBS - any delimiters left? Skip first byte - for (int i = 1; i < encodedToSend; i++) - { - if (encodedBytes[i] == 0x00) - { - throw new InvalidProgramException( - "All zeros should have been removed. There's one at offset of {i}"); - } - } - - // Terminate packet with delimiter so packet boundaries can be more easily found - encodedBytes[0] = 0; // Start delimiter - encodedToSend++; - encodedBytes[encodedToSend] = 0; // End delimiter - encodedToSend++; - - try - { - - using var cts = new CancellationTokenSource(DefaultTimeout); - var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token); - await Write(encodedBytes, encodedToSend, combinedCts.Token); - } - catch (InvalidOperationException ioe) // Port not opened - { - Logger?.LogError(ioe, $"Write but port not opened{Environment.NewLine}"); - throw; - } - catch (ArgumentOutOfRangeException aore) // offset or count don't match buffer - { - Logger?.LogError(aore, $"Write buffer, offset and count don't line up{Environment.NewLine}"); - throw; - } - catch (ArgumentException ae) // offset plus count > buffer length - { - Logger?.LogError(ae, $"Write offset plus count > buffer length{Environment.NewLine}"); - throw; - } - catch (TimeoutException te) // Took too long to send - { - Logger?.LogError(te, $"Write took too long to send {Environment.NewLine}"); - throw; - } - } - catch (Exception except) - { - Logger?.LogTrace(except, $"EncodeAndSendPacket threw{Environment.NewLine}"); - throw; - } - } - - private protected async Task WaitForResponseMessageAsync(Command command, - CancellationToken cancellationToken = default, - [CallerMemberName] string? caller = null) - { - Logger?.LogTrace( - "{caller} is waiting {seconds} for response to {requestType}.", - caller, - command.Timeout.TotalSeconds, - command.RequestType); - - var tcs = new TaskCompletionSource(); - var result = false; - var message = string.Empty; - var messageType = MeadowMessageType.ErrOutput; - - void ResponseHandler(object? s, MeadowMessageEventArgs e) - { - - var msg = string.IsNullOrWhiteSpace(e.Message) ? "[empty]" : e.Message; - - switch (e.MessageType) - { - case MeadowMessageType.Data: - Logger?.LogDebug(msg); // We may not need this - break; - case MeadowMessageType.ErrOutput: - if (msg.ToLower().Contains("newer cli protocol version")) - { - // Parse message for required version - var msgSplit = msg.ToLower().Split(':'); - if (msgSplit.Length > 2) - { - int requiredVersion; - if (Int32.TryParse(msgSplit[3].Substring(0, 4), out requiredVersion)) - { - if (requiredVersion == Constants.HCOM_PROTOCOL_PREVIOUS_VERSION_NUMBER) - { - MeadowDeviceManager.MaxAllowableMsgPacketLength = MeadowDeviceManager.PreviousMaxAllowableMsgPacketLength; - Command.HcomProtocolCommunicationVersion = Constants.HCOM_PROTOCOL_PREVIOUS_VERSION_NUMBER; - } - } - } - } - else - { - Logger?.LogError(msg); - } - break; - case MeadowMessageType.DownloadFailed: - // Set Re-download flag, increment download count. - reUploadSkippedFiles = true; - break; - default: - break; - } - - Logger?.LogTrace($"Received MessageType: {e.MessageType} Message: {msg}"); - - if (command.ResponsePredicate(e)) - { - Logger?.LogTrace("Message matched response filter"); - message = e.Message; - messageType = e.MessageType; - result = true; - } - - if (command.CompletionPredicate(e)) - { - Logger?.LogTrace("Setting result complete"); - //message = e.Message; - //messageType = e.MessageType; - result = true; //TODO: Adrian - Pete - should this be here?? I added it - tcs.SetResult(true); - } - } - - Logger?.LogTrace("Attaching response handler(s)"); - Debug.Assert(DataProcessor != null); - if (command.ResponseHandler != null) - { - DataProcessor.OnReceiveData += command.ResponseHandler; - } - - DataProcessor.OnReceiveData += ResponseHandler; - Logger?.LogTrace("Attaching completion handler(s)"); - - try - { - var messageBytes = command.ToMessageBytes(); - await EncodeAndSendPacket(messageBytes, 0, messageBytes.Length, cancellationToken); - - using var timeoutCancellationTokenSource = - new CancellationTokenSource(command.Timeout); - - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellationTokenSource.Token); - - timeoutCancellationTokenSource.Token.Register(() => tcs.TrySetCanceled()); - await tcs.Task; - if (cts.IsCancellationRequested) - throw new TimeoutException("Timeout while waiting for meadow"); - } - catch (TaskCanceledException e) - { - throw new MeadowCommandException(command, - "Command timeout waiting for response.", - innerException: e); - } - finally - { - Logger?.LogTrace("Removing handlers"); - DataProcessor.OnReceiveData -= ResponseHandler; - if (command.ResponseHandler != null) - { - DataProcessor.OnReceiveData -= command.ResponseHandler; - } - } - - if (result) - { - Logger?.LogTrace( - "Returning to {caller} with {message}", - caller, - string.IsNullOrWhiteSpace(message) ? "[empty]" : message); - - return new CommandResponse(result, message, messageType); - } - - throw new MeadowCommandException(command, message); - } - } -} diff --git a/Meadow.CLI.Core/Devices/MeadowLocalDevice.FileManager.cs b/Meadow.CLI.Core/Devices/MeadowLocalDevice.FileManager.cs deleted file mode 100644 index 91286ce7..00000000 --- a/Meadow.CLI.Core/Devices/MeadowLocalDevice.FileManager.cs +++ /dev/null @@ -1,785 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.DeviceManagement.Tools; -using Meadow.CLI.Core.Internals.MeadowCommunication; -using Meadow.Hcom; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Threading; -using System.Threading.Tasks; -using YamlDotNet.Serialization; - -namespace Meadow.CLI.Core.Devices -{ - public abstract partial class MeadowLocalDevice - { - private string[] dllLinkIngoreList = { "System.Threading.Tasks.Extensions.dll" };//, "Microsoft.Extensions.Primitives.dll" }; - private string[] pdbLinkIngoreList = { "System.Threading.Tasks.Extensions.pdb" };//, "Microsoft.Extensions.Primitives.pdb" }; - - public async Task> GetFilesAndFolders( - TimeSpan timeout, - CancellationToken cancellationToken = default) - { - var started = false; - - var items = new List(); - - EventHandler handler = (s, e) => - { - if (e.MessageType == MeadowMessageType.Accepted) - { - started = true; - } - else if (started == false) - { //ignore everything until we've started a new file list request - return; - } - - if (e.MessageType == MeadowMessageType.Data) - { - items.Add(e.Message); - } - }; - - var command = new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_GET_FILES_AND_FOLDERS) - .WithResponseHandler(handler) - .Build(); - - await SendCommand(command, cancellationToken); - - return items; - } - - public async Task> GetFilesAndCrcs( - TimeSpan timeout, - int partition = 0, - CancellationToken cancellationToken = default) - { - var started = false; - - EventHandler handler = (s, e) => - { - if (e.MessageType == MeadowMessageType.FileListTitle) - { - FilesOnDevice.Clear(); - started = true; - } - else if (started == false) - { - //ignore everything until we've started a new file list request - return; - } - - if (e.MessageType == MeadowMessageType.FileListCrcMember) - { - if (FileData.TryParse(e.Message, out FileData? data)) - { - FilesOnDevice.Add(data); - } - } - }; - - var command = new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_LIST_PART_FILES_AND_CRC) - .WithResponseHandler(handler) - .WithUserData((uint)partition) - .Build(); - - await SendCommand(command, cancellationToken); - - return FilesOnDevice; - } - - /// - /// Write a file to the Meadow - /// - /// The name of the file - /// The path to the file - /// The amount of time to wait to write the file - /// The to cancel the operation - /// - public async Task WriteFile(string sourceFileName, - string destinationFileName, - TimeSpan timeout, - CancellationToken cancellationToken = - default) - { - if (IsDeviceInitialized() == false) - { - throw new Exception("Device is not initialized"); - } - - var fi = new FileInfo(sourceFileName); - if (!fi.Exists) - { - throw new FileNotFoundException("Cannot find source file", fi.FullName); - } - - // If ESP32 file we must also send the MD5 has of the file - using var md5 = MD5.Create(); - - byte[] fileBytes; - using (var stream = File.Open(sourceFileName, FileMode.Open)) - { - var streamLength = (int)stream.Length; - fileBytes = new byte[streamLength]; - var bytesRead = 0; - - while (stream.Position < streamLength) - { - bytesRead += await stream.ReadAsync(fileBytes, bytesRead, streamLength, cancellationToken); - } - - if (bytesRead != streamLength) - { - throw new InvalidDataException($"Read bytes: {bytesRead} from {sourceFileName} does not match stream Length: {streamLength}!"); - } - } - - var hash = md5.ComputeHash(fileBytes); - string md5Hash = BitConverter.ToString(hash) - .Replace("-", "") - .ToLowerInvariant(); - - var fileCrc32 = CrcTools.Crc32part(fileBytes, fileBytes.Length, 0); - - var command = - new FileCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER) - .WithSourceFileName(sourceFileName) - .WithDestinationFileName(destinationFileName) - .WithTimeout(timeout) - .WithPartition(0) - .Build(); - - var sw = Stopwatch.StartNew(); - - await SendTheEntireFile(command, true, cancellationToken); - - sw.Stop(); - - return new FileTransferResult(sw.ElapsedMilliseconds, fileBytes.Length, fileCrc32); - } - - public async Task DeleteFile(string fileName, - uint partition = 0, - CancellationToken cancellationToken = default) - { - var command = - new FileCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_DELETE_FILE_BY_NAME) - .WithDestinationFileName(fileName) - .WithPartition(partition) - .WithResponseType(MeadowMessageType.Concluded) - .WithCompletionResponseType(MeadowMessageType.Concluded) - .Build(); - - await SendCommand(command, cancellationToken); - } - - public Task EraseFlash(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_BULK_FLASH_ERASE) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithTimeout(TimeSpan.FromMinutes(5)) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task VerifyErasedFlash(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_VERIFY_ERASED_FLASH) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithTimeout(TimeSpan.FromMinutes(5)) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task FormatFileSystem(uint partition = 0, - CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_FORMAT_FLASH_FILE_SYS) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithTimeout(TimeSpan.FromMinutes(5)) - .WithUserData(partition) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task RenewFileSystem(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_PART_RENEW_FILE_SYS) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithTimeout(TimeSpan.FromMinutes(5)) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task UpdateMonoRuntime(string? fileName, - uint partition = 0, - CancellationToken cancellationToken = default) - { - return UpdateMonoRuntime(fileName, null, partition, cancellationToken); - } - - public async Task UpdateMonoRuntime(string? fileName, - string? osVersion, - uint partition = 0, - CancellationToken cancellationToken = default) - { - var sourceFilename = fileName; - - if (string.IsNullOrWhiteSpace(sourceFilename)) - { - if (string.IsNullOrWhiteSpace(osVersion) == false) - { - sourceFilename = Path.Combine( - DownloadManager.FirmwarePathForVersion(osVersion), - DownloadManager.RuntimeFilename); - } - else - { - sourceFilename = Path.Combine( - DownloadManager.FirmwareDownloadsFilePath, - DownloadManager.RuntimeFilename); - } - - if (File.Exists(sourceFilename)) - { - Logger.LogInformation($"Writing {sourceFilename} runtime"); - } - else - { - Logger.LogInformation("Unable to locate a runtime file. Either provide a path or download one."); - return; - } - } - else if (!File.Exists(sourceFilename)) - { - sourceFilename = Path.Combine(Directory.GetCurrentDirectory(), sourceFilename); - - if (!File.Exists(sourceFilename)) - { - Logger.LogInformation($"File '{sourceFilename}' not found"); - return; - } - } - - var targetFileName = Path.GetFileName(sourceFilename); - - Logger.LogDebug("Sending Mono Update Runtime Request"); - var command = - new FileCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME) - .WithPartition(partition) - .WithDestinationFileName(targetFileName) - .WithSourceFileName(sourceFilename) - .Build(); - - await SendTheEntireFile(command, true, cancellationToken); - } - - public async Task WriteFileToEspFlash(string fileName, - uint partition = 0, - string? mcuDestAddress = null, - CancellationToken cancellationToken = default) - { - var targetFileName = Path.GetFileName(fileName); - // For the ESP32 on the meadow, we don't need the target file name, we just need the - // MCU's destination address and the file's binary. - // Assume if no mcuDestAddress that the fileName is a CSV with both file names and Mcu Address - if (mcuDestAddress != null) - { - // Convert mcuDestAddress from a string to a 32-bit unsigned int, but first - // insure it starts with 0x - uint mcuAddress = 0; - if (mcuDestAddress.StartsWith("0x") || mcuDestAddress.StartsWith("0X")) - { - mcuAddress = uint.Parse( - mcuDestAddress.Substring(2), - System.Globalization.NumberStyles.HexNumber); - } - else - { - Logger.LogError( - $"The '--McuDestAddress' argument must be followed with an address in the form '0x1800'"); - - return; - } - - var command = - new FileCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER) - .WithPartition(partition) - .WithDestinationFileName(targetFileName) - .WithMcuAddress(mcuAddress) - .WithSourceFileName(fileName) - .WithTimeout(new TimeSpan(hours: 0, minutes: 3, seconds: 0)) - .Build(); - - await SendTheEntireFile(command, true, cancellationToken); - } - else - { - // At this point, the fileName field should contain a CSV string containing the destination - // addresses followed by file's location within the host's file system. - // E.g. "0x8000, C:\Blink\partition-table.bin, 0x1000, C:\Blink\bootloader.bin, 0x10000, C:\Blink\blink.bin" - string[] fileElement = fileName.Split(','); - if (fileElement.Length % 2 != 0) - { - Logger.LogError( - "Please provide a CSV input with \"address, fileName, address, fileName\""); - - return; - } - - uint mcuAddress; - for (int i = 0; i < fileElement.Length; i += 2) - { - // Trim any white space from this mcu addr and file name - fileElement[i] = fileElement[i] - .Trim(); - - fileElement[i + 1] = fileElement[i + 1] - .Trim(); - - if (fileElement[i] - .StartsWith("0x") - || fileElement[i] - .StartsWith("0X")) - { - // Fill in the Mcu Address - mcuAddress = uint.Parse( - fileElement[i].Substring(2), - System.Globalization.NumberStyles.HexNumber); - } - else - { - Logger.LogError("Please provide a CSV input with addresses like 0x1234"); - return; - } - - // Meadow.CLI --Esp32WriteFile --SerialPort Com26 --File - // "0x8000, C:\Download\Esp32\Hello\partition-table.bin, 0x1000, C:\Download\Esp32\Hello\bootloader.bin, 0x10000, C:\Download\Esp32\Hello\hello-world.bin" - // File Path and Name - targetFileName = Path.GetFileName(fileElement[i + 1]); - bool lastFile = i == fileElement.Length - 2; - - // this may need need to be awaited? - var command = - new FileCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER) - .WithPartition(partition) - .WithDestinationFileName(targetFileName) - .WithMcuAddress(mcuAddress) - .WithSourceFileName(fileElement[i + 1]) - .Build(); - - await SendTheEntireFile(command, lastFile, cancellationToken); - } - } - } - - public async Task FlashEsp(string? sourcePath, - string? osVersion = null, - CancellationToken cancellationToken = default) - { - if (osVersion == null) - { - sourcePath ??= DownloadManager.FirmwareDownloadsFilePath; - } - else - { - sourcePath = DownloadManager.FirmwarePathForVersion(osVersion); - } - - Logger.LogInformation($"Transferring {Path.Combine(sourcePath, DownloadManager.NetworkMeadowCommsFilename)}"); - await WriteFileToEspFlash( - Path.Combine(sourcePath, DownloadManager.NetworkMeadowCommsFilename), - mcuDestAddress: "0x10000", - cancellationToken: cancellationToken); - - await Task.Delay(3000, cancellationToken); - - Logger.LogInformation($"Transferring {Path.Combine(sourcePath, DownloadManager.NetworkBootloaderFilename)}"); - await WriteFileToEspFlash( - Path.Combine(sourcePath, DownloadManager.NetworkBootloaderFilename), - mcuDestAddress: "0x1000", - cancellationToken: cancellationToken); - - await Task.Delay(1000, cancellationToken); - - Logger.LogInformation($"Transferring {Path.Combine(sourcePath, DownloadManager.NetworkPartitionTableFilename)}"); - await WriteFileToEspFlash( - Path.Combine(sourcePath, DownloadManager.NetworkPartitionTableFilename), - mcuDestAddress: "0x8000", - cancellationToken: cancellationToken); - - await Task.Delay(1000, cancellationToken); - } - - public async Task GetInitialBytesFromFile(string fileName, - uint partition = 0, - CancellationToken cancellationToken = - default) - { - Logger.LogDebug("Getting initial bytes from {fileName}", fileName); - var encodedFileName = System.Text.Encoding.UTF8.GetBytes(fileName); - - var command = - new SimpleCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_GET_INITIAL_FILE_BYTES) - .WithResponseType(MeadowMessageType.InitialFileData) - .WithData(encodedFileName) - .Build(); - - var commandResponse = await SendCommand(command, cancellationToken); - - if (!commandResponse.IsSuccess) - { - Logger.LogWarning("No bytes found for file."); - } - - return commandResponse.Message; - } - - public Task ForwardVisualStudioDataToMono(byte[] debuggerData, - uint userData, - CancellationToken cancellationToken = - default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_DEBUGGING_DEBUGGER_DATA) - .WithData(debuggerData) - .WithResponseType(MeadowMessageType.Accepted) - .WithCompletionResponseType(MeadowMessageType.Accepted) - .WithUserData(userData) - .WithAcknowledgement(false) - .Build(); - - return SendCommand(command, cancellationToken); - } - - //ToDo this is super fragile (extra-super fragile!) - //Need updated API to read files after B5.1 - private async Task DeleteTemporaryFiles(CancellationToken cancellationToken = default) - { - var items = await GetFilesAndFolders(new TimeSpan(0, 0, 15), cancellationToken); - - bool isRoot = false; - bool isFolder = false; - string folderName = string.Empty; - - var filesToDelete = new List(); - - for (int i = 0; i < items.Count; i++) - { //start of folders in root - if (isRoot == false && items[i].Contains("meadow0/")) - { - isRoot = true; - } //next root folder - break out - else if (isRoot && items[i].Contains(" ") == false) - { - break; - } //item under meadow0 - else if (isRoot && - items[i].Contains("/") && - items[i].Contains("./") == false) - { - folderName = items[i].Substring(1); - isFolder = true; - } - else if (isFolder == true && - items[i].Contains(" ") && - items[i].Contains("[file]")) - { - var end = items[i].IndexOf(" [file]"); - filesToDelete.Add(Path.Combine(folderName, items[i].Substring(2, end - 2))); - } - else - { - continue; - } - } - - foreach (var item in filesToDelete) - { - if (item.Contains("Data/") || - item.Contains("Documents/")) - { - continue; - } - - Logger.LogInformation($"Deleting {item}"); - await DeleteFile(item, 0, cancellationToken); - } - } - - private record BuildOptions - { - public DeployOptions Deploy { get; set; } - - public record DeployOptions - { - public List NoLink { get; set; } - public bool? IncludePDBs { get; set; } - } - } - - public async Task DeployApp(string applicationFilePath, - string osVersion, - bool includePdbs = false, - bool verbose = false, - IList? noLink = null, - CancellationToken cancellationToken = default) - { - try - { - // does a meadow.build.yml file exist? - var buildOptionsFile = Path.Combine(Path.GetDirectoryName(applicationFilePath), "app.build.yaml"); - if (File.Exists(buildOptionsFile)) - { - Logger.LogInformation($"'app.build.yaml' found!"); - - var yaml = File.ReadAllText(buildOptionsFile); - var deserializer = new DeserializerBuilder() - .IgnoreUnmatchedProperties() - .Build(); - var opts = deserializer.Deserialize(yaml); - - if (opts.Deploy.NoLink != null && opts.Deploy.NoLink.Count > 0) - { - noLink = opts.Deploy.NoLink; - } - if (opts.Deploy.IncludePDBs != null) - { - includePdbs = opts.Deploy.IncludePDBs.Value; - } - } - } - catch (Exception ex) - { - Logger.LogInformation($"Failed to read app.build.yaml: {ex.Message}"); - } - - try - { - if (!File.Exists(applicationFilePath)) - { - Logger.LogError($"{applicationFilePath} not found."); - return; - } - - var fi = new FileInfo(applicationFilePath); - var directoryName = fi.DirectoryName ?? string.Empty; - var meadowDll = Path.Combine(directoryName, "Meadow.dll"); - - if (!File.Exists(meadowDll)) - { - Logger.LogError($"{meadowDll} not found."); - return; - } - - var fileName = fi.Name; - var fileNamePdb = Path.Combine(directoryName, "App.pdb"); - - await DeleteTemporaryFiles(cancellationToken); - - var deviceFiles = await GetFilesAndCrcs( - DefaultTimeout, - cancellationToken: cancellationToken); - - foreach (var f in deviceFiles) - { - Logger.LogInformation($"Found {f.FileName} (CRC: {f.Crc})" + Environment.NewLine); - } - - var binaries = Directory.EnumerateFiles(directoryName, "*.*", SearchOption.TopDirectoryOnly) - .Where(s => new FileInfo(s).Extension != ".dll") - .Where(s => new FileInfo(s).Extension != ".pdb") - .Where(s => !s.Contains(".DS_Store")); - // .Where(s => extensions.Contains(new FileInfo(s).Extension)); - - var files = new Dictionary(); - - // Add the App.dll - await AddFile(Path.Combine(directoryName, fileName), false); - - if (includePdbs) - { - await AddFile(fileNamePdb, false); - } - else if (verbose) - { - Logger.LogInformation("Skipping PDBs"); - } - - - async Task AddFile(string file, bool includePdbs) - { - if (files.ContainsKey(Path.GetFileName(file))) - { - return; - } - - using FileStream fs = File.Open(file, FileMode.Open); - var len = (int)fs.Length; - var bytes = new byte[len]; - - await fs.ReadAsync(bytes, 0, len, cancellationToken); - - //0x - var crc = CrcTools.Crc32part(bytes, len, 0); // 0x04C11DB7); - - Logger.LogDebug("{file} crc is {crc:X8}", file, crc); - files.Add(file, crc); - if (includePdbs) - { - var pdbFile = Path.ChangeExtension(file, "pdb"); - if (File.Exists(pdbFile)) - await AddFile(pdbFile, false); - } - } - - var dependencies = AssemblyManager.GetDependencies(fileName, directoryName, osVersion) - .Except(new string[] { "App.dll", "App.exe" }) - .ToList(); - - var trimmedDependencies = await AssemblyManager.TrimDependencies(fileName, directoryName, dependencies, noLink, Logger, includePdbs: includePdbs, verbose: verbose); - - //add local files (this includes App.exe) - foreach (var file in binaries) - { - await AddFile(file, false); - } - - if (trimmedDependencies != null) - { - trimmedDependencies = trimmedDependencies.Where(x => x.Contains("App.") == false) - .Where(x => dllLinkIngoreList.Any(f => x.Contains(f)) == false) - .Where(x => pdbLinkIngoreList.Any(f => x.Contains(f)) == false) - .ToList(); - - //crawl trimmed dependencies - foreach (var file in trimmedDependencies) - { - await AddFile(file, false); - } - - for (int i = 0; i < dllLinkIngoreList.Length; i++) - { //add the files from the dll link ignore list - if (dependencies.Exists(f => f.Contains(dllLinkIngoreList[i]))) - { - await AddFile(dependencies.FirstOrDefault(f => f.Contains(dllLinkIngoreList[i])), includePdbs); - } - } - } - else - { - //crawl dependencies - foreach (var file in dependencies) - { - await AddFile(file, false); - } - } - - // delete unused files - foreach (var devicefile in deviceFiles) - { - bool found = false; - foreach (var localfile in files.Keys) - { - if (Path.GetFileName(localfile).Equals(devicefile.FileName)) - { - found = true; - } - if (found) { break; } - } - if (found == false) - { - await DeleteFile(devicefile.FileName, cancellationToken: cancellationToken); - - Logger.LogInformation($"Removing file: {devicefile}" + Environment.NewLine); - } - } - - // write new files - foreach (var file in files) - { - // does the file name and CRC match? - var filename = Path.GetFileName(file.Key); - - if (deviceFiles.Any(d => d.FileName == filename && d.Crc == file.Value)) - { - Logger.LogInformation($"Skipping file (hash match): {filename}" + Environment.NewLine); - continue; - } - - if (!File.Exists(file.Key)) - { - Logger.LogInformation($"{filename} not found" + Environment.NewLine); - continue; - } - - Logger.LogInformation($"{Environment.NewLine}Sending file: {file.Key}" + Environment.NewLine); - await WriteFile( - file.Key, - filename, - DefaultTimeout, - cancellationToken); - } - - if (reUploadSkippedFiles) - { - reUploadCounter++; - if (reUploadCounter < 3) - { - await DeployApp(applicationFilePath, - osVersion, - includePdbs, - verbose, - noLink, - cancellationToken); - } - else - { - // Clean up the reload variables. - reUploadSkippedFiles = false; - reUploadCounter = 0; - - // Let's bail out of here - throw new Exception("Tried to send files to Meadow at least 3 times and failed. Something it seriously wrong! Check you are running the latest OS etc."); - } - } - else - { - Logger.LogInformation($"{Environment.NewLine}{fileName} deploy complete!{Environment.NewLine}"); - } - } - catch (Exception ex) - { - Logger.LogError($"An error occurred during the App deployment process."); - Logger.LogError($"Error:{Environment.NewLine}{ex.Message} {Environment.NewLine}Stack Trace :{Environment.NewLine}{ex.StackTrace}"); - throw ex; - } - } - - public async Task IsFileOnDevice(string filename, CancellationToken cancellationToken) - { - if (FilesOnDevice.Any() == false) - { - await GetFilesAndCrcs(DefaultTimeout, 0, cancellationToken); - } - return FilesOnDevice.Any(f => f.FileName == filename); - } - } -} diff --git a/Meadow.CLI.Core/Devices/MeadowLocalDevice.cs b/Meadow.CLI.Core/Devices/MeadowLocalDevice.cs deleted file mode 100644 index 0e534bea..00000000 --- a/Meadow.CLI.Core/Devices/MeadowLocalDevice.cs +++ /dev/null @@ -1,378 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Internals.MeadowCommunication; -using Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses; -using Meadow.Hcom; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Devices -{ - public abstract partial class MeadowLocalDevice : IMeadowDevice - { - private protected TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60); - - public ILogger? Logger { get; } - public MeadowDataProcessor DataProcessor { get; } - public MeadowDeviceInfo? DeviceInfo { get; protected set; } - public DebuggingServer DebuggingServer { get; } - public IList FilesOnDevice { get; } = new List(); - public bool InMeadowCLI { get; set; } - - protected MeadowLocalDevice(MeadowDataProcessor dataProcessor, ILogger? logger = null) - { - Logger = logger; - DataProcessor = dataProcessor; - - var entryAssembly = Assembly.GetEntryAssembly()!; - - if (entryAssembly != null) - InMeadowCLI = entryAssembly.FullName.ToLower().Contains("meadow"); - } - - public abstract Task Write(byte[] encodedBytes, - int encodedToSend, - CancellationToken cancellationToken = default); - - public async Task GetDeviceInfo(TimeSpan timeout, CancellationToken cancellationToken = default) - { - DeviceInfo = null; - - var command = new SimpleCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_GET_DEVICE_INFORMATION) - .WithTimeout(timeout) - .WithResponseType(MeadowMessageType.DeviceInfo) - .WithCompletionResponseType(MeadowMessageType.Concluded) - .Build(); - - - try - { - var retryCount = 1; - - Retry: - var commandResponse = await SendCommand(command, cancellationToken); - - if (commandResponse.IsSuccess) - { - if (commandResponse.Message == String.Empty) - { // TODO: this feels like a bug lower down or in HCOM, but I can reproduce it regularly (3 Oct 2022) - if (--retryCount >= 0) - { - goto Retry; - } - } - - DeviceInfo = new MeadowDeviceInfo(commandResponse.Message!); - return DeviceInfo; - } - - throw new DeviceInfoException(); - } - catch (MeadowDeviceManagerException mdmEx) - { - throw new DeviceInfoException(mdmEx); - } - } - - //device name is processed when the message is received - //this will request the device name and return true it was successfully - public async Task GetDeviceName(TimeSpan timeout, CancellationToken cancellationToken = default) - { - var info = await GetDeviceInfo(timeout, cancellationToken); - - return info?.Product ?? String.Empty; - } - - public async Task GetMonoRunState(CancellationToken cancellationToken = default) - { - Logger.LogDebug("Sending Mono Run State Request"); - - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_RUN_STATE) - .WithResponseType(MeadowMessageType.Data) - .Build(); - - var commandResponse = - await SendCommand(command, cancellationToken); - - var result = false; - switch (commandResponse.Message) - { - case "On reset, Meadow will start MONO and run app.exe": - case "Mono is enabled": - result = true; - break; - case "On reset, Meadow will not start MONO, therefore app.exe will not run": - case "Mono is disabled": - result = false; - break; - } - - Logger.LogDebug("Mono Run State: {runState}", result ? "enabled" : "disabled"); - return result; - } - - public async Task MonoDisable(CancellationToken cancellationToken = default) - { - Logger.LogDebug("Sending Mono Disable Request"); - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_DISABLE) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithResponseType(MeadowMessageType.SerialReconnect) - .Build(); - - await SendCommand(command, cancellationToken); - } - - public async Task MonoEnable(CancellationToken cancellationToken = default) - { - Logger.LogDebug("Sending Mono Enable Request"); - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_ENABLE) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithResponseType(MeadowMessageType.SerialReconnect) - .Build(); - - await SendCommand(command, cancellationToken); - } - - public Task MonoFlash(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_FLASH) - .WithCompletionFilter( - e => e.Message.StartsWith("Mono runtime successfully flashed.")) - .WithTimeout(TimeSpan.FromMinutes(5)) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public async Task ResetMeadow(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_RESET_PRIMARY_MCU) - .WithCompletionResponseType(MeadowMessageType.SerialReconnect) - .WithResponseType(MeadowMessageType.SerialReconnect) - .Build(); - - await SendCommand(command, cancellationToken); - } - - public Task EnterDfuMode(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_ENTER_DFU_MODE) - .WithCompletionResponseType(MeadowMessageType.Accepted) - .WithResponseFilter(x => true) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task NshEnable(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_ENABLE_DISABLE_NSH) - .WithUserData(1) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task NshDisable(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_ENABLE_DISABLE_NSH) - .WithUserData(0) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task TraceEnable(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_SEND_TRACE_TO_HOST) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task Uart1Trace(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_SEND_TRACE_TO_UART) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task TraceDisable(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_NO_TRACE_TO_HOST) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task SetTraceLevel(uint traceLevel, CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_CHANGE_TRACE_LEVEL) - .WithUserData(traceLevel) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task SetDeveloper(ushort level, uint userData, CancellationToken cancellationToken = default) - { - var command = new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_DEVELOPER) - .WithDeveloperLevel(level) - .WithUserData(userData) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task Uart1Apps(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_NO_TRACE_TO_UART) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task QspiWrite(int value, CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_S25FL_QSPI_WRITE) - .WithUserData((uint)value) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task QspiRead(int value, CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_S25FL_QSPI_READ) - .WithUserData((uint)value) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public Task QspiInit(int value, CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_S25FL_QSPI_INIT) - .WithUserData((uint)value) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public async Task StartDebugging(int port, CancellationToken cancellationToken) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_START_DBG_SESSION) - .WithCompletionResponseType(MeadowMessageType.Accepted) - .WithResponseType(MeadowMessageType.Accepted) - .Build(); - - await SendCommand(command, cancellationToken); - } - - public Task RestartEsp32(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_RESTART_ESP32) - .WithCompletionResponseType(MeadowMessageType.Concluded) - .Build(); - - return SendCommand(command, cancellationToken); - } - - public async Task GetDeviceMacAddress(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_READ_ESP_MAC_ADDRESS).Build(); - - var commandResponse = - await SendCommand(command, cancellationToken); - - return commandResponse.Message; - } - - public async Task GetRtcTime(CancellationToken cancellationToken = default) - { - var command = - new SimpleCommandBuilder( - HcomMeadowRequestType.HCOM_MDOW_REQUEST_RTC_READ_TIME_CMD) - .WithResponseType(MeadowMessageType.Data) - .Build(); - - var commandResponse = - await SendCommand(command, cancellationToken); - - // return will be in the format "UTC time:2022-10-22T10:40:19+0:00" - return DateTimeOffset.Parse(commandResponse.Message.Substring(9)); - } - - public async Task SetRtcTime(DateTimeOffset dateTime, CancellationToken cancellationToken) - { - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_RTC_SET_TIME_CMD - ) - .WithCompletionResponseType(MeadowMessageType.Accepted) - .WithResponseType(MeadowMessageType.Accepted) - .WithData(Encoding.ASCII.GetBytes(dateTime.ToString("o"))) - .Build(); - - await SendCommand(command, cancellationToken); - } - - public async Task CloudRegisterDevice(CancellationToken cancellationToken = default) - { - Logger.LogInformation("Sending Meadow Cloud registration request (~2 mins)"); - - var command = - new SimpleCommandBuilder(HcomMeadowRequestType.HCOM_MDOW_REQUEST_OTA_REGISTER_DEVICE) - .WithResponseType(MeadowMessageType.DevicePublicKey) - .WithCompletionResponseType(MeadowMessageType.Concluded) - .WithTimeout(new TimeSpan(hours: 0, minutes: 5, seconds: 0)) // RSA keypair generation on device takes a while - .Build(); - - var commandResponse = - await SendCommand(command, cancellationToken); - - return commandResponse.Message; - } - - public abstract Task Initialize(CancellationToken cancellationToken); - - public abstract bool IsDeviceInitialized(); - - private protected abstract void Dispose(bool disposing); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~MeadowLocalDevice() - { - Dispose(false); - } - } -} diff --git a/Meadow.CLI.Core/Devices/MeadowSerialDevice.cs b/Meadow.CLI.Core/Devices/MeadowSerialDevice.cs deleted file mode 100644 index 0a722b01..00000000 --- a/Meadow.CLI.Core/Devices/MeadowSerialDevice.cs +++ /dev/null @@ -1,172 +0,0 @@ -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Internals.MeadowCommunication; -using System; -using System.IO; -using System.IO.Ports; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Devices -{ - public class MeadowSerialDevice : MeadowLocalDevice - { - private readonly string _serialPortName; - public SerialPort? SerialPort { get; private set; } - - const int SERIAL_PORT_TIMEOUT = 5; - - private readonly object lockObject = new object(); - - public MeadowSerialDevice(string serialPortName, ILogger? logger = null) - : this(serialPortName, OpenSerialPort(serialPortName), logger) - { - } - - internal MeadowSerialDevice(string serialPortName, - SerialPort serialPort, - ILogger? logger = null) - : base(new MeadowSerialDataProcessor(serialPort, logger), logger) - { - SerialPort = serialPort; - _serialPortName = serialPortName; - } - - public override bool IsDeviceInitialized() - { - return SerialPort != null; - } - - private protected override void Dispose(bool disposing) - { - if (disposing) - { - Logger?.LogTrace("Disposing SerialPort"); - - if (SerialPort != null) - { - lock (lockObject) - { - if (SerialPort.IsOpen) - { - SerialPort.Close(); - } - SerialPort.Dispose(); - SerialPort = null; - } - } - } - } - - public override async Task Write(byte[] encodedBytes, int encodedToSend, CancellationToken cancellationToken = default) - { - if (SerialPort == null || SerialPort.IsOpen == false) - { - Logger.LogDebug("SerialPort is null or not open."); - throw new DeviceDisconnectedException(); - } - - await SerialPort.BaseStream.WriteAsync(encodedBytes, 0, encodedToSend, cancellationToken); - } - - public override async Task Initialize(CancellationToken cancellationToken) - { - var initTimeout = TimeSpan.FromSeconds(60); - var now = DateTime.UtcNow; - var then = now.Add(initTimeout); - while (DateTime.UtcNow < then) - { - try - { - if (SerialPort is { IsOpen: true }) - { - Logger.LogDebug("Initializing Meadow for the first time"); - - // TODO: Find a way to flush all the garbage startup messages - await Task.Delay(1000, cancellationToken); - - DeviceInfo = await GetDeviceInfo(TimeSpan.FromSeconds(5), cancellationToken); - - return true; - } - } - catch (MeadowCommandException meadowCommandException) - { - Logger.LogTrace( - meadowCommandException, - "Caught exception while waiting for device to be ready. Retrying."); - } - catch (DeviceDisconnectedException ddEx) - { - // eat it - Logger.LogTrace(ddEx, - "Caught exception while waiting for device to be ready. Retrying."); - } - catch (Exception ex) - { - Logger.LogTrace(ex, "Caught exception while waiting for device to be ready. Retrying."); - } - //ToDo: Adrian - review - increased delay from 100ms to 500ms - await Task.Delay(500, cancellationToken); - } - - throw new Exception($"Device not ready after {initTimeout}s"); - } - - private static SerialPort OpenSerialPort(string portName) - { - if (string.IsNullOrEmpty(portName)) - { - throw new ArgumentException("Serial Port name cannot be empty", nameof(portName)); - } - - // Create a new SerialPort object with default settings - var port = new SerialPort - { - PortName = portName, - BaudRate = 115200, // This value is ignored when using ACM - Parity = Parity.None, - DataBits = 8, - StopBits = StopBits.One, - Handshake = Handshake.None, - - // Set the read/write timeouts - ReadTimeout = 5000, - WriteTimeout = 5000 - }; - - if (port.IsOpen) - port.Close(); - - int retries = 10; - - for (int i = 0; i < retries; i++) - { - try - { //on Windows the port can be slow to release after disposing - port.Open(); - port.BaseStream.ReadTimeout = 0; - break; - } - catch (FileNotFoundException) - { - throw new Exception($"Serial port '{portName}' not found"); - } - catch (UnauthorizedAccessException uae) - { - if (i == retries - 1) - { - throw new Exception($"{uae.Message} Another application may have access to '{portName}'. "); - } - Thread.Sleep(500); - } - catch (Exception ex) - { - // We don't know what happened, best to bail and let the user know. - throw new Exception($"Unable to open port '{portName}'. {ex.Message}"); - } - } - - return port; - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Devices/MeadowSocketDevice.cs b/Meadow.CLI.Core/Devices/MeadowSocketDevice.cs deleted file mode 100644 index 881237d8..00000000 --- a/Meadow.CLI.Core/Devices/MeadowSocketDevice.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Globalization; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using Meadow.CLI.Core.Internals.MeadowCommunication; - -namespace Meadow.CLI.Core.Devices -{ - public class MeadowSocketDevice : MeadowLocalDevice - { - private readonly AddressFamily _addressFamily; - public readonly Socket Socket; - - public MeadowSocketDevice(Socket socket, ILogger? logger = null) - : base(new MeadowSerialDataProcessor(socket), logger) - { - Socket = socket; - } - - public override bool IsDeviceInitialized() - { - throw new NotImplementedException(); - } - - private protected override void Dispose(bool disposing) - { - if (disposing) - Socket?.Dispose(); - } - - public override async Task Write(byte[] encodedBytes, int encodedToSend, CancellationToken cancellationToken) - { - await Task.Yield(); - Socket.Send(encodedBytes, encodedToSend, - SocketFlags.None); - } - - public override Task Initialize(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - //Socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - - //try - //{ - // Socket.Connect(endpoint); - //} - //catch (SocketException) - //{ - // Console.WriteLine("Could not connect to socket, aborting..."); - // Environment.Exit(1); - //} - } - - private static bool TryCreateIPEndPoint(string address, - out IPEndPoint? endpoint) - { - if (string.IsNullOrEmpty(address)) - { - address = string.Empty; - } - address = address.Replace("localhost", "127.0.0.1"); - endpoint = null; - - string[] ep = address.Split(':'); - if (ep.Length != 2) - return false; - - if (!IPAddress.TryParse(ep[0], out IPAddress ip)) - return false; - - int port; - if (!int.TryParse(ep[1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port)) - return false; - - endpoint = new IPEndPoint(ip, port); - return true; - } - } -} diff --git a/Meadow.CLI.Core/Exceptions/DeviceDisconnectedException.cs b/Meadow.CLI.Core/Exceptions/DeviceDisconnectedException.cs deleted file mode 100644 index 90fcf4d1..00000000 --- a/Meadow.CLI.Core/Exceptions/DeviceDisconnectedException.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Meadow.CLI.Core.Exceptions -{ - public class DeviceDisconnectedException : MeadowDeviceException - { - public DeviceDisconnectedException() - : base("The Meadow is no longer connected.") - { - } - } -} diff --git a/Meadow.CLI.Core/Exceptions/DeviceNotFoundException.cs b/Meadow.CLI.Core/Exceptions/DeviceNotFoundException.cs deleted file mode 100644 index 7f5f85ba..00000000 --- a/Meadow.CLI.Core/Exceptions/DeviceNotFoundException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Meadow.CLI.Core.DeviceManagement; - -namespace Meadow.CLI.Core.Exceptions -{ - public class DeviceNotFoundException : MeadowDeviceException - { - public DeviceNotFoundException(string? message = null, Exception? innerException = null) - : base(message ?? "Unable to find Meadow", innerException) - { - - } - } -} diff --git a/Meadow.CLI.Core/Exceptions/MeadowCloudAuthException.cs b/Meadow.CLI.Core/Exceptions/MeadowCloudAuthException.cs deleted file mode 100644 index 708c3ab7..00000000 --- a/Meadow.CLI.Core/Exceptions/MeadowCloudAuthException.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.Exceptions -{ - public class MeadowCloudAuthException : Exception - { - } -} diff --git a/Meadow.CLI.Core/Exceptions/MeadowCloudException.cs b/Meadow.CLI.Core/Exceptions/MeadowCloudException.cs deleted file mode 100644 index c24f9bee..00000000 --- a/Meadow.CLI.Core/Exceptions/MeadowCloudException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.Exceptions -{ - public class MeadowCloudException : Exception - { - public MeadowCloudException(string message, Exception? innerException = null) - : base(message, innerException) { } - } -} diff --git a/Meadow.CLI.Core/Exceptions/MeadowCommandException.cs b/Meadow.CLI.Core/Exceptions/MeadowCommandException.cs deleted file mode 100644 index a7525c10..00000000 --- a/Meadow.CLI.Core/Exceptions/MeadowCommandException.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Internals.MeadowCommunication; - -namespace Meadow.CLI.Core.Exceptions -{ - public class MeadowCommandException : MeadowDeviceException - { - public MeadowCommandException(Command command, string message, CommandResponse? commandResponse = null, Exception? innerException = null) - : base(message, innerException) - { - Command = command; - MeadowMessage = commandResponse?.Message; - MessageType = commandResponse?.MessageType; - } - - public Command Command { get; } - public MeadowMessageType? MessageType { get; } - public string? MeadowMessage { get; } - - public override string ToString() - { - var b = base.ToString(); - return $"{Command}{Environment.NewLine}" - + $"{b}"; - } - } -} diff --git a/Meadow.CLI.Core/Exceptions/MeadowDeviceException.cs b/Meadow.CLI.Core/Exceptions/MeadowDeviceException.cs deleted file mode 100644 index 259259ce..00000000 --- a/Meadow.CLI.Core/Exceptions/MeadowDeviceException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Meadow.CLI.Core.Exceptions -{ - public class MeadowDeviceException : Exception - { - public MeadowDeviceException(string message, Exception? innerException = null) - : base(message, innerException) - { - } - } -} diff --git a/Meadow.CLI.Core/Exceptions/MultipleDfuDevicesException.cs b/Meadow.CLI.Core/Exceptions/MultipleDfuDevicesException.cs deleted file mode 100644 index 35910f18..00000000 --- a/Meadow.CLI.Core/Exceptions/MultipleDfuDevicesException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Meadow.CLI.Core.Exceptions -{ - public class MultipleDfuDevicesException : DeviceNotFoundException - { - public MultipleDfuDevicesException(string message, Exception? innerException = null) - : base(message, innerException) - { - } - } -} diff --git a/Meadow.CLI.Core/Extensions.cs b/Meadow.CLI.Core/Extensions.cs deleted file mode 100644 index 25b8cbd0..00000000 --- a/Meadow.CLI.Core/Extensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Meadow.CLI.Core -{ - public static class Extensions - { - public static Version ToVersion(this string s) - { - if (Version.TryParse(s, out var result)) - { - return result; - } - else - { - return new Version(); - } - } - } -} diff --git a/Meadow.CLI.Core/Firmware/FirmwareInfo.cs b/Meadow.CLI.Core/Firmware/FirmwareInfo.cs deleted file mode 100644 index 031b25cc..00000000 --- a/Meadow.CLI.Core/Firmware/FirmwareInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core -{ - public class BuildDateConverter : JsonConverter - { - // build date is in the format "2022-09-01 09:47:26" - private const string FormatString = "yyyy-MM-dd HH:mm:ss"; - - public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - Debug.Assert(typeToConvert == typeof(DateTime)); - - if (!reader.TryGetDateTime(out DateTime value)) - { - value = DateTime.ParseExact(reader.GetString(), FormatString, CultureInfo.InvariantCulture); - } - - return value; - } - - public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToString(FormatString)); - } - } - - public class FirmwareInfo - { - public string Version { get; set; } = string.Empty; - [JsonPropertyName("build-date")] - public DateTime BuildDate { get; set; } - [JsonPropertyName("build-hash")] - public string BuildHash { get; set; } = string.Empty; - public bool IsLatest { get; set; } - - public override bool Equals(object obj) - { - var other = obj as FirmwareInfo; - if (other == null) return false; - return BuildHash.Equals(other.BuildHash); - } - - public override int GetHashCode() - { - return BuildHash.GetHashCode(); - } - } -} diff --git a/Meadow.CLI.Core/Firmware/FirmwareManager.cs b/Meadow.CLI.Core/Firmware/FirmwareManager.cs deleted file mode 100644 index 9e1657cd..00000000 --- a/Meadow.CLI.Core/Firmware/FirmwareManager.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core -{ - public static partial class JsonSerializerExtensions - { - public static T? DeserializeAnonymousType(string json, T anonymousTypeObject, JsonSerializerOptions? options = default) - => JsonSerializer.Deserialize(json, options); - - public static ValueTask DeserializeAnonymousTypeAsync(Stream stream, TValue anonymousTypeObject, JsonSerializerOptions? options = default, CancellationToken cancellationToken = default) - => JsonSerializer.DeserializeAsync(stream, options, cancellationToken); // Method to deserialize from a stream added for completeness - } - - public static class FirmwareManager - { - public static async Task GetRemoteFirmwareInfo(string versionNumber, ILogger logger, CancellationToken cancellationToken) - { - var manager = new DownloadManager(logger); - - return await manager.DownloadMeadowOSVersionFile(versionNumber, cancellationToken); - } - - public static async Task GetRemoteFirmware(string versionNumber, ILogger logger) - { - var manager = new DownloadManager(logger); - - await manager.DownloadOsBinaries(versionNumber, true); - } - - public static async Task GetCloudLatestFirmwareVersion() - { - var request = (HttpWebRequest)WebRequest.Create($"{DownloadManager.VersionCheckUrlRoot}latest.json"); - using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync()) - using (Stream stream = response.GetResponseStream()) - using (StreamReader reader = new StreamReader(stream)) - { - var json = await reader.ReadToEndAsync(); - - if (json == null) return string.Empty; - - return JsonSerializerExtensions.DeserializeAnonymousType(json, new { version = string.Empty }).version; - } - } - - public static string GetLocalLatestFirmwareVersion() - { - var di = new DirectoryInfo(DownloadManager.FirmwareDownloadsFilePathRoot); - var latest = string.Empty; - var latestFile = di.GetFiles("latest.txt").FirstOrDefault(); - if (latestFile != null) - { - latest = File.ReadAllText(latestFile.FullName).Trim(); - } - return latest; - } - - public static FirmwareInfo[] GetAllLocalFirmwareBuilds() - { - var list = new List(); - - var di = new DirectoryInfo(DownloadManager.FirmwareDownloadsFilePathRoot); - - var latest = GetLocalLatestFirmwareVersion(); - - var options = new JsonSerializerOptions(); - options.Converters.Add(new BuildDateConverter()); - - FirmwareInfo? ParseInfo(string version, string json) - { - var fi = JsonSerializer.Deserialize(json, options); - if (fi == null) return null; - fi.Version = version; - fi.IsLatest = version == latest; - return fi; - } - - foreach (var dir in di.EnumerateDirectories()) - { - var info = dir.GetFiles("build-info.json").FirstOrDefault(); - if (info == null) continue; - var json = File.ReadAllText(info.FullName); - try - { - var fi = ParseInfo(dir.Name, json); - if (fi != null) - { - list.Add(fi); - } - } - catch (JsonException ex) - { - // work around for Issue #229 (bad json) - var index = json.IndexOf(']'); - if (index != -1 && json[index + 1] == ',') - { - var fix = $"{json.Substring(0, index + 1)}{json.Substring(index + 2)}"; - try - { - var fi = ParseInfo(dir.Name, fix); - if (fi != null) - { - list.Add(fi); - } - } - catch - { - continue; - } - } - - continue; - } - } - return list.ToArray(); - } - - public static FirmwareUpdater GetFirmwareUpdater(MeadowConnectionManager connectionManager) - { - return new FirmwareUpdater(connectionManager); - } - - - - public static async Task PushApplicationToDevice(IMeadowConnection connection, DirectoryInfo appFolder, ILogger? logger = null) - { - try - { - if (connection == null) throw new ArgumentNullException("connection"); - if (connection.Device == null) throw new ArgumentNullException("connection.Device"); - if (!connection.IsConnected) - { - if (!await connection.WaitForConnection(TimeSpan.FromSeconds(5))) - { - throw new Exception("No device connected"); - } - } - - connection.AutoReconnect = false; - - if (connection.Device.DeviceInfo == null) - { - await connection.Device.GetDeviceInfo(TimeSpan.FromSeconds(5)); - } - - var osVersion = connection.Device.DeviceInfo.MeadowOsVersion; - - await connection.Device.MonoDisable(); - // the device will disconnect and reconnect here - - // can't check "is connected" immediately, as it take a few hundred ms to disable mono and restart - await Task.Delay(1000); - - // wait for reconnect - await connection.WaitForConnection(TimeSpan.FromSeconds(15)); - - await connection.Device.DeployApp(Path.Combine(appFolder.FullName, "App.dll"), osVersion); - - await connection.Device.MonoEnable(); - } - catch (Exception ex) - { - logger?.LogError(ex, "Error flashing OS to Meadow"); - } - finally - { - connection.AutoReconnect = true; - } - } - } -} diff --git a/Meadow.CLI.Core/Firmware/FirmwareUpdater.cs b/Meadow.CLI.Core/Firmware/FirmwareUpdater.cs deleted file mode 100644 index a20ae0fc..00000000 --- a/Meadow.CLI.Core/Firmware/FirmwareUpdater.cs +++ /dev/null @@ -1,373 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Internals.Dfu; -using System; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core -{ - public class FirmwareUpdater - { - private MeadowConnectionManager _connectionManager; - private ILogger? _logger; - private Task? _updateTask; - private IMeadowConnection _connection; - private UpdateState _state; - - private string RequestedVersion { get; set; } - - public enum UpdateState - { - NotStarted, - EnteringDFUMode, - InDFUMode, - UpdatingOS, - DFUCompleted, - DisablingMonoForRuntime, - UpdatingRuntime, - DisablingMonoForCoprocessor, - UpdatingCoprocessor, - AllWritesComplete, - VerifySuccess, - UpdateSuccess, - Error - } - - public UpdateState PreviousState { get; private set; } - - internal FirmwareUpdater(MeadowConnectionManager connectionManager) - { - _connectionManager = connectionManager; - _logger = connectionManager.Logger; - } - - public UpdateState CurrentState - { - get => _state; - private set - { - if (value == _state) return; - PreviousState = CurrentState; - _state = value; - _logger.LogDebug($"Firmware Updater: {PreviousState}->{CurrentState}"); - } - } - - private async void StateMachine() - { - var tries = 0; - - MeadowDeviceInfo? info = null; - - while (true) - { - switch (CurrentState) - { - case UpdateState.NotStarted: - try - { - // make sure we have a current device info - info = await _connection.Device.GetDeviceInfo(TimeSpan.FromSeconds(10)); - - if (info.MeadowOsVersion == RequestedVersion) - { - // no need to update, it's already there - CurrentState = UpdateState.DFUCompleted; - break; - } - - // enter DFU mode - await _connection.Device.EnterDfuMode(); - CurrentState = UpdateState.EnteringDFUMode; - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - - break; - case UpdateState.EnteringDFUMode: - // look for DFU device - try - { - var dfu = DfuUtils.GetDeviceInBootloaderMode(); - CurrentState = UpdateState.InDFUMode; - } - catch (Exception ex) - { - ++tries; - if (tries > 5) - { - _logger.LogError($"Failed to enter DFU mode: {ex.Message}"); - CurrentState = UpdateState.Error; - - // exit state machine - return; - } - await Task.Delay(1000); - } - break; - case UpdateState.InDFUMode: - try - { - var success = await DfuUtils.FlashVersion(RequestedVersion, _logger); - if (success) - { - CurrentState = UpdateState.DFUCompleted; - } - else - { - CurrentState = UpdateState.Error; - - // exit state machine - return; - } - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - break; - case UpdateState.DFUCompleted: - // if we started in DFU mode, we'll have no connection. We'll have to just assume the first one to appear is what we're after - try - { - if (_connection == null) - { - _connection = await GetFirstAvailableConnection(); - } - - // wait for device to reconnect - await _connection.WaitForConnection(TimeSpan.FromSeconds(30)); - await Task.Delay(2000); // wait 2 seconds to allow full boot - - if (info == null) - { - info = _connection.Device.DeviceInfo; - } - - CurrentState = UpdateState.DisablingMonoForRuntime; - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - break; - case UpdateState.DisablingMonoForRuntime: - try - { - await _connection.Device.MonoDisable(); - } - catch (DeviceDisconnectedException) - { - // this happens after calling MonoDisable because it tries to read a response from a non-existing serial port - // just ignore it, the next state waits for a reconnect anyway - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - CurrentState = UpdateState.UpdatingRuntime; - break; - case UpdateState.UpdatingRuntime: - if (info.RuntimeVersion == RequestedVersion) - { - // no need to update, it's already there - } - else - { - try - { - await _connection.WaitForConnection(TimeSpan.FromSeconds(30)); - await Task.Delay(2000); // wait 2 seconds to allow full boot - - if (info == null) - { - info = _connection.Device.DeviceInfo; - } - - await _connection.Device.UpdateMonoRuntime(null, RequestedVersion); - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - } - CurrentState = UpdateState.DisablingMonoForCoprocessor; - break; - case UpdateState.DisablingMonoForCoprocessor: - try - { - await _connection.Device.MonoDisable(); - - CurrentState = UpdateState.UpdatingCoprocessor; - } - catch (DeviceDisconnectedException) - { - // this happens after calling MonoDisable because it tries to read a response from a non-existing serial port - // just ignore it, the next state waits for a reconnect anyway - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - CurrentState = UpdateState.UpdatingCoprocessor; - break; - case UpdateState.UpdatingCoprocessor: - if (info.CoProcessorOsVersion == RequestedVersion) - { - // no need to update, it's already there - } - else - { - try - { - Debug.WriteLine(">> waiting for connection"); - await _connection.WaitForConnection(TimeSpan.FromSeconds(30)); - Debug.WriteLine(">> delay"); - await Task.Delay(3000); // wait to allow full boot - no idea why this takes longer - - if (info == null) - { - Debug.WriteLine(">> query device info"); - info = _connection.Device.DeviceInfo; - } - - Debug.WriteLine(">> flashing ESP"); - await _connection.Device.FlashEsp(DownloadManager.FirmwareDownloadsFilePath, RequestedVersion); - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - } - CurrentState = UpdateState.AllWritesComplete; - break; - case UpdateState.AllWritesComplete: - try - { - await _connection.Device.ResetMeadow(); - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - break; - CurrentState = UpdateState.VerifySuccess; - case UpdateState.VerifySuccess: - try - { - await _connection.WaitForConnection(TimeSpan.FromSeconds(30)); - await Task.Delay(2000); // wait 2 seconds to allow full boot - info = await _connection.Device.GetDeviceInfo(TimeSpan.FromSeconds(30)); - if (info.MeadowOsVersion != RequestedVersion) - { - // this is a failure - _logger?.LogWarning($"OS version {info.MeadowOsVersion} does not match requested version {RequestedVersion}"); - } - if (info.RuntimeVersion != RequestedVersion) - { - // this is a failure - _logger?.LogWarning($"Runtime version {info.RuntimeVersion} does not match requested version {RequestedVersion}"); - } - if (info.CoProcessorOsVersion != RequestedVersion) - { - // not necessarily an error - _logger?.LogWarning($"Coprocessor version {info.CoProcessorOsVersion} does not match requested version {RequestedVersion}"); - } - } - catch (Exception ex) - { - _logger?.LogError(ex.Message); - CurrentState = UpdateState.Error; - return; - } - CurrentState = UpdateState.UpdateSuccess; - break; - case UpdateState.UpdateSuccess: - _connection.AutoReconnect = true; - _connection.MonitorState = true; - _logger?.LogInformation("Update complete"); - return; - default: - break; - } - - await Task.Delay(1000); - } - } - - private async Task GetFirstAvailableConnection() - { - IMeadowConnection connection = null; - - while (true) - { - connection = _connectionManager.FirstOrDefault(); - if (connection != null) return connection; - await Task.Delay(1000); - } - } - - private async Task GetConnectionDevice(IMeadowConnection connection) - { - if (connection.Device != null) return; - connection.Connect(); - } - - public Task Update(IMeadowConnection? connection, string? version = null) - { - string updateVersion; - if (version == null) - { - // use "latest" - updateVersion = FirmwareManager.GetLocalLatestFirmwareVersion(); - } - else - { - // verify the version requested is valid - var build = FirmwareManager.GetAllLocalFirmwareBuilds().FirstOrDefault(b => b.Version == version); - if (build == null) - { - throw new Exception($"Unknown build: '{version}'"); - } - updateVersion = build.Version; - } - - RequestedVersion = updateVersion; - - if (connection == null) - { - // assume DFU mode startup - CurrentState = UpdateState.EnteringDFUMode; - } - else - { - _connection = connection; - _connection.AutoReconnect = false; - _connection.MonitorState = false; - CurrentState = UpdateState.NotStarted; - } - - return Task.Run(StateMachine); - } - } -} diff --git a/Meadow.CLI.Core/Globals.cs b/Meadow.CLI.Core/Globals.cs deleted file mode 100644 index 26f1b897..00000000 --- a/Meadow.CLI.Core/Globals.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using Microsoft.Extensions.Logging; -global using Microsoft.Extensions.Logging.Abstractions; \ No newline at end of file diff --git a/Meadow.CLI.Core/Identity/IdentityManager.cs b/Meadow.CLI.Core/Identity/IdentityManager.cs deleted file mode 100644 index 746a69e9..00000000 --- a/Meadow.CLI.Core/Identity/IdentityManager.cs +++ /dev/null @@ -1,278 +0,0 @@ -using CredentialManagement; -using IdentityModel.Client; -using IdentityModel.OidcClient; -using Microsoft.Extensions.Configuration; -using Microsoft.IdentityModel.Logging; -using System; -using System.Diagnostics; -using System.Linq; -using System.Net; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Identity -{ - - public class IdentityManager - { - public readonly string WlRefreshCredentialName = "WL:Identity:Refresh"; - private readonly string authority = "https://identity.wildernesslabs.co/oauth2/default"; - private readonly string redirectUri = "http://localhost:8877/"; - private readonly string clientId = "0oa3axsuyupb7J6E15d6"; - private readonly ILogger _logger; - private IConfiguration _config; - - public IdentityManager(IConfiguration config, ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger("IdentityManager"); - _config = config; - } - - /// - /// Kick off login - /// - /// - public async Task Login(string host, CancellationToken cancellationToken = default) - { - try - { - if (string.IsNullOrEmpty(host)) - { - host = _config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]; - } - - var client = await GetOidcClient(); - - using (var http = new HttpListener()) - { - http.Prefixes.Add(redirectUri); - http.Start(); - - // generated login url with PKCE - var state = await client.PrepareLoginAsync(cancellationToken: cancellationToken); - - OpenBrowser(state.StartUrl); - - var context = await http.GetContextAsync(); - var raw = context.Request.RawUrl; - context.Response.StatusCode = 302; - context.Response.AddHeader("Location", host); - context.Response.Close(); - - var result = await client.ProcessResponseAsync(raw, state, cancellationToken: cancellationToken); - - if (result.IsError) - { - _logger.LogError(result.Error); - } - else - { - var email = result.User.Claims.SingleOrDefault(x => x.Type == "email")?.Value; - if (string.IsNullOrWhiteSpace(email)) - { - _logger.LogWarning("Unable to get email address"); - } - else - { - // saving only the refresh token since the access token is too large - SaveCredential(WlRefreshCredentialName, email!, result.RefreshToken); - } - } - return !result.IsError; - } - } - catch (Exception ex) - { - _logger.LogError(ex, "An error occurred"); - return false; - } - } - - public void Logout() - { - DeleteCredential(WlRefreshCredentialName); - } - - /// - /// Get access token through a token refresh - /// - /// - public async Task GetAccessToken(CancellationToken cancellationToken = default) - { - string refreshToken = string.Empty; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - refreshToken = GetCredentials(WlRefreshCredentialName).password; - } - else - { - _logger.LogWarning("Unsupported OS detected."); - throw new NotSupportedException(); - } - - if (!string.IsNullOrEmpty(refreshToken)) - { - var client = await GetOidcClient(); - var result = await client.RefreshTokenAsync(refreshToken, cancellationToken: cancellationToken); - return result.AccessToken; - } - else - { - return string.Empty; - } - } - - /// - /// Get the stored credentials - /// - /// - /// - public (string username, string password) GetCredentials(string credentialName) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var cred = new Credential() { Target = credentialName }; - if (cred.Load()) - { - return (cred.Username, cred.Password); - } - else - { - return (string.Empty, string.Empty); - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - using (var libSecret = new LibSecret("WildernessLabs", credentialName)) - { - //Username & Password delimited with a space. String split, and returned as a tuple. - return libSecret.GetSecret().Split(' ') switch { var a => (a[0], a[1]) }; - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return Keychain.Query(credentialName); - } - else - { - _logger.LogWarning("Unsupported OS detected."); - throw new NotSupportedException(); - } - } - - private async Task GetOidcClient() - { - var options = new OidcClientOptions - { - Authority = authority, - ClientId = clientId, - RedirectUri = redirectUri, - Policy = new Policy - { - Discovery = new DiscoveryPolicy - { - ValidateEndpoints = false - } - }, - Scope = "openid email profile groups offline_access", - Flow = OidcClientOptions.AuthenticationFlow.AuthorizationCode, - ResponseMode = OidcClientOptions.AuthorizeResponseMode.Redirect, - }; - IdentityModelEventSource.ShowPII = true; - return new OidcClient(options); - } - - public void DeleteCredential(string credentialName) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var cred = new Credential() { Target = credentialName }; - cred.Delete(); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - using (var libSecret = new LibSecret("WildernessLabs", credentialName)) - { - libSecret.ClearSecret(); - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - Keychain.Delete(credentialName); - } - else - { - _logger.LogWarning("Unsupported OS detected."); - throw new NotSupportedException(); - } - } - - public bool SaveCredential(string credentialName, string username, string password) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var credential = new Credential() - { - Password = password, - Type = CredentialType.Generic, - PersistanceType = PersistanceType.LocalComputer, - Target = credentialName, - Username = username, - }; - return credential.Save(); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - using (var libSecret = new LibSecret("WildernessLabs", credentialName)) - { - //Username & Password delimited with a space. - libSecret.SetSecret($"{username} {password}"); - return true; - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - // delete first in case it already exists - Keychain.Delete(credentialName); - return Keychain.Add(credentialName, username, password); - } - else - { - _logger.LogWarning("Unsupported OS detected."); - throw new NotSupportedException(); - } - } - - private void OpenBrowser(string url) - { - try - { - Process.Start(url); - } - catch - { - // hack because of this: https://github.com/dotnet/corefx/issues/10361 - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - url = url.Replace("&", "^&"); - Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - Process.Start("xdg-open", url); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - Process.Start("open", url); - } - else - { - _logger.LogWarning("Unsupported OS detected."); - throw new NotSupportedException(); - } - } - } - } -} diff --git a/Meadow.CLI.Core/Identity/Keychain.cs b/Meadow.CLI.Core/Identity/Keychain.cs deleted file mode 100644 index d9300c6c..00000000 --- a/Meadow.CLI.Core/Identity/Keychain.cs +++ /dev/null @@ -1,226 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Meadow.CLI.Core.Identity -{ - static class Keychain - { - const string libSystem = "/usr/lib/libSystem.dylib"; - const string SecurityFramework = "/System/Library/Frameworks/Security.framework/Security"; - const string CoreFoundationFramework = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"; - - const uint kCFStringEncodingUTF8 = 0x08000100; - - static IntPtr securityHandle; - static IntPtr kSecClass; - static IntPtr kSecClassGenericPassword; - static IntPtr kSecAttrLabel; - static IntPtr kSecAttrAccount; - static IntPtr kSecValueData; - static IntPtr kSecReturnAttributes; - static IntPtr kSecReturnData; - - static IntPtr cfHandle; - static IntPtr kCFBooleanTrue; - static IntPtr kCFTypeDictionaryKeyCallBacks; - static IntPtr kCFTypeDictionaryValueCallBacks; - - static void Init() - { - if (securityHandle != IntPtr.Zero) - return; - - securityHandle = dlopen(SecurityFramework, 0); - if (securityHandle == IntPtr.Zero) - throw new Exception($"Failed to dlopen {SecurityFramework}"); - - cfHandle = dlopen(CoreFoundationFramework, 0); - if (cfHandle == IntPtr.Zero) - throw new Exception($"Failed to dlopen {CoreFoundationFramework}"); - - kSecClass = GetConstant(securityHandle, "kSecClass"); - kSecClassGenericPassword = GetConstant(securityHandle, "kSecClassGenericPassword"); - kSecAttrLabel = GetConstant(securityHandle, "kSecAttrLabel"); - kSecAttrAccount = GetConstant(securityHandle, "kSecAttrAccount"); - kSecValueData = GetConstant(securityHandle, "kSecValueData"); - kSecReturnAttributes = GetConstant(securityHandle, "kSecReturnAttributes"); - kSecReturnData = GetConstant(securityHandle, "kSecReturnData"); - - kCFBooleanTrue = GetConstant(cfHandle, "kCFBooleanTrue"); - kCFTypeDictionaryKeyCallBacks = GetConstant(cfHandle, "kCFTypeDictionaryKeyCallBacks", false); - kCFTypeDictionaryValueCallBacks = GetConstant(cfHandle, "kCFTypeDictionaryValueCallBacks", false); - } - - static IntPtr GetConstant(IntPtr handle, string symbol, bool deref = true) - { - var ptr = dlsym(handle, symbol); - if (ptr == IntPtr.Zero) - throw new EntryPointNotFoundException(symbol); - return deref ? Marshal.ReadIntPtr(ptr) : ptr; - } - - public static unsafe bool Add(string label, string username, string password) - { - Init(); - var cfLabel = CFStringCreateWithCharacters(IntPtr.Zero, label, (IntPtr)label.Length); - try { - var cfUsername = CFStringCreateWithCharacters(IntPtr.Zero, username, (IntPtr)username.Length); - try { - var cfPassword = CFStringCreateWithCharacters(IntPtr.Zero, password, (IntPtr)password.Length); - try { - var cfPasswordData = CFStringCreateExternalRepresentation(IntPtr.Zero, cfPassword, kCFStringEncodingUTF8, 0); - try { - var keys = stackalloc IntPtr [4]; - var values = stackalloc IntPtr [4]; - keys[0] = kSecClass; - values[0] = kSecClassGenericPassword; - keys[1] = kSecAttrLabel; - values[1] = cfLabel; - keys[2] = kSecAttrAccount; - values [2] = cfUsername; - keys [3] = kSecValueData; - values [3] = cfPasswordData; - var dict = CFDictionaryCreate(IntPtr.Zero, keys, values, 4, kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks); - try { - var result = SecItemAdd(dict, IntPtr.Zero); - //if (result != 0) - // throw new Exception($"SecItemAdd failed with {result}"); - return result == 0; - } finally { - CFRelease(dict); - } - } finally { - CFRelease(cfPasswordData); - } - } finally { - CFRelease(cfPassword); - } - } finally { - CFRelease(cfUsername); - } - } finally { - CFRelease(cfLabel); - } - } - - static unsafe IntPtr CreateQueryDict(string label) - { - Init(); - var cfLabel = CFStringCreateWithCharacters(IntPtr.Zero, label, (IntPtr)label.Length); - try { - var keys = stackalloc IntPtr [4]; - var values = stackalloc IntPtr [4]; - keys [0] = kSecClass; - values [0] = kSecClassGenericPassword; - keys [1] = kSecAttrLabel; - values [1] = cfLabel; - keys [2] = kSecReturnAttributes; - values [2] = kCFBooleanTrue; - keys [3] = kSecReturnData; - values [3] = kCFBooleanTrue; - return CFDictionaryCreate(IntPtr.Zero, keys, values, 4, kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks); - } finally { - CFRelease(cfLabel); - } - } - - public static unsafe (string username, string password) Query(string label) - { - var dict = CreateQueryDict(label); - try { - IntPtr data; - var result = SecItemCopyMatching(dict, out data); - if (result == -25300/*errSecItemNotFound*/) - return (string.Empty, string.Empty); - if (result != 0) - throw new Exception($"SecItemCopyMatching failed with {result}"); - var cfUsername = CFDictionaryGetValue(data, kSecAttrAccount); - var cfPasswordData = CFDictionaryGetValue(data, kSecValueData); - var cfPassword = CFStringCreateFromExternalRepresentation(IntPtr.Zero, cfPasswordData, kCFStringEncodingUTF8); - try { - var username = cfUsername == IntPtr.Zero ? string.Empty : GetCFString(cfUsername); - var password = cfPassword == IntPtr.Zero ? string.Empty : GetCFString(cfPassword); - return (username, password); - } finally { - CFRelease(cfPassword); - } - } finally { - CFRelease(dict); - } - } - - public static bool Delete(string label) - { - var dict = CreateQueryDict(label); - try { - return SecItemDelete(dict) == 0; - } finally { - CFRelease (dict); - } - } - - static string GetCFString(IntPtr handle) - { - var len = (int)CFStringGetLength(handle); - var buf = Marshal.AllocHGlobal(len * 2); - try { - CFStringGetCharacters(handle, new CFRange { Location = (IntPtr)0, Length = (IntPtr)len }, buf); - return Marshal.PtrToStringUni(buf, len); - } finally { - Marshal.FreeHGlobal(buf); - } - } - - #region dlfcn - [DllImport (libSystem)] - static extern IntPtr dlopen(string path, int mode); - - [DllImport (libSystem)] - static extern IntPtr dlsym(IntPtr handle, string symbol); - #endregion - - #region CoreFoundation - [DllImport(CoreFoundationFramework)] - unsafe static extern IntPtr/*CFDictionaryRef*/ CFDictionaryCreate(IntPtr/*CFAllocatorRef*/ allocator, IntPtr* keys, IntPtr* values, long numValues, IntPtr/*const CFDictionaryKeyCallBacks**/ keyCallBacks, IntPtr/*const CFDictionaryValueCallBacks**/ valueCallBacks); - - [DllImport(CoreFoundationFramework)] - static extern IntPtr/*const void**/ CFDictionaryGetValue(IntPtr/*CFDictionaryRef*/ theDict, IntPtr/*const void**/ key); - - [DllImport(CoreFoundationFramework, CharSet = CharSet.Unicode)] - extern static IntPtr CFStringCreateWithCharacters(IntPtr/*CFAllocatorRef*/ allocator, string str, IntPtr count); - - [DllImport(CoreFoundationFramework)] - extern static IntPtr CFStringGetLength(IntPtr handle); - - [StructLayout(LayoutKind.Sequential)] - struct CFRange - { - public IntPtr Location; - public IntPtr Length; - } - - [DllImport(CoreFoundationFramework)] - extern static IntPtr CFStringGetCharacters(IntPtr handle, CFRange range, IntPtr buffer); - - [DllImport(CoreFoundationFramework)] - extern static IntPtr/*CFDataRef*/ CFStringCreateExternalRepresentation(IntPtr/*CFAllocatorRef*/ alloc, IntPtr/*CFStringRef*/ theString, uint encoding, byte lossByte); - - [DllImport(CoreFoundationFramework)] - extern static IntPtr/*CFStringRef*/ CFStringCreateFromExternalRepresentation(IntPtr/*CFAllocatorRef*/ alloc, IntPtr/*CFDataRef*/ data, uint encoding); - - [DllImport (CoreFoundationFramework)] - extern static void CFRelease(IntPtr obj); - #endregion - - #region Keychain - [DllImport(SecurityFramework)] - static extern int/*OSStatus*/ SecItemAdd(IntPtr/*CFDictionaryRef*/ attributes, IntPtr/*CFTypeRef _Nullable* */ result); - - [DllImport(SecurityFramework)] - static extern int/*OSStatus*/ SecItemCopyMatching(IntPtr/*CFDictionaryRef*/ query, out IntPtr/*CFTypeRef _Nullable* */ result); - - [DllImport (SecurityFramework)] - static extern int/*OSStatus*/ SecItemDelete(IntPtr/*CFDictionaryRef*/ query); - #endregion - } -} diff --git a/Meadow.CLI.Core/Identity/LibSecret.cs b/Meadow.CLI.Core/Identity/LibSecret.cs deleted file mode 100644 index d89d75f1..00000000 --- a/Meadow.CLI.Core/Identity/LibSecret.cs +++ /dev/null @@ -1,112 +0,0 @@ -//Password store, using libSecret, commonly found on Linux systems. - -using System; -using System.Runtime.InteropServices; - -namespace Meadow.CLI.Core.Identity -{ - public class LibSecret : IDisposable - { - - internal struct GError - { - public uint Domain; - public int Code; - public string Message; - } - - public enum AttributeType - { - STRING = 0, - INTEGER = 1, - BOOLEAN = 2, - } - - public enum SchemaFlags - { - NONE = 0, - DONT_MATCH_NAME = 2, - } - - const string COLLECTION_SESSION = null; - const string serviceLabel = "service"; - const string accountLabel = "account"; - - public IntPtr intPt { get; private set; } - public string Service { get; private set; } - public string Account { get; private set; } - - public LibSecret(String service, String account) - { - Service = service; - Account = account; - intPt = secret_schema_new("org.freedesktop.Secret.Generic", - (int)SchemaFlags.DONT_MATCH_NAME, - serviceLabel, - (int)AttributeType.STRING, - accountLabel, - (int)AttributeType.STRING,IntPtr.Zero); - } - - public void SetSecret(String password) - { - _ = secret_password_store_sync(intPt, COLLECTION_SESSION, $"{Service}/{Account}", password, IntPtr.Zero, out IntPtr errorPtr, serviceLabel, Service, accountLabel, Account, IntPtr.Zero); - HandleError(errorPtr, "An error was encountered while writing secret to keyring"); - } - - public String GetSecret() - { - IntPtr passwordPtr = secret_password_lookup_sync(intPt, IntPtr.Zero, out IntPtr errorPtr, serviceLabel, Service, accountLabel, Account, IntPtr.Zero); - HandleError(errorPtr, "An error was encountered while reading secret from keyring"); - return passwordPtr != IntPtr.Zero ? Marshal.PtrToStringAnsi(passwordPtr) : null; - } - - public void ClearSecret() - { - _ = secret_password_clear_sync(intPt, IntPtr.Zero, out IntPtr errorPtr, serviceLabel, Service, accountLabel, Account, IntPtr.Zero); - HandleError(errorPtr, "An error was encountered while clearing secret from keyring "); - } - - public void Dispose() - { - if (intPt != IntPtr.Zero) secret_schema_unref(intPt); - } - - private static void HandleError(IntPtr errorPtr, string errorMessage) - { - if (errorPtr == IntPtr.Zero) - { - return; - } - - GError error; - try - { - error = Marshal.PtrToStructure(errorPtr); - } - catch (Exception ex) - { - throw new InvalidOperationException($"An exception was encountered while processing libsecret error: {ex}", ex); - } - - throw new InvalidOperationException($"{errorMessage}, domain:'{error.Domain}', code:'{error.Code}', message:'{error.Message}'"); - } - - [DllImport("libsecret-1.so.0", CallingConvention = CallingConvention.StdCall)] - static extern void secret_schema_unref (IntPtr schema); - - [DllImport("libsecret-1.so.0", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] - static extern IntPtr secret_password_lookup_sync(IntPtr schema, IntPtr cancellable, out IntPtr error, string attribute1Type, string attribute1Value, string attribute2Type, string attribute2Value, IntPtr end); - - [DllImport("libsecret-1.so.0", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] - static extern int secret_password_store_sync(IntPtr schema, string collection, string label, string password, IntPtr cancellable, out IntPtr error, string attribute1Type, string attribute1Value, string attribute2Type, string attribute2Value, IntPtr end); - - [DllImport("libsecret-1.so.0", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] - static extern int secret_password_clear_sync(IntPtr schema, IntPtr cancellable, out IntPtr error, string attribute1Type, string attribute1Value, string attribute2Type, string attribute2Value, IntPtr end); - - [DllImport("libsecret-1.so.0", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)] - static extern IntPtr secret_schema_new(string name, int flags, string attribute1, int attribute1Type, string attribute2, int attribute2Type, IntPtr end); - - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Dfu/DfuContext.cs b/Meadow.CLI.Core/Internals/Dfu/DfuContext.cs deleted file mode 100644 index 95163a63..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/DfuContext.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using DfuSharp; - -namespace MeadowCLI -{ - public class DfuContext - { - private List validVendorIDs = new List - { - 0x22B1, // secret labs - 0x1B9F, // ghi - 0x05A, // who knows - 0x0483 // bootloader - }; - - // --------------------------- INSTANCE - public static DfuContext Current; - - public static void Init() - { - Current = new DfuContext(); - Current._context = new Context(); - } - - public static void Dispose() - { - Current._context.Dispose(); - } - // --------------------------- INSTANCE - - private Context _context; - - public List GetDevices() - { - return _context.GetDfuDevices(validVendorIDs); - } - - public bool HasCapability(Capabilities caps) - { - return _context.HasCapability(caps); - } - - public void BeginListeningForHotplugEvents() - { - _context.BeginListeningForHotplugEvents(); - } - - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Dfu/DfuSharp.cs b/Meadow.CLI.Core/Internals/Dfu/DfuSharp.cs deleted file mode 100644 index 7f42d446..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/DfuSharp.cs +++ /dev/null @@ -1,827 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace DfuSharp -{ - enum Consts - { - USB_DT_DFU = 0x21 - } - - public enum LogLevel - { - None = 0, - Error, - Warning, - Info, - Debug - } - - public delegate void HotplugCallback(IntPtr ctx, IntPtr device, HotplugEventType eventType, IntPtr userData); - - - class NativeMethods - { - - const string LIBUSB_LIBRARY = "libusb-1.0.dll"; - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_init(ref IntPtr ctx); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern void libusb_exit(IntPtr ctx); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern void libusb_set_debug(IntPtr ctx, LogLevel level); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_get_device_list(IntPtr ctx, ref IntPtr list); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_free_device_list(IntPtr list, int free_devices); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_open(IntPtr dev, ref IntPtr handle); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_close(IntPtr handle); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_claim_interface(IntPtr dev, int interface_number); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting); - - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout); - - /// - /// Whether or not the USB supports a particular feature. - /// - /// nonzero if the running library has the capability, 0 otherwise - /// Capability. - [DllImport(LIBUSB_LIBRARY)] - internal static extern int libusb_has_capability(Capabilities capability); - - - [DllImport(LIBUSB_LIBRARY)] - internal static extern ErrorCodes libusb_hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, - int vendorID, int productID, int deviceClass, - HotplugCallback callback, IntPtr userData, - out IntPtr callbackHandle); - [DllImport(LIBUSB_LIBRARY)] - internal static extern void libusb_hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle); - - } - - [Flags] - public enum HotplugEventType : uint - { - /** A device has been plugged in and is ready to use */ - //LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED - DeviceArrived = 0x01, - - /** A device has left and is no longer available. - * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device. - * It is safe to call libusb_get_device_descriptor on a device that has left */ - //LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT - DeviceLeft = 0x02 - } - - [Flags] - public enum HotplugFlags : uint - { - /** Default value when not using any flags. */ - //LIBUSB_HOTPLUG_NO_FLAGS = 0, - DefaultNoFlags = 0, - - /** Arm the callback and fire it for all matching currently attached devices. */ - //LIBUSB_HOTPLUG_ENUMERATE - EnumerateNow = 1 << 0, - } - - [Flags] - public enum Capabilities : uint - { - /** The libusb_has_capability() API is available. */ - //LIBUSB_CAP_HAS_CAPABILITY - HasCapabilityAPI = 0x0000, - /** Hotplug support is available on this platform. */ - //LIBUSB_CAP_HAS_HOTPLUG - SupportsHotplug = 0x0001, - /** The library can access HID devices without requiring user intervention. - * Note that before being able to actually access an HID device, you may - * still have to call additional libusb functions such as - * \ref libusb_detach_kernel_driver(). */ - //LIBUSB_CAP_HAS_HID_ACCESS - SupportsHidDevices = 0x0100, - /** The library supports detaching of the default USB driver, using - * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */ - //LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER - SupportsKernalDriverDetaching = 0x0101 - } - - public enum ErrorCodes : int - { - /** Success (no error) */ - Success = 0, - - /** Input/output error */ - IOError = -1, - - /** Invalid parameter */ - InvalidParamter = -2, - - /** Access denied (insufficient permissions) */ - AccessDenied = -3, - - /** No such device (it may have been disconnected) */ - NoSuchDevice = -4, - - /** Entity not found */ - EntityNotFound = -5, - - /** Resource busy */ - ResourceBusy = -6, - - /** Operation timed out */ - OperationTimedout = -7, - - /** Overflow */ - Overflow = -8, - - /** Pipe error */ - PipeError = -9, - - /** System call interrupted (perhaps due to signal) */ - SystemCallInterrupted = -10, - - /** Insufficient memory */ - InsufficientMemory = -11, - - /** Operation not supported or unimplemented on this platform */ - OperationNotSupported = -12, - - /* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the - message strings in strerror.c when adding new error codes here. */ - - /** Other error */ - OtherError = -99, - }; - - struct DeviceDescriptor - { - public byte bLength; - public byte bDescriptorType; - public ushort bcdUSB; - public byte bDeviceClass; - public byte bDeviceSubClass; - public byte bDeviceProtocol; - public byte bMaxPacketSize0; - public ushort idVendor; - public ushort idProduct; - public ushort bcdDevice; - public byte iManufacturer; - public byte iProduct; - public byte iSerialNumber; - public byte bNumConfigurations; - } - - struct ConfigDescriptor - { - public byte bLength; - public byte bDescriptorType; - public ushort wTotalLength; - public byte bNumInterfaces; - public byte bConfigurationValue; - public byte iConfiguration; - public byte bmAttributes; - public byte MaxPower; - public IntPtr interfaces; - public IntPtr extra; - public int extra_length; - } - - struct @Interface - { - public IntPtr altsetting; - public int num_altsetting; - - public InterfaceDescriptor[] Altsetting - { - get - { - var descriptors = new InterfaceDescriptor[num_altsetting]; - for (int i = 0; i < num_altsetting; i++) - { - descriptors[i] = Marshal.PtrToStructure(altsetting + i * Marshal.SizeOf()); - } - - return descriptors; - } - } - } - - public struct InterfaceDescriptor - { - public byte bLength; - public byte bDescriptorType; - public byte bInterfaceNumber; - public byte bAlternateSetting; - public byte bNumEndpoints; - public byte bInterfaceClass; - public byte bInterfaceSubClass; - public byte bInterfaceProtocol; - public byte iInterface; - public IntPtr endpoint; - public IntPtr extra; - public int extra_length; - } - - public struct DfuFunctionDescriptor - { - public byte bLength; - public byte bDescriptorType; - public byte bmAttributes; - public ushort wDetachTimeOut; - public ushort wTransferSize; - public ushort bcdDFUVersion; - } - - public delegate void UploadingEventHandler(object sender, UploadingEventArgs e); - - public class UploadingEventArgs : EventArgs - { - public int BytesUploaded { get; private set; } - - public UploadingEventArgs(int bytesUploaded) - { - this.BytesUploaded = bytesUploaded; - } - } - - public class DfuDevice : IDisposable - { - // FIXME: Figure out why dfu_function_descriptor.wTransferSize isn't right and why STM isn't reporting flash_size right - const int flash_size = 0x200000; - const int transfer_size = 0x800; - const int address = 0x08000000; - - IntPtr handle; - InterfaceDescriptor interface_descriptor; - DfuFunctionDescriptor dfu_descriptor; - - public DfuDevice(IntPtr device, InterfaceDescriptor interface_descriptor, DfuFunctionDescriptor dfu_descriptor) - { - this.interface_descriptor = interface_descriptor; - this.dfu_descriptor = dfu_descriptor; - if (NativeMethods.libusb_open(device, ref handle) < 0) - throw new Exception("Error opening device"); - } - - public event UploadingEventHandler Uploading; - - protected virtual void OnUploading(UploadingEventArgs e) - { - if (Uploading != null) - Uploading(this, e); - } - public void ClaimInterface() - { - NativeMethods.libusb_claim_interface(handle, interface_descriptor.bInterfaceNumber); - } - - public void SetInterfaceAltSetting(int alt_setting) - { - NativeMethods.libusb_set_interface_alt_setting(handle, interface_descriptor.bInterfaceNumber, alt_setting); - } - - public void Clear() - { - var state = (byte)0xff; - - while (state != 0 && state != 2) - { - state = GetStatus(handle, interface_descriptor.bInterfaceNumber); - - switch (state) - { - case 5: - case 9: - Abort(handle, interface_descriptor.bInterfaceNumber); - break; - case 10: - ClearStatus(handle, interface_descriptor.bInterfaceNumber); - break; - default: - break; - } - } - } - - public void Upload(FileStream file, int? baseAddress = null) - { - var buffer = new byte[transfer_size]; - - using (var reader = new BinaryReader(file)) - { - for (var pos = 0; pos < flash_size; pos += transfer_size) - { - int write_address = (baseAddress ?? address) + pos; - var count = reader.Read(buffer, 0, transfer_size); - - if (count == 0) - return; - - Upload(buffer, write_address); - } - } - } - - public void Upload(byte[] data, int? baseAddress = null, int altSetting = 0) - { - var mem = Marshal.AllocHGlobal(transfer_size); - - try - { - //Clear(); - //ClaimInterface(); - //if (altSetting != 0) SetInterfaceAltSetting(altSetting); - - for (var pos = 0; pos < flash_size; pos += transfer_size) - { - int write_address = (baseAddress ?? address) + pos; - var count = Math.Min(data.Length - pos, transfer_size); - - if (count <= 0) - return; - - Clear(); - ClaimInterface(); - if (altSetting != 0) SetInterfaceAltSetting(altSetting); - SetAddress(write_address); - Clear(); - - Marshal.Copy(data, pos, mem, count); - - var ret = NativeMethods.libusb_control_transfer( - handle, - 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 1 /*DFU_DNLOAD*/, - 2, - interface_descriptor.bInterfaceNumber, - mem, - (ushort)count, - 5000); - - if (ret < 0) - throw new Exception(string.Format("Error with WRITE_SECTOR: {0}", ret)); - var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - - while (status == 4) - { - Thread.Sleep(100); - status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - } - OnUploading(new UploadingEventArgs(count)); - } - } - finally - { - Marshal.FreeHGlobal(mem); - } - } - - public void Download(FileStream file) - { - var buffer = new byte[transfer_size]; - var mem = Marshal.AllocHGlobal(transfer_size); - - try - { - int count = 0; - ushort transaction = 2; - using (var writer = new BinaryWriter(file)) - { - while (count < flash_size) - { - Clear(); - ClaimInterface(); - - int ret = NativeMethods.libusb_control_transfer( - handle, - 0x80 /*LIBUSB_ENDPOINT_IN*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 2 /*DFU_UPLOAD*/, - transaction++, - interface_descriptor.bInterfaceNumber, - mem, - transfer_size, - 5000); - if (ret < 0) - throw new Exception(string.Format("Error with DFU_UPLOAD: {0}", ret)); - - count += ret; - Marshal.Copy(mem, buffer, 0, ret); - writer.Write(buffer, 0, ret); - } - } - } - finally - { - Marshal.FreeHGlobal(mem); - } - } - - public void Download(byte[] block, int address, int altSetting = 0) - { - int size = block.Length; - - var mem = Marshal.AllocHGlobal(size); - - try - { - ushort transaction = 2; - - Clear(); - ClaimInterface(); - if (altSetting != 0) SetInterfaceAltSetting(altSetting); - SetAddress(address); - Clear(); - - int ret = NativeMethods.libusb_control_transfer( - handle, - 0x80 /*LIBUSB_ENDPOINT_IN*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 2 /*DFU_UPLOAD*/, - transaction++, - interface_descriptor.bInterfaceNumber, - mem, - (ushort)size, - 5000); - if (ret < 0) - throw new Exception(string.Format("Error with DFU_UPLOAD: {0}", ret)); - - Marshal.Copy(mem, block, 0, ret); - } - finally - { - Marshal.FreeHGlobal(mem); - Clear(); - } - } - - public void EraseSector(int address) - { - var mem = Marshal.AllocHGlobal(5); - - try - { - Marshal.WriteByte(mem, 0, 0x41); - Marshal.WriteByte(mem, 1, (byte)((address >> 0) & 0xff)); - Marshal.WriteByte(mem, 2, (byte)((address >> 8) & 0xff)); - Marshal.WriteByte(mem, 3, (byte)((address >> 16) & 0xff)); - Marshal.WriteByte(mem, 4, (byte)((address >> 24) & 0xff)); - - - var ret = NativeMethods.libusb_control_transfer( - handle, - 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 1 /*DFU_DNLOAD*/, - 0, - interface_descriptor.bInterfaceNumber, - mem, - 5, - 5000); - - if (ret < 0) - throw new Exception(string.Format("Error with ERASE_SECTOR: {0}", ret)); - - var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - - while (status == 4) - { - Thread.Sleep(100); - status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - } - } - finally - { - Marshal.FreeHGlobal(mem); - } - } - - public void Reset() - { - var mem = Marshal.AllocHGlobal(0); - - try - { - var ret = NativeMethods.libusb_control_transfer( - handle, - 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 1 /*DFU_DNLOAD*/, - 0, - interface_descriptor.bInterfaceNumber, - mem, - 0, - 5000); - - if (ret < 0) - throw new Exception(string.Format("Error with RESET: {0}", ret)); - - var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - - while (status == 4) - { - Thread.Sleep(100); - status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - } - } - finally - { - Marshal.FreeHGlobal(mem); - } - } - - public void SetAddress(int address) - { - var mem = Marshal.AllocHGlobal(5); - - try - { - Marshal.WriteByte(mem, 0, 0x21); - Marshal.WriteByte(mem, 1, (byte)((address >> 0) & 0xff)); - Marshal.WriteByte(mem, 2, (byte)((address >> 8) & 0xff)); - Marshal.WriteByte(mem, 3, (byte)((address >> 16) & 0xff)); - Marshal.WriteByte(mem, 4, (byte)((address >> 24) & 0xff)); - - - var ret = NativeMethods.libusb_control_transfer( - handle, - 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 1 /*DFU_DNLOAD*/, - 0, - interface_descriptor.bInterfaceNumber, - mem, - 5, - 5000); - - if (ret < 0) - throw new Exception(string.Format("Error with ERASE_SECTOR: {0}", ret)); - - var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - - while (status == 4) - { - Thread.Sleep(100); - status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - } - } - finally - { - Marshal.FreeHGlobal(mem); - } - } - - static byte GetStatus(IntPtr dev, ushort interface_number) - { - var buffer = Marshal.AllocHGlobal(6); - - try - { - int ret = NativeMethods.libusb_control_transfer( - dev, - 0x80 /*LIBUSB_ENDPOINT_IN*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 3 /*DFU_GETSTATUS*/, - 0, - interface_number, - buffer, - 6, - 5000); - - if (ret == 6) - return Marshal.ReadByte(buffer, 4); - - return 0xff; - } - finally - { - Marshal.FreeHGlobal(buffer); - } - } - - static void Abort(IntPtr dev, ushort interface_number) - { - int ret = NativeMethods.libusb_control_transfer( - dev, - 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 6 /*DFU_ABORT*/, - 0, - interface_number, - IntPtr.Zero, - 0, - 5000); - } - static void ClearStatus(IntPtr dev, ushort interface_number) - { - int ret = NativeMethods.libusb_control_transfer( - dev, - 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, - 4 /*DFU_GETSTATUS*/, - 0, - interface_number, - IntPtr.Zero, - 0, - 5000); - } - public void Dispose() - { - NativeMethods.libusb_close(handle); - } - } - - public class Context : IDisposable - { - public event EventHandler DeviceConnected = delegate { }; - - // doing this here so its lifecycle is tied to the class - protected HotplugCallback _hotplugCallbackHandler; - - IntPtr _callbackHandle = IntPtr.Zero; - - - IntPtr handle; - public Context(LogLevel debug_level = LogLevel.None) - { - var ret = NativeMethods.libusb_init(ref handle); - - NativeMethods.libusb_set_debug(handle, debug_level); - if (ret != 0) - throw new Exception(string.Format("Error: {0} while trying to initialize libusb", ret)); - - // instantiate our callback handler - //this._hotplugCallbackHandler = new HotplugCallback(HandleHotplugCallback); - } - - public void Dispose() - { - //this.StopListeningForHotplugEvents(); // not needed, they're automatically deregistered in libusb_exit. - NativeMethods.libusb_exit(handle); - } - - public List GetDfuDevices(List idVendors) - { - var list = IntPtr.Zero; - var dfu_devices = new List(); - var ret = NativeMethods.libusb_get_device_list(handle, ref list); - - if (ret < 0) - throw new Exception(string.Format("Error: {0} while trying to get the device list", ret)); - - var devices = new IntPtr[ret]; - Marshal.Copy(list, devices, 0, ret); - - // This is awful nested looping -- we should fix it. - for (int i = 0; i < ret; i++) - { - var device_descriptor = new DeviceDescriptor(); - var ptr = IntPtr.Zero; - - if (NativeMethods.libusb_get_device_descriptor(devices[i], ref device_descriptor) != 0) - continue; - - //if (!idVendors.Contains(device_descriptor.idVendor)) - // continue; - - for (int j = 0; j < device_descriptor.bNumConfigurations; j++) - { - var ret2 = NativeMethods.libusb_get_config_descriptor(devices[i], (ushort)j, out ptr); - - if (ret2 < 0) - continue; - //throw new Exception(string.Format("Error: {0} while trying to get the config descriptor", ret2)); - - var config_descriptor = Marshal.PtrToStructure(ptr); - - for (int k = 0; k < config_descriptor.bNumInterfaces; k++) - { - var p = config_descriptor.interfaces + j * Marshal.SizeOf<@Interface>(); - - if (p == IntPtr.Zero) - continue; - - var @interface = Marshal.PtrToStructure<@Interface>(p); - for (int l = 0; l < @interface.num_altsetting; l++) - { - var interface_descriptor = @interface.Altsetting[l]; - - // Ensure this is a DFU descriptor - if (interface_descriptor.bInterfaceClass != 0xfe || interface_descriptor.bInterfaceSubClass != 0x1) - continue; - - var dfu_descriptor = FindDescriptor(interface_descriptor.extra, interface_descriptor.extra_length, (byte)Consts.USB_DT_DFU); - if (dfu_descriptor != null) - dfu_devices.Add(new DfuDevice(devices[i], interface_descriptor, dfu_descriptor.Value)); - } - } - } - } - - NativeMethods.libusb_free_device_list(list, 1); - return dfu_devices; - } - - static DfuFunctionDescriptor? FindDescriptor(IntPtr desc_list, int list_len, byte desc_type) - { - int p = 0; - - while (p + 1 < list_len) - { - int len, type; - - len = Marshal.ReadByte(desc_list, p); - type = Marshal.ReadByte(desc_list, p + 1); - - if (type == desc_type) - { - return Marshal.PtrToStructure(desc_list + p); - } - p += len; - } - - return null; - } - - public bool HasCapability(Capabilities caps) - { - return NativeMethods.libusb_has_capability(caps) == 0 ? false : true; - } - - public void BeginListeningForHotplugEvents() - { - if (_callbackHandle != IntPtr.Zero) - { - Debug.WriteLine("Already listening for events."); - return; - } - - if (!HasCapability(Capabilities.HasCapabilityAPI)) - { - Debug.WriteLine("Capability API not supported."); - return; - } - - if (!HasCapability(Capabilities.SupportsHotplug)) - { - Debug.WriteLine("Hotplug notifications not supported."); - return; - } - - int vendorID = -1; // wildcard match (all) - int productID = -1; - int deviceClass = -1; - IntPtr userData = IntPtr.Zero; - - ErrorCodes success = NativeMethods.libusb_hotplug_register_callback(this.handle, HotplugEventType.DeviceArrived | HotplugEventType.DeviceLeft, HotplugFlags.DefaultNoFlags, - vendorID, productID, deviceClass, this._hotplugCallbackHandler, userData, out _callbackHandle); - - if (success == ErrorCodes.Success) - { - Debug.WriteLine("Callback registration successful"); - } - else - { - throw new Exception("callback registration failed, error: " + success.ToString()); - } - - } - - public void StopListeningForHotplugEvents() - { - if (_callbackHandle == IntPtr.Zero) - { - Debug.WriteLine("Not listening already."); - return; - } - - NativeMethods.libusb_hotplug_deregister_callback(this.handle, this._callbackHandle); - - } - - public void HandleHotplugCallback(IntPtr ctx, IntPtr device, HotplugEventType eventType, IntPtr userData) - { - Debug.WriteLine("Hotplug Callback called, event type: " + eventType.ToString()); - // raise the event - this.DeviceConnected(this, new EventArgs()); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Dfu/DfuUtils.cs b/Meadow.CLI.Core/Internals/Dfu/DfuUtils.cs deleted file mode 100644 index a044e052..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/DfuUtils.cs +++ /dev/null @@ -1,373 +0,0 @@ -using LibUsbDotNet; -using LibUsbDotNet.LibUsb; -using LibUsbDotNet.Main; -using Meadow.CLI.Core.Exceptions; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Internals.Dfu -{ - public static class DfuUtils - { - static int _osAddress = 0x08000000; - static string _usbStmName = "STM32 BOOTLOADER"; - static int _usbBootLoaderVenderID = 1155; // Equivalent to _usbStmName but for the LibUsbDotNet 3.x - - public static string LastSerialNumber { get; private set; } = ""; - - public static bool CheckForValidDevice() - { - try - { - GetDeviceInBootloaderMode(); - return true; - } - catch (Exception) - { - return false; - } - } -#if WIN_10 - public static UsbRegistry GetDeviceInBootloaderMode() -#else - public static IUsbDevice GetDeviceInBootloaderMode() -#endif - { - var allDevices = GetDevicesInBootloaderMode(); - if (allDevices.Count() > 1) - { - throw new MultipleDfuDevicesException("More than one DFU device found, please connect only one and try again."); - } - - var device = allDevices.SingleOrDefault(); - if (device == null) - { - throw new DeviceNotFoundException("Device not found. Connect a device in bootloader mode. If the device is in bootloader mode, please update the device driver. See instructions at https://wldrn.es/usbdriver"); - } - - return device; - } -#if WIN_10 - public static IEnumerable GetDevicesInBootloaderMode() -#else - public static IEnumerable GetDevicesInBootloaderMode() -#endif - { -#if WIN_10 - - var allDevices = UsbDevice.AllDevices; - IEnumerable ourDevices; - - switch (Environment.OSVersion.Platform) - { - case PlatformID.Win32NT: - ourDevices = allDevices.Where(d => d.DeviceProperties["FriendlyName"].ToString() == _usbStmName); - break; - default: - ourDevices = allDevices.Where(d => d.DeviceProperties["DeviceDesc"].ToString() == _usbStmName); - break; - } - - if (ourDevices.Count() < 1) - { - throw new DeviceNotFoundException("No Devices found. Connect a device in bootloader mode. If the device is in bootloader mode, please update the device driver. See instructions at https://wldrn.es/usbdriver"); - } - return ourDevices; -#else - using (UsbContext context = new UsbContext()) - { - var allDevices = context.List(); - var ourDevices = allDevices.Where(d => d.Info.VendorId == _usbBootLoaderVenderID); - if (ourDevices.Count() < 1) - { - throw new DeviceNotFoundException("No Devices found. Connect a device in bootloader mode. If the device is in bootloader mode, please update the device driver. See instructions at https://wldrn.es/usbdriver"); - } - return ourDevices; - } -#endif - } - -#if WIN_10 - public static string GetDeviceSerial(UsbRegistry device) - { - if (device != null && device.DeviceProperties != null) - { - switch (Environment.OSVersion.Platform) - { - case PlatformID.Win32NT: - var deviceID = device.DeviceProperties["DeviceID"].ToString(); - if (!string.IsNullOrWhiteSpace(deviceID)) - return deviceID.Substring(deviceID.LastIndexOf("\\") + 1); - else - return string.Empty; - default: - return device.DeviceProperties["SerialNumber"].ToString(); - } - } - else - return string.Empty; - } -#else - public static string GetDeviceSerial(IUsbDevice device) - - { - var serialNumber = string.Empty; - - if (device != null) - { - device.Open(); - if (device.IsOpen) - { - serialNumber = device.Info?.SerialNumber; - device.Close(); - } - } - - return serialNumber; - } -#endif - - public enum DfuFlashFormat - { - /// - /// Percentage only - /// - Percent, - /// - /// Full console output, no formatting - /// - Full, - /// - /// Console.WriteLine for CLI - ToDo - remove - /// - ConsoleOut, - } - - static void FormatDfuOutput(string logLine, ILogger? logger, DfuFlashFormat format = DfuFlashFormat.Percent) - { - if(format == DfuFlashFormat.Full) - { - logger?.LogInformation(logLine); - } - else if(format == DfuFlashFormat.Percent) - { - if (logLine.Contains("%")) - { - var operation = logLine.Substring(0, - logLine.IndexOf("\t", StringComparison.Ordinal)).Trim(); - var progressBarEnd = logLine.IndexOf("]", StringComparison.Ordinal) + 1; - var progress = logLine.Substring(progressBarEnd, logLine.IndexOf("%", StringComparison.Ordinal) - progressBarEnd + 1).TrimStart(); - if (progress != "100%") - { - logger?.LogInformation(progress); - } - } - else - { - logger?.LogInformation(logLine); - } - } - else //Console out - { - Console.Write(logLine); - - Console.Write(logLine.Contains("%")?"\r":"\r\n"); - } - } - - public static Task FlashVersion(string version, ILogger? logger = null, DfuFlashFormat format = DfuFlashFormat.Percent) - { - var fileName = Path.Combine(DownloadManager.FirmwarePathForVersion(version), DownloadManager.OsFilename); - - return FlashFile(fileName: fileName, logger: logger, format: format); - } - - public static Task FlashLatest(ILogger? logger = null, DfuFlashFormat format = DfuFlashFormat.Percent) - { - var fileName = Path.Combine(DownloadManager.FirmwareDownloadsFilePath, DownloadManager.OsFilename); - - return FlashFile(fileName: fileName, logger: logger, format: DfuUtils.DfuFlashFormat.ConsoleOut); - } -#if WIN_10 - public static async Task FlashFile(string fileName, UsbRegistry? device = null, ILogger? logger = null, DfuFlashFormat format = DfuFlashFormat.Percent) -#else - public static async Task FlashFile(string fileName, IUsbDevice? device = null, ILogger? logger = null, DfuFlashFormat format = DfuFlashFormat.Percent) -#endif - { - logger ??= NullLogger.Instance; - device ??= GetDeviceInBootloaderMode(); - - if (!File.Exists(fileName)) - { - logger.LogError($"Unable to flash {fileName} - file or folder does not exist"); - return false; - } - - if (!File.Exists(fileName)) - { - logger.LogError($"Unable to find file '{DownloadManager.OsFilename}'. Please specify valid --File or download the latest with: meadow download os"); - return false; - } - else - { - logger.LogInformation($"Flashing OS with {fileName}"); - } - - LastSerialNumber = GetDeviceSerial(device); - - var dfuUtilVersion = new System.Version(GetDfuUtilVersion()); - logger.LogDebug("Detected OS: {os}", RuntimeInformation.OSDescription); - - if (dfuUtilVersion == null) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - logger.LogError("dfu-util not found - to install, run: `meadow install dfu-util` (may require administrator mode)"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - logger.LogError("dfu-util not found - to install run: `brew install dfu-util`"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - logger.LogError("dfu-util not found - install using package manager, for example: `apt install dfu-util` or the equivalent for your Linux distribution"); - } - return false; - } - else if (dfuUtilVersion.CompareTo(new System.Version("0.11")) < 0) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - logger.LogError("dfu-util update required. To update, run in administrator mode: `meadow install dfu-util`"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - logger.LogError("dfu-util update required. To update, run: `brew upgrade dfu-util`"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - logger.LogError("dfu-util update required. To update , run: `apt upgrade dfu-util` or the equivalent for your Linux distribution"); - } - else - { - return false; - } - } - - try - { - var args = $"-a 0 -S {LastSerialNumber} -D \"{fileName}\" -s {_osAddress}:leave"; - - await RunDfuUtil(args, logger, format); - } - catch (Exception ex) - { - logger.LogError($"There was a problem executing dfu-util: {ex.Message}"); - return false; - } - - return true; - } - - static async Task RunDfuUtil(string args, ILogger? logger, DfuFlashFormat format = DfuFlashFormat.Percent) - { - var startInfo = new ProcessStartInfo("dfu-util", args) - { - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = false, - CreateNoWindow = true - }; - using var process = Process.Start(startInfo); - - if (process == null) - { - throw new Exception("Failed to start dfu-util"); - } - - var informationLogger = logger != null - ? Task.Factory.StartNew( - () => - { - var lastProgress = string.Empty; - - while (process.HasExited == false) - { - var logLine = process.StandardOutput.ReadLine(); - // Ignore empty output - if (logLine == null) - continue; - - FormatDfuOutput(logLine, logger, format); - } - }) : Task.CompletedTask; - - var errorLogger = logger != null - ? Task.Factory.StartNew( - () => - { - while (process.HasExited == false) - { - var logLine = process.StandardError.ReadLine(); - logger.LogError(logLine); - } - }) : Task.CompletedTask; - await informationLogger; - await errorLogger; - process.WaitForExit(); - } - - private static string GetDfuUtilVersion() - { - try - { - using (var process = new Process()) - { - process.StartInfo.FileName = "dfu-util"; - process.StartInfo.Arguments = $"--version"; - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardOutput = true; - process.Start(); - - var reader = process.StandardOutput; - string output = reader.ReadLine(); - if (output.StartsWith("dfu-util")) - { - var split = output.Split(new char[] { ' ' }); - if (split.Length == 2) - { - return split[1]; - } - } - - process.WaitForExit(); - return string.Empty; - } - } - catch (Win32Exception ex) - { - switch (ex.NativeErrorCode) - { - case 0x0002: // ERROR_FILE_NOT_FOUND - case 0x0003: // ERROR_PATH_NOT_FOUND - case 0x000F: // ERROR_INVALID_DRIVE - case 0x0014: // ERROR_BAD_UNIT - case 0x001B: // ERROR_SECTOR_NOT_FOUND - case 0x0033: // ERROR_REM_NOT_LIST - case 0x013D: // ERROR_MR_MID_NOT_FOUND - return string.Empty; - - default: - throw; - } - } - } - } -} diff --git a/Meadow.CLI.Core/Internals/Dfu/WIP.DfuContext.cs b/Meadow.CLI.Core/Internals/Dfu/WIP.DfuContext.cs deleted file mode 100644 index 47659d5f..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/WIP.DfuContext.cs +++ /dev/null @@ -1,50 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using DfuSharp; - -//namespace MeadowCLI -//{ -// public class DfuContext -// { -// private List validVendorIDs = new List -// { -// 0x22B1, // secret labs -// 0x1B9F, // ghi -// 0x05A, // who knows -// 0x0483 // bootloader -// }; - -// // --------------------------- INSTANCE -// public static DfuContext Current; - -// public static void Init() -// { -// Current = new DfuContext(); -// Current._context = new Context(); -// } - -// public static void Dispose() -// { -// Current._context.Dispose(); -// } -// // --------------------------- INSTANCE - -// private Context _context; - -// public List GetDevices() -// { -// return _context.GetDfuDevices(validVendorIDs); -// } - -// public bool HasCapability(Capabilities caps) -// { -// return _context.HasCapability(caps); -// } - -// public void BeginListeningForHotplugEvents() -// { -// _context.BeginListeningForHotplugEvents(); -// } - -// } -//} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Dfu/WIP.DfuSharp.cs b/Meadow.CLI.Core/Internals/Dfu/WIP.DfuSharp.cs deleted file mode 100644 index 87b08c06..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/WIP.DfuSharp.cs +++ /dev/null @@ -1,682 +0,0 @@ -//using System; -//using System.IO; -//using System.Threading; -//using System.Collections.Generic; -//using System.Runtime.InteropServices; -//using System.Diagnostics; - -//namespace DfuSharp -//{ -// enum Consts -// { -// USB_DT_DFU = 0x21 -// } - -// public enum LogLevel -// { -// None = 0, -// Error, -// Warning, -// Info, -// Debug -// } - -// public delegate void HotplugCallback(IntPtr ctx, IntPtr device, HotplugEventType eventType, IntPtr userData); - -// [Flags] -// public enum HotplugEventType : uint -// { -// /** A device has been plugged in and is ready to use */ -// //LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED -// DeviceArrived = 0x01, - -// /** A device has left and is no longer available. -// * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device. -// * It is safe to call libusb_get_device_descriptor on a device that has left */ -// //LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT -// DeviceLeft = 0x02 -// } - -// [Flags] -// public enum HotplugFlags : uint -// { -// /** Default value when not using any flags. */ -// //LIBUSB_HOTPLUG_NO_FLAGS = 0, -// DefaultNoFlags = 0, - -// /** Arm the callback and fire it for all matching currently attached devices. */ -// //LIBUSB_HOTPLUG_ENUMERATE -// EnumerateNow = 1 << 0, -// } - -// [Flags] -// public enum Capabilities : uint -// { -// /** The libusb_has_capability() API is available. */ -// //LIBUSB_CAP_HAS_CAPABILITY -// HasCapabilityAPI = 0x0000, -// /** Hotplug support is available on this platform. */ -// //LIBUSB_CAP_HAS_HOTPLUG -// SupportsHotplug = 0x0001, -// /** The library can access HID devices without requiring user intervention. -// * Note that before being able to actually access an HID device, you may -// * still have to call additional libusb functions such as -// * \ref libusb_detach_kernel_driver(). */ -// //LIBUSB_CAP_HAS_HID_ACCESS -// SupportsHidDevices = 0x0100, -// /** The library supports detaching of the default USB driver, using -// * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */ -// //LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER -// SupportsKernalDriverDetaching = 0x0101 -// } - -// public enum ErrorCodes : int -// { -// /** Success (no error) */ -// Success = 0, - -// /** Input/output error */ -// IOError = -1, - -// /** Invalid parameter */ -// InvalidParamter = -2, - -// /** Access denied (insufficient permissions) */ -// AccessDenied = -3, - -// /** No such device (it may have been disconnected) */ -// NoSuchDevice = -4, - -// /** Entity not found */ -// EntityNotFound = -5, - -// /** Resource busy */ -// ResourceBusy = -6, - -// /** Operation timed out */ -// OperationTimedout = -7, - -// /** Overflow */ -// Overflow = -8, - -// /** Pipe error */ -// PipeError = -9, - -// /** System call interrupted (perhaps due to signal) */ -// SystemCallInterrupted = -10, - -// /** Insufficient memory */ -// InsufficientMemory = -11, - -// /** Operation not supported or unimplemented on this platform */ -// OperationNotSupported = -12, - -// /* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the -// message strings in strerror.c when adding new error codes here. */ - -// /** Other error */ -// OtherError = -99, -// }; - -// struct DeviceDescriptor -// { -// public byte bLength; -// public byte bDescriptorType; -// public ushort bcdUSB; -// public byte bDeviceClass; -// public byte bDeviceSubClass; -// public byte bDeviceProtocol; -// public byte bMaxPacketSize0; -// public ushort idVendor; -// public ushort idProduct; -// public ushort bcdDevice; -// public byte iManufacturer; -// public byte iProduct; -// public byte iSerialNumber; -// public byte bNumConfigurations; -// } - -// struct ConfigDescriptor -// { -// public byte bLength; -// public byte bDescriptorType; -// public ushort wTotalLength; -// public byte bNumInterfaces; -// public byte bConfigurationValue; -// public byte iConfiguration; -// public byte bmAttributes; -// public byte MaxPower; -// public IntPtr interfaces; -// public IntPtr extra; -// public int extra_length; -// } - -// struct @Interface -// { -// public IntPtr altsetting; -// public int num_altsetting; - -// public InterfaceDescriptor[] Altsetting { -// get { -// var descriptors = new InterfaceDescriptor[num_altsetting]; -// for (int i = 0; i < num_altsetting; i++) { -// descriptors[i] = Marshal.PtrToStructure(altsetting + i * Marshal.SizeOf()); -// } - -// return descriptors; -// } -// } -// } - -// public struct InterfaceDescriptor -// { -// public byte bLength; -// public byte bDescriptorType; -// public byte bInterfaceNumber; -// public byte bAlternateSetting; -// public byte bNumEndpoints; -// public byte bInterfaceClass; -// public byte bInterfaceSubClass; -// public byte bInterfaceProtocol; -// public byte iInterface; -// public IntPtr endpoint; -// public IntPtr extra; -// public int extra_length; -// } - -// public struct DfuFunctionDescriptor -// { -// public byte bLength; -// public byte bDescriptorType; -// public byte bmAttributes; -// public ushort wDetachTimeOut; -// public ushort wTransferSize; -// public ushort bcdDFUVersion; -// } - -// public delegate void UploadingEventHandler(object sender, UploadingEventArgs e); - -// public class UploadingEventArgs : EventArgs -// { -// public int BytesUploaded { get; private set; } - -// public UploadingEventArgs(int bytesUploaded) -// { -// this.BytesUploaded = bytesUploaded; -// } -// } - -// public class DfuDevice : IDisposable -// { -// // FIXME: Figure out why dfu_function_descriptor.wTransferSize isn't right and why STM isn't reporting flash_size right -// const int flash_size = 0x200000; -// const int transfer_size = 0x800; -// const int address = 0x08000000; - -// IntPtr handle; -// InterfaceDescriptor interface_descriptor; -// DfuFunctionDescriptor dfu_descriptor; - -// public DfuDevice(IntPtr device, InterfaceDescriptor interface_descriptor, DfuFunctionDescriptor dfu_descriptor) -// { -// this.interface_descriptor = interface_descriptor; -// this.dfu_descriptor = dfu_descriptor; -// if (LibUsb.libusb_open(device, ref handle) < 0) -// throw new Exception("Error opening device"); -// } - -// public event UploadingEventHandler Uploading; - -// protected virtual void OnUploading(UploadingEventArgs e) -// { -// if (Uploading != null) -// Uploading(this, e); -// } -// public void ClaimInterface() -// { -// LibUsb.libusb_claim_interface(handle, interface_descriptor.bInterfaceNumber); -// } - -// public void SetInterfaceAltSetting(int alt_setting) -// { -// LibUsb.libusb_set_interface_alt_setting(handle, interface_descriptor.bInterfaceNumber, alt_setting); -// } - -// public void Clear() -// { -// var state = (byte)0xff; - -// while (state != 0 && state != 2) { -// state = GetStatus(handle, interface_descriptor.bInterfaceNumber); - -// switch (state) { -// case 5: -// case 9: -// Abort(handle, interface_descriptor.bInterfaceNumber); -// break; -// case 10: -// ClearStatus(handle, interface_descriptor.bInterfaceNumber); -// break; -// default: -// break; -// } -// } -// } - -// public void Upload(FileStream file, int? baseAddress = null) -// { -// var buffer = new byte[transfer_size]; - -// using (var reader = new BinaryReader(file)) { -// for (var pos = 0; pos < flash_size; pos += transfer_size) { -// int write_address = (baseAddress ?? address) + pos; -// var count = reader.Read(buffer, 0, transfer_size); - -// if (count == 0) -// return; - -// Upload(buffer, write_address); -// } -// } -// } - -// public void Upload(byte[] data, int? baseAddress = null, int altSetting = 0) -// { -// var mem = Marshal.AllocHGlobal(transfer_size); - -// try { -// for (var pos = 0; pos < flash_size; pos += transfer_size) { -// int write_address = (baseAddress ?? address) + pos; -// var count = Math.Min(data.Length - pos, transfer_size); - -// if (count <= 0) -// return; - -// Clear(); -// ClaimInterface(); -// if (altSetting != 0) SetInterfaceAltSetting(altSetting); -// SetAddress(write_address); -// Clear(); - -// Marshal.Copy(data, pos, mem, count); - -// var ret = LibUsb.libusb_control_transfer( -// handle, -// 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 1 /*DFU_DNLOAD*/, -// 2, -// interface_descriptor.bInterfaceNumber, -// mem, -// (ushort)count, -// 5000); - -// if (ret < 0) -// throw new Exception(string.Format("Error with WRITE_SECTOR: {0}", ret)); -// var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - -// while (status == 4) { -// Thread.Sleep(100); -// status = GetStatus(handle, interface_descriptor.bInterfaceNumber); -// } -// OnUploading(new UploadingEventArgs(count)); -// } -// } finally { -// Marshal.FreeHGlobal(mem); -// } -// } - -// public void Download(FileStream file) -// { -// var buffer = new byte[transfer_size]; -// var mem = Marshal.AllocHGlobal(transfer_size); - -// try { -// int count = 0; -// ushort transaction = 2; -// using (var writer = new BinaryWriter(file)) { -// while (count < flash_size) { -// int ret = LibUsb.libusb_control_transfer( -// handle, -// 0x80 /*LIBUSB_ENDPOINT_IN*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 2 /*DFU_UPLOAD*/, -// transaction++, -// interface_descriptor.bInterfaceNumber, -// mem, -// transfer_size, -// 5000); -// if (ret < 0) -// throw new Exception(string.Format("Error with DFU_UPLOAD: {0}", ret)); - -// count += ret; -// Marshal.Copy(mem, buffer, 0, ret); -// writer.Write(buffer, 0, ret); -// } -// } -// } finally { -// Marshal.FreeHGlobal(mem); -// } -// } - -// public void Download(byte[] block, int address, int altSetting = 0) -// { -// int size = block.Length; - -// var mem = Marshal.AllocHGlobal(size); - -// try { -// ushort transaction = 2; - -// Clear(); -// ClaimInterface(); -// if (altSetting != 0) SetInterfaceAltSetting(altSetting); -// SetAddress(address); -// Clear(); - -// int ret = LibUsb.libusb_control_transfer( -// handle, -// 0x80 /*LIBUSB_ENDPOINT_IN*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 2 /*DFU_UPLOAD*/, -// transaction++, -// interface_descriptor.bInterfaceNumber, -// mem, -// (ushort)size, -// 5000); -// if (ret < 0) -// throw new Exception(string.Format("Error with DFU_UPLOAD: {0}", ret)); - -// Marshal.Copy(mem, block, 0, ret); -// } finally { -// Marshal.FreeHGlobal(mem); -// Clear(); -// } -// } - -// public void EraseSector(int address) -// { -// var mem = Marshal.AllocHGlobal(5); - -// try { -// Marshal.WriteByte(mem, 0, 0x41); -// Marshal.WriteByte(mem, 1, (byte)((address >> 0) & 0xff)); -// Marshal.WriteByte(mem, 2, (byte)((address >> 8) & 0xff)); -// Marshal.WriteByte(mem, 3, (byte)((address >> 16) & 0xff)); -// Marshal.WriteByte(mem, 4, (byte)((address >> 24) & 0xff)); - - -// var ret = LibUsb.libusb_control_transfer( -// handle, -// 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 1 /*DFU_DNLOAD*/, -// 0, -// interface_descriptor.bInterfaceNumber, -// mem, -// 5, -// 5000); - -// if (ret < 0) -// throw new Exception(string.Format("Error with ERASE_SECTOR: {0}", ret)); - -// var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - -// while (status == 4) { -// Thread.Sleep(100); -// status = GetStatus(handle, interface_descriptor.bInterfaceNumber); -// } -// } finally { -// Marshal.FreeHGlobal(mem); -// } -// } - -// public void SetAddress(int address) -// { -// var mem = Marshal.AllocHGlobal(5); - -// try { -// Marshal.WriteByte(mem, 0, 0x21); -// Marshal.WriteByte(mem, 1, (byte)((address >> 0) & 0xff)); -// Marshal.WriteByte(mem, 2, (byte)((address >> 8) & 0xff)); -// Marshal.WriteByte(mem, 3, (byte)((address >> 16) & 0xff)); -// Marshal.WriteByte(mem, 4, (byte)((address >> 24) & 0xff)); - - -// var ret = LibUsb.libusb_control_transfer( -// handle, -// 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 1 /*DFU_DNLOAD*/, -// 0, -// interface_descriptor.bInterfaceNumber, -// mem, -// 5, -// 5000); - -// if (ret < 0) -// throw new Exception(string.Format("Error with ERASE_SECTOR: {0}", ret)); - -// var status = GetStatus(handle, interface_descriptor.bInterfaceNumber); - -// while (status == 4) { -// Thread.Sleep(100); -// status = GetStatus(handle, interface_descriptor.bInterfaceNumber); -// } -// } finally { -// Marshal.FreeHGlobal(mem); -// } -// } - -// static byte GetStatus(IntPtr dev, ushort interface_number) -// { -// var buffer = Marshal.AllocHGlobal(6); - -// try { -// int ret = LibUsb.libusb_control_transfer( -// dev, -// 0x80 /*LIBUSB_ENDPOINT_IN*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 3 /*DFU_GETSTATUS*/, -// 0, -// interface_number, -// buffer, -// 6, -// 5000); - -// if (ret == 6) -// return Marshal.ReadByte(buffer, 4); - -// return 0xff; -// } finally { -// Marshal.FreeHGlobal(buffer); -// } -// } - -// static void Abort(IntPtr dev, ushort interface_number) -// { -// int ret = LibUsb.libusb_control_transfer( -// dev, -// 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 6 /*DFU_ABORT*/, -// 0, -// interface_number, -// IntPtr.Zero, -// 0, -// 5000); -// } -// static void ClearStatus(IntPtr dev, ushort interface_number) -// { -// int ret = LibUsb.libusb_control_transfer( -// dev, -// 0x00 /*LIBUSB_ENDPOINT_OUT*/ | (0x1 << 5) /*LIBUSB_REQUEST_TYPE_CLASS*/ | 0x01 /*LIBUSB_RECIPIENT_INTERFACE*/, -// 4 /*DFU_GETSTATUS*/, -// 0, -// interface_number, -// IntPtr.Zero, -// 0, -// 5000); -// } -// public void Dispose() -// { -// LibUsb.libusb_close(handle); -// } -// } - -// public class Context : IDisposable -// { -// public event EventHandler DeviceConnected = delegate { }; - -// // doing this here so its lifecycle is tied to the class -// protected HotplugCallback _hotplugCallbackHandler; - -// IntPtr _callbackHandle = IntPtr.Zero; - - -// IntPtr handle; -// public Context(LogLevel debug_level = LogLevel.None) -// { -// var ret = LibUsb.libusb_init(ref handle); - -// LibUsb.libusb_set_debug(handle, debug_level); -// if (ret != 0) -// throw new Exception(string.Format("Error: {0} while trying to initialize libusb", ret)); - -// // instantiate our callback handler -// //this._hotplugCallbackHandler = new HotplugCallback(HandleHotplugCallback); -// } - -// public void Dispose() -// { -// //this.StopListeningForHotplugEvents(); // not needed, they're automatically deregistered in libusb_exit. -// LibUsb.libusb_exit(handle); -// } - -// public List GetDfuDevices(List idVendors) -// { -// var list = IntPtr.Zero; -// var dfu_devices = new List(); -// var ret = LibUsb.libusb_get_device_list(handle, ref list); - -// if (ret < 0) -// throw new Exception(string.Format("Error: {0} while trying to get the device list", ret)); - -// var devices = new IntPtr[ret]; -// Marshal.Copy(list, devices, 0, ret); - -// // This is awful nested looping -- we should fix it. -// for (int i = 0; i < ret; i++) { -// var device_descriptor = new DeviceDescriptor(); -// var ptr = IntPtr.Zero; - -// if (LibUsb.libusb_get_device_descriptor(devices[i], ref device_descriptor) != 0) -// continue; - -// //if (!idVendors.Contains(device_descriptor.idVendor)) -// // continue; - -// for (int j = 0; j < device_descriptor.bNumConfigurations; j++) { -// var ret2 = LibUsb.libusb_get_config_descriptor(devices[i], (ushort)j, out ptr); - -// if (ret2 < 0) -// continue; -// //throw new Exception(string.Format("Error: {0} while trying to get the config descriptor", ret2)); - -// var config_descriptor = Marshal.PtrToStructure(ptr); - -// for (int k = 0; k < config_descriptor.bNumInterfaces; k++) { -// var p = config_descriptor.interfaces + j * Marshal.SizeOf<@Interface>(); - -// if (p == IntPtr.Zero) -// continue; - -// var @interface = Marshal.PtrToStructure<@Interface>(p); -// for (int l = 0; l < @interface.num_altsetting; l++) { -// var interface_descriptor = @interface.Altsetting[l]; - -// // Ensure this is a DFU descriptor -// if (interface_descriptor.bInterfaceClass != 0xfe || interface_descriptor.bInterfaceSubClass != 0x1) -// continue; - -// var dfu_descriptor = FindDescriptor(interface_descriptor.extra, interface_descriptor.extra_length, (byte)Consts.USB_DT_DFU); -// if (dfu_descriptor != null) -// dfu_devices.Add(new DfuDevice(devices[i], interface_descriptor, dfu_descriptor.Value)); -// } -// } -// } -// } - -// LibUsb.libusb_free_device_list(list, 1); -// return dfu_devices; -// } - -// static DfuFunctionDescriptor? FindDescriptor(IntPtr desc_list, int list_len, byte desc_type) -// { -// int p = 0; - -// while (p + 1 < list_len) { -// int len, type; - -// len = Marshal.ReadByte(desc_list, p); -// type = Marshal.ReadByte(desc_list, p + 1); - -// if (type == desc_type) { -// return Marshal.PtrToStructure(desc_list + p); -// } -// p += len; -// } - -// return null; -// } - -// public bool HasCapability(Capabilities caps) -// { -// return LibUsb.libusb_has_capability(caps) == 0 ? false : true; -// } - -// public void BeginListeningForHotplugEvents() -// { -// if (_callbackHandle != IntPtr.Zero) { -// Debug.WriteLine("Already listening for events."); -// return; -// } - -// if (!HasCapability(Capabilities.HasCapabilityAPI)) { -// Debug.WriteLine("Capability API not supported."); -// return; -// } - -// if (!HasCapability(Capabilities.SupportsHotplug)) { -// Debug.WriteLine("Hotplug notifications not supported."); -// return; -// } - -// int vendorID = -1; // wildcard match (all) -// int productID = -1; -// int deviceClass = -1; -// IntPtr userData = IntPtr.Zero; - -// ErrorCodes success = LibUsb.libusb_hotplug_register_callback(this.handle, HotplugEventType.DeviceArrived | HotplugEventType.DeviceLeft, HotplugFlags.DefaultNoFlags, -// vendorID, productID, deviceClass, this._hotplugCallbackHandler, userData, out _callbackHandle); - -// if (success == ErrorCodes.Success) { -// Debug.WriteLine("Callback registration successful"); -// } else { -// throw new Exception("callback registration failed, error: " + success.ToString()); -// } - -// } - -// public void StopListeningForHotplugEvents() -// { -// if (_callbackHandle == IntPtr.Zero) { -// Debug.WriteLine("Not listening already."); -// return; -// } - -// LibUsb.libusb_hotplug_deregister_callback(this.handle, this._callbackHandle); - -// } - -// public void HandleHotplugCallback(IntPtr ctx, IntPtr device, HotplugEventType eventType, IntPtr userData) -// { -// Debug.WriteLine("Hotplug Callback called, event type: " + eventType.ToString()); -// // raise the event -// this.DeviceConnected(this, new EventArgs()); -// } -// } -//} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Dfu/WIP.DfuUpload.cs b/Meadow.CLI.Core/Internals/Dfu/WIP.DfuUpload.cs deleted file mode 100644 index 2041c10c..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/WIP.DfuUpload.cs +++ /dev/null @@ -1,72 +0,0 @@ -//using System; -//using System.IO; -//using DfuSharp; - -//namespace MeadowCLI -//{ -// public static class DfuUpload -// { -// static string os = "nuttx.bin"; -// static string user = "nuttx_user.bin"; - -// static int os_address = 0x08000000; -// static int user_address = 0x08040000; - -// static int uploadedByteCount = 0; -// static int totalBytes = 0; - -// public static void FlashNuttx(string dfuOsPath, string dfuUserPath) -// { -// DfuContext.Init(); -// var devices = DfuContext.Current.GetDevices(); - -// if (devices.Count < 1) { -// Console.WriteLine("Attach a device in DFU mode, mofo."); -// } else { -// if (!string.IsNullOrEmpty(dfuOsPath)) { -// if (!File.Exists(dfuOsPath)) { -// Console.WriteLine($"Cannot find {dfuOsPath} file."); -// return; -// } -// } else if (!File.Exists($"{Environment.CurrentDirectory}\\{os}")) { -// Console.WriteLine($"Cannot find {os} file."); -// return; -// } - -// if (!string.IsNullOrEmpty(dfuUserPath)) { -// if (!File.Exists(dfuUserPath)) { -// Console.WriteLine($"Cannot find {dfuUserPath} file."); -// return; -// } -// } else if (!File.Exists($"{Environment.CurrentDirectory}\\{user}")) { -// Console.WriteLine($"Cannot find {user} file."); -// return; -// } - -// devices[0].Uploading += Program_Uploading; - -// Upload(devices[0], $"{dfuOsPath ?? Path.Combine(Environment.CurrentDirectory, os)}", os_address); -// Upload(devices[0], $"{dfuUserPath ?? Path.Combine(Environment.CurrentDirectory, user)}", user_address); -// } -// } - -// private static void Upload(DfuDevice device, string path, int address) -// { -// FileInfo fi = new FileInfo(path); -// byte[] bytes = File.ReadAllBytes(path); -// totalBytes = bytes.Length; - -// Console.WriteLine($"Uploading {fi.Name}"); -// uploadedByteCount = 0; -// device.Upload(bytes, (int)address); -// Console.WriteLine("\rdone "); -// } - -// private static void Program_Uploading(object sender, UploadingEventArgs e) -// { -// uploadedByteCount += e.BytesUploaded; - -// Console.Write($"\r{(uploadedByteCount * 100 / totalBytes)}%"); -// } -// } -//} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Dfu/WIP.NativeMethods.cs b/Meadow.CLI.Core/Internals/Dfu/WIP.NativeMethods.cs deleted file mode 100644 index 2a309774..00000000 --- a/Meadow.CLI.Core/Internals/Dfu/WIP.NativeMethods.cs +++ /dev/null @@ -1,406 +0,0 @@ -//using System; -//using System.Runtime.InteropServices; - -//namespace DfuSharp -//{ -// internal interface ILibUsb -// { -// int init(ref IntPtr ctx); -// void exit(IntPtr ctx); -// void set_debug(IntPtr ctx, LogLevel level); -// int get_device_list(IntPtr ctx, ref IntPtr list); -// int free_device_list(IntPtr list, int free_devices); -// int get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc); -// int get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc); -// int open(IntPtr dev, ref IntPtr handle); -// int close(IntPtr handle); -// int claim_interface(IntPtr dev, int interface_number); -// int set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting); -// int control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout); -// int has_capability(Capabilities capability); -// ErrorCodes hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, -// int vendorID, int productID, int deviceClass, -// HotplugCallback callback, IntPtr userData, -// out IntPtr callbackHandle); -// void hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle); -// } - -// internal static class LibUsb -// { -// private static ILibUsb _libUsb; - -// static LibUsb() -// { -// switch (Environment.OSVersion.Platform) { -// case PlatformID.MacOSX: -// case PlatformID.Unix: -// _libUsb = new LibUsbMac(); -// break; -// case PlatformID.Win32NT: -// case PlatformID.Win32S: -// case PlatformID.Win32Windows: -// case PlatformID.WinCE: -// _libUsb = new LibUsbWindows(); -// break; -// } -// } - -// public static int libusb_init(ref IntPtr ctx) -// { -// return _libUsb.init(ref ctx); -// } - -// public static void libusb_exit(IntPtr ctx) -// { -// _libUsb.exit(ctx); -// } - -// public static void libusb_set_debug(IntPtr ctx, LogLevel level) -// { -// _libUsb.set_debug(ctx, level); -// } - -// public static int libusb_get_device_list(IntPtr ctx, ref IntPtr list) -// { -// return _libUsb.get_device_list(ctx, ref list); -// } - -// public static int libusb_free_device_list(IntPtr list, int free_devices) -// { -// return _libUsb.free_device_list(list, free_devices); -// } - -// public static int libusb_get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc) -// { -// return _libUsb.get_device_descriptor(dev, ref desc); -// } - -// public static int libusb_get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc) -// { -// return _libUsb.get_config_descriptor(dev, config_index, out desc); -// } - -// public static int libusb_open(IntPtr dev, ref IntPtr handle) -// { -// return _libUsb.open(dev, ref handle); -// } - -// public static int libusb_close(IntPtr handle) -// { -// return _libUsb.close(handle); -// } - -// public static int libusb_claim_interface(IntPtr dev, int interface_number) -// { -// return _libUsb.claim_interface(dev, interface_number); -// } - -// public static int libusb_set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting) -// { -// return _libUsb.set_interface_alt_setting(dev, interface_number, alternate_setting); -// } - -// public static int libusb_control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout) -// { -// return _libUsb.control_transfer(dev, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout); -// } - -// public static int libusb_has_capability(Capabilities capability) -// { -// return _libUsb.has_capability(capability); -// } - -// public static ErrorCodes libusb_hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, -// int vendorID, int productID, int deviceClass, -// HotplugCallback callback, IntPtr userData, -// out IntPtr callbackHandle) -// { -// return _libUsb.hotplug_register_callback(ctx, eventType, flags, vendorID, productID, deviceClass, callback, userData, out callbackHandle); -// } - -// public static void libusb_hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle) -// { -// _libUsb.hotplug_deregister_callback(ctx, callbackHandle); -// } -// } - -// internal class LibUsbWindows : ILibUsb -// { -// public int init(ref IntPtr ctx) -// { -// return NativeMethods.libusb_init(ref ctx); -// } - -// public void exit(IntPtr ctx) -// { -// NativeMethods.libusb_exit(ctx); -// } - -// public void set_debug(IntPtr ctx, LogLevel level) -// { -// NativeMethods.libusb_set_debug(ctx, level); -// } - -// public int get_device_list(IntPtr ctx, ref IntPtr list) -// { -// return NativeMethods.libusb_get_device_list(ctx, ref list); -// } - -// public int free_device_list(IntPtr list, int free_devices) -// { -// return NativeMethods.libusb_free_device_list(list, free_devices); -// } - -// public int get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc) -// { -// return NativeMethods.libusb_get_device_descriptor(dev, ref desc); -// } - -// public int get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc) -// { -// return NativeMethods.libusb_get_config_descriptor(dev, config_index, out desc); -// } - -// public int open(IntPtr dev, ref IntPtr handle) -// { -// return NativeMethods.libusb_open(dev, ref handle); -// } - -// public int close(IntPtr handle) -// { -// return NativeMethods.libusb_close(handle); -// } - -// public int claim_interface(IntPtr dev, int interface_number) -// { -// return NativeMethods.libusb_claim_interface(dev, interface_number); -// } - -// public int set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting) -// { -// return NativeMethods.libusb_set_interface_alt_setting(dev, interface_number, alternate_setting); -// } - -// public int control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout) -// { -// return NativeMethods.libusb_control_transfer(dev, bmRequestType, bmRequestType, wValue, wIndex, data, wLength, timeout); -// } - -// public int has_capability(Capabilities capability) -// { -// return NativeMethods.libusb_has_capability(capability); -// } - -// public ErrorCodes hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, -// int vendorID, int productID, int deviceClass, -// HotplugCallback callback, IntPtr userData, -// out IntPtr callbackHandle) -// { -// return NativeMethods.libusb_hotplug_register_callback(ctx, eventType, flags, vendorID, productID, deviceClass, callback, userData, out callbackHandle); -// } - -// public void hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle) -// { -// NativeMethods.libusb_hotplug_deregister_callback(ctx, callbackHandle); -// } - -// private static partial class NativeMethods -// { -// const string LIBUSB_LIBRARY = "libusb-1.0.dll"; - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_init(ref IntPtr ctx); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern void libusb_exit(IntPtr ctx); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern void libusb_set_debug(IntPtr ctx, LogLevel level); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_get_device_list(IntPtr ctx, ref IntPtr list); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_free_device_list(IntPtr list, int free_devices); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_open(IntPtr dev, ref IntPtr handle); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_close(IntPtr handle); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_claim_interface(IntPtr dev, int interface_number); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout); - -// /// -// /// Whether or not the USB supports a particular feature. -// /// -// /// nonzero if the running library has the capability, 0 otherwise -// /// Capability. -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_has_capability(Capabilities capability); - - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern ErrorCodes libusb_hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, -// int vendorID, int productID, int deviceClass, -// HotplugCallback callback, IntPtr userData, -// out IntPtr callbackHandle); -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern void libusb_hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle); - -// } -// } - -// internal class LibUsbMac : ILibUsb -// { -// public int init(ref IntPtr ctx) -// { -// return NativeMethods.libusb_init(ref ctx); -// } - -// public void exit(IntPtr ctx) -// { -// NativeMethods.libusb_exit(ctx); -// } - -// public void set_debug(IntPtr ctx, LogLevel level) -// { -// NativeMethods.libusb_set_debug(ctx, level); -// } - -// public int get_device_list(IntPtr ctx, ref IntPtr list) -// { -// return NativeMethods.libusb_get_device_list(ctx, ref list); -// } - -// public int free_device_list(IntPtr list, int free_devices) -// { -// return NativeMethods.libusb_free_device_list(list, free_devices); -// } - -// public int get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc) -// { -// return NativeMethods.libusb_get_device_descriptor(dev, ref desc); -// } - -// public int get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc) -// { -// return NativeMethods.libusb_get_config_descriptor(dev, config_index, out desc); -// } - -// public int open(IntPtr dev, ref IntPtr handle) -// { -// return NativeMethods.libusb_open(dev, ref handle); -// } - -// public int close(IntPtr handle) -// { -// return NativeMethods.libusb_close(handle); -// } - -// public int claim_interface(IntPtr dev, int interface_number) -// { -// return NativeMethods.libusb_claim_interface(dev, interface_number); -// } - -// public int set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting) -// { -// return NativeMethods.libusb_set_interface_alt_setting(dev, interface_number, alternate_setting); -// } - -// public int control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout) -// { -// return NativeMethods.libusb_control_transfer(dev, bmRequestType, bmRequestType, wValue, wIndex, data, wLength, timeout); -// } - -// public int has_capability(Capabilities capability) -// { -// return NativeMethods.libusb_has_capability(capability); -// } - -// public ErrorCodes hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, -// int vendorID, int productID, int deviceClass, -// HotplugCallback callback, IntPtr userData, -// out IntPtr callbackHandle) -// { -// return NativeMethods.libusb_hotplug_register_callback(ctx, eventType, flags, vendorID, productID, deviceClass, callback, userData, out callbackHandle); -// } - -// public void hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle) -// { -// NativeMethods.libusb_hotplug_deregister_callback(ctx, callbackHandle); -// } - -// private static partial class NativeMethods -// { -// const string LIBUSB_LIBRARY = "libusb-1.0"; - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_init(ref IntPtr ctx); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern void libusb_exit(IntPtr ctx); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern void libusb_set_debug(IntPtr ctx, LogLevel level); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_get_device_list(IntPtr ctx, ref IntPtr list); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_free_device_list(IntPtr list, int free_devices); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_get_device_descriptor(IntPtr dev, ref DeviceDescriptor desc); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_get_config_descriptor(IntPtr dev, ushort config_index, out IntPtr desc); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_open(IntPtr dev, ref IntPtr handle); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_close(IntPtr handle); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_claim_interface(IntPtr dev, int interface_number); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_set_interface_alt_setting(IntPtr dev, int interface_number, int alternate_setting); - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_control_transfer(IntPtr dev, byte bmRequestType, byte bRequest, ushort wValue, ushort wIndex, IntPtr data, ushort wLength, uint timeout); - -// /// -// /// Whether or not the USB supports a particular feature. -// /// -// /// nonzero if the running library has the capability, 0 otherwise -// /// Capability. -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern int libusb_has_capability(Capabilities capability); - - -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern ErrorCodes libusb_hotplug_register_callback(IntPtr ctx, HotplugEventType eventType, HotplugFlags flags, -// int vendorID, int productID, int deviceClass, -// HotplugCallback callback, IntPtr userData, -// out IntPtr callbackHandle); -// [DllImport(LIBUSB_LIBRARY)] -// internal static extern void libusb_hotplug_deregister_callback(IntPtr ctx, IntPtr callbackHandle); - -// } -// } -//} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/Command.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/Command.cs deleted file mode 100644 index 8d60c1b1..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/Command.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.Hcom; -using System; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication -{ - public class Command - { - private protected const int HcomProtocolCommandRequiredHeaderLength = 12; - private protected const int HcomProtocolCommandSeqNumber = 0; - // TODO No longer required private protected const ushort HcomProtocolExtraDataDefaultValue = 0x0000; - private protected const int HcomProtocolRequestMd5HashLength = 32; - static internal ushort HcomProtocolCommunicationVersion = Constants.HCOM_PROTOCOL_CURRENT_VERSION_NUMBER; - - public Command(HcomMeadowRequestType requestType, - TimeSpan timeout, - ushort developerLevel, - uint userData, - byte[]? data, - Predicate responsePredicate, - Predicate completionPredicate, - EventHandler? responseHandler, - bool isAcknowledged, - string commandBuilder) - { - RequestType = requestType; - Timeout = timeout; - DeveloperLevel = developerLevel; - UserData = userData; - Data = data; - ResponsePredicate = responsePredicate; - CompletionPredicate = completionPredicate; - ResponseHandler = responseHandler; - IsAcknowledged = isAcknowledged; - CommandBuilder = commandBuilder; - } - - public HcomMeadowRequestType RequestType { get; protected set; } - public ushort DeveloperLevel { get; protected set; } - public uint UserData { get; protected set; } - public byte[]? Data { get; protected set; } - public TimeSpan Timeout { get; protected set; } - public Predicate ResponsePredicate { get; protected set; } - public Predicate CompletionPredicate { get; protected set; } - public EventHandler? ResponseHandler { get; protected set; } - public string CommandBuilder { get; protected set; } - public bool IsAcknowledged { get; set; } - - protected int ToMessageBytes(ref byte[] messageBytes) - { - int offset = 0; - - // Two byte seq numb - Array.Copy( - BitConverter.GetBytes((ushort)HcomProtocolCommandSeqNumber), - 0, - messageBytes, - offset, - sizeof(ushort)); - - offset += sizeof(ushort); - - // Protocol version - Array.Copy( - BitConverter.GetBytes(Command.HcomProtocolCommunicationVersion), - 0, - messageBytes, - offset, - sizeof(ushort)); - - offset += sizeof(ushort); - - // Command type (2 bytes) - Array.Copy( - BitConverter.GetBytes((ushort)RequestType), - 0, - messageBytes, - offset, - sizeof(ushort)); - - offset += sizeof(ushort); - - // DeveloperLevel - Array.Copy( - BitConverter.GetBytes(DeveloperLevel), - 0, - messageBytes, - offset, - sizeof(ushort)); - - offset += sizeof(ushort); - - // User Data - Array.Copy(BitConverter.GetBytes(UserData), 0, messageBytes, offset, sizeof(uint)); - offset += sizeof(uint); - - if (Data != null) - { - Array.Copy( - Data, - 0, - messageBytes, - HcomProtocolCommandRequiredHeaderLength, - Data.Length); - offset += Data.Length; - } - - return offset; - } - - public virtual byte[] ToMessageBytes() - { - var messageSize = HcomProtocolCommandRequiredHeaderLength + (Data?.Length).GetValueOrDefault(0); - var messageBytes = new byte[messageSize]; - // Note: Could use the StructLayout attribute to build - ToMessageBytes(ref messageBytes); - return messageBytes; - } - - public override string ToString() - { - return CommandBuilder; - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/CommandResponse.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/CommandResponse.cs deleted file mode 100644 index 86a8d3cd..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/CommandResponse.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Meadow.CLI.Core.Internals.MeadowCommunication -{ - public class CommandResponse - { - public CommandResponse(bool isSuccess, string? message, MeadowMessageType? messageType) - { - IsSuccess = isSuccess; - Message = message; - MessageType = messageType; - } - - public bool IsSuccess { get; } - public string? Message { get; } - public MeadowMessageType? MessageType { get; } - - public static CommandResponse Empty = new CommandResponse(true, null, null); - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/FileCommand.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/FileCommand.cs deleted file mode 100644 index c822d760..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/FileCommand.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.Hcom; -using System; -using System.Diagnostics; -using System.Text; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication -{ - public class FileCommand : Command - { - internal FileCommand(HcomMeadowRequestType requestType, - TimeSpan timeout, - string sourceFileName, - string destinationFileName, - string? md5Hash, - uint crc32, - int fileSize, - uint partition, - uint mcuAddress, - byte[]? fileBytes, - Predicate responseHandler, - Predicate completionHandler, - string commandBuilder) - : base(requestType, timeout, 0, partition, null, responseHandler, completionHandler, null, true, commandBuilder) - { - SourceFileName = sourceFileName; - DestinationFileName = destinationFileName; - Md5Hash = md5Hash ?? string.Empty; - Crc32 = crc32; - FileSize = fileSize; - Partition = partition; - McuAddress = mcuAddress; - FileBytes = fileBytes; - } - - public string DestinationFileName { get; protected set; } - public string SourceFileName { get; protected set; } - public string Md5Hash { get; protected set; } - public uint Crc32 { get; protected set; } - public int FileSize { get; protected set; } - public uint Partition { get; protected set; } - public uint McuAddress { get; protected set; } - public byte[]? FileBytes { get; protected set; } - - public override byte[] ToMessageBytes() - { - // Allocate the correctly size message buffers - byte[] targetFileName = Encoding.UTF8.GetBytes(DestinationFileName); // Using UTF-8 works for ASCII but should be Unicode in nuttx - - byte[] md5HashBytes = Encoding.UTF8.GetBytes(Md5Hash); - int optionalDataLength = sizeof(uint) - + sizeof(uint) - + sizeof(uint) - + HcomProtocolRequestMd5HashLength - + targetFileName.Length; - - byte[] messageBytes = new byte[HcomProtocolCommandRequiredHeaderLength + optionalDataLength]; - - var offset = base.ToMessageBytes(ref messageBytes); - Array.Copy(BitConverter.GetBytes(FileSize), 0, messageBytes, offset, sizeof(uint)); - offset += sizeof(uint); - - // CRC32 checksum or delete file partition number - Array.Copy(BitConverter.GetBytes(Crc32), 0, messageBytes, offset, sizeof(uint)); - offset += sizeof(uint); - - // MCU address for this file. Used for ESP32 file downloads - Array.Copy(BitConverter.GetBytes(McuAddress), 0, messageBytes, offset, sizeof(uint)); - offset += sizeof(uint); - - // Include ESP32 MD5 hash if it's needed - if (string.IsNullOrEmpty(Md5Hash)) - Array.Clear(messageBytes, offset, HcomProtocolRequestMd5HashLength); - else - Array.Copy(md5HashBytes, 0, messageBytes, offset, HcomProtocolRequestMd5HashLength); - - offset += HcomProtocolRequestMd5HashLength; - - // Destination File Name - Array.Copy(targetFileName, 0, messageBytes, offset, targetFileName.Length); - offset += targetFileName.Length; - - Debug.Assert(offset == optionalDataLength + HcomProtocolCommandRequiredHeaderLength); - - return messageBytes; - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/FileCommandBuilder.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/FileCommandBuilder.cs deleted file mode 100644 index 1189288a..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/FileCommandBuilder.cs +++ /dev/null @@ -1,227 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.DeviceManagement.Tools; -using Meadow.Hcom; -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication -{ - public class FileCommandBuilder - { - private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60); - private readonly Dictionary> _predicates = - new Dictionary>() - { - { - HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER, - p => p.MessageType == MeadowMessageType.Concluded - || p.MessageType == MeadowMessageType.DownloadStartOkay - || p.MessageType == MeadowMessageType.DownloadStartFail - }, - { - HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER, - p => p.MessageType == MeadowMessageType.Concluded - || p.MessageType == MeadowMessageType.DownloadStartOkay - || p.MessageType == MeadowMessageType.DownloadStartFail - }, - { - HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME, - p => p.MessageType == MeadowMessageType.Concluded - || p.MessageType == MeadowMessageType.DownloadStartOkay - || p.MessageType == MeadowMessageType.DownloadStartFail - } - }; - - public FileCommandBuilder(HcomMeadowRequestType requestType) - { - RequestType = requestType; - if (_predicates.ContainsKey(RequestType)) - { - CompletionPredicate = _predicates[RequestType]; - ResponsePredicate = _predicates[RequestType]; - } - } - - private protected MeadowMessageType? ResponseMessageType; - private protected MeadowMessageType? CompletionMessageType; - - public HcomMeadowRequestType RequestType { get; protected set; } - public uint UserData { get; protected set; } - public TimeSpan? Timeout { get; protected set; } - public byte[]? Data { get; protected set; } - public string? DestinationFileName { get; protected set; } - public string? SourceFileName { get; protected set; } - public string? Md5Hash { get; protected set; } - public uint Crc32 { get; protected set; } - public int FileSize { get; protected set; } - public uint Partition { get; protected set; } - public uint McuAddress { get; protected set; } - public byte[]? FileBytes { get; protected set; } - public Predicate? ResponsePredicate { get; protected set; } - public Predicate? CompletionPredicate { get; protected set; } - - public FileCommandBuilder WithDestinationFileName(string destinationFileName) - { - DestinationFileName = destinationFileName; - return this; - } - - public FileCommandBuilder WithSourceFileName(string sourceFileName) - { - SourceFileName = sourceFileName; - return this; - } - - public FileCommandBuilder WithMd5Hash(string md5Hash) - { - Md5Hash = md5Hash; - return this; - } - - public FileCommandBuilder WithCrc32(uint crc32) - { - Crc32 = crc32; - return this; - } - - public FileCommandBuilder WithPartition(uint partition) - { - Partition = partition; - return this; - } - - public FileCommandBuilder WithMcuAddress(uint mcuAddress) - { - McuAddress = mcuAddress; - return this; - } - - public FileCommandBuilder WithFileBytes(byte[] fileBytes) - { - FileBytes = fileBytes; - return this; - } - - public FileCommandBuilder WithTimeout(TimeSpan timeout) - { - Timeout = timeout; - return this; - } - - public FileCommandBuilder WithResponseType(MeadowMessageType responseMessageType) - { - ResponseMessageType = responseMessageType; - return this; - } - - public FileCommandBuilder WithCompletionResponseType(MeadowMessageType completionMessageType) - { - CompletionMessageType = completionMessageType; - return this; - } - - public FileCommandBuilder WithResponseFilter(Predicate predicate) - { - ResponsePredicate = predicate; - return this; - } - - public FileCommandBuilder WithCompletionFilter(Predicate predicate) - { - CompletionPredicate = predicate; - return this; - } - - public FileCommand Build() - { - if (RequestType != HcomMeadowRequestType.HCOM_MDOW_REQUEST_DELETE_FILE_BY_NAME) - { - if (string.IsNullOrWhiteSpace(SourceFileName)) - { - throw new ArgumentNullException(SourceFileName); - } - - if (FileBytes == null) - { - var fi = new FileInfo(SourceFileName); - if (!fi.Exists) - { - throw new FileNotFoundException("Cannot find source file", fi.FullName); - } - - FileBytes = File.ReadAllBytes(SourceFileName); - } - - FileSize = FileBytes.Length; - if (Md5Hash == null) - { - // Calculate the file hashes - using var md5 = MD5.Create(); - var hash = md5.ComputeHash(FileBytes); - if (McuAddress != 0) - { - Md5Hash = BitConverter.ToString(hash) - .Replace("-", "") - .ToLowerInvariant(); - } - } - - if (Crc32 == 0) - { - Crc32 = CrcTools.Crc32part(FileBytes, FileBytes.Length, 0); - } - } - else - { - SourceFileName ??= DestinationFileName; - } - - DestinationFileName ??= Path.GetFileName(SourceFileName); - - if (ResponsePredicate == null) - { - if (ResponseMessageType != null) - ResponsePredicate = e => e.MessageType == ResponseMessageType; - else ResponsePredicate = e => e.MessageType == MeadowMessageType.Concluded; - } - - if (CompletionPredicate == null) - { - if (CompletionMessageType != null) - CompletionPredicate = e => e.MessageType == CompletionMessageType; - else CompletionPredicate = e => e.MessageType == MeadowMessageType.Concluded; - } - - return new FileCommand( - RequestType, - Timeout ?? DefaultTimeout, - SourceFileName, - DestinationFileName, - Md5Hash, - Crc32, - FileSize, - Partition, - McuAddress, - FileBytes, - ResponsePredicate, - CompletionPredicate, - ToString()); - } - - public override string ToString() - { - return $"RequestType: {RequestType} " - + $"Timeout: {Timeout} " - + $"UserData: {UserData} " - + $"ResponseType {ResponseMessageType?.ToString() ?? "none"} " - + $"CompletionMessageType: {CompletionMessageType?.ToString() ?? "none"} " - + $"CompletionPredicate: {CompletionPredicate != null} " - + $"ResponsePredicate: {ResponsePredicate != null} " - + $"MD5: {Md5Hash} " - + $"CRC: {Crc32} " - + $"MCU Address: {McuAddress}"; - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/MeadowSerialDataProcessor.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/MeadowSerialDataProcessor.cs deleted file mode 100644 index 38075904..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/MeadowSerialDataProcessor.cs +++ /dev/null @@ -1,426 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.DeviceManagement.Tools; -using Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses; -using Meadow.Hcom; -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Ports; -using System.Linq; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication -{ - // For data received due to a CLI request these provide a secondary - // type of identification. The primary being the protocol request value - public enum MeadowMessageType - { - AppOutput, - ErrOutput, - DeviceInfo, - FileListTitle, - FileListMember, - FileListCrcMember, - Data, - InitialFileData, - MeadowTrace, - SerialReconnect, - Accepted, - Concluded, - DownloadStartOkay, - DownloadStartFail, - DownloadFailed, - DevicePublicKey - } - - public class MeadowSerialDataProcessor : MeadowDataProcessor - { - private readonly ILogger _logger; - //collapse to one and use enum - private readonly SerialPort _serialPort; - readonly Socket _socket; - private readonly Task _dataProcessorTask; - - private readonly ReceiveMessageFactoryManager _receiveMessageFactoryManager; - private readonly CancellationTokenSource _cts; - - // TODO: make these user settable via CLI - public string StdInfoPrefix { get; set; } = "Meadow StdInfo"; - public string StdOutPrefix { get; set; } = "Meadow StdOut"; - public string StdErrPrefix { get; set; } = "Meadow StdErr"; - - // It seems that the .Net SerialPort class is not all it could be. - // To acheive reliable operation some SerialPort class methods must - // not be used. When receiving, the BaseStream must be used. - // http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport - - //------------------------------------------------------------- - // Constructor - private MeadowSerialDataProcessor(ILogger logger) - { - _cts = new CancellationTokenSource(); - _receiveMessageFactoryManager = new ReceiveMessageFactoryManager(logger); - _logger = logger; - } - - public MeadowSerialDataProcessor(SerialPort serialPort, ILogger? logger = null) : this(logger ?? new NullLogger()) - { - _serialPort = serialPort; - _dataProcessorTask = Task.Factory.StartNew(ReadSerialPort, TaskCreationOptions.LongRunning); - } - - public MeadowSerialDataProcessor(Socket socket, ILogger? logger = null) : this(logger ?? new NullLogger()) - { - this._socket = socket; - _dataProcessorTask = Task.Factory.StartNew(ReadSocket, TaskCreationOptions.LongRunning); - } - - //------------------------------------------------------------- - // All received data handled here - private async Task ReadSocket() - { - byte[] buffer = new byte[MeadowDeviceManager.MaxEstimatedSizeOfEncodedPayload]; - - try - { - while (!_cts.IsCancellationRequested) - { - var segment = new ArraySegment(buffer); - var receivedLength = await _socket.ReceiveAsync(segment, SocketFlags.None); - - DecodeAndProcessPacket(buffer.AsMemory(0, receivedLength), _cts.Token); - - await Task.Delay(50); - } - } - catch (ThreadAbortException) - { - //ignoring for now until we wire cancellation ... - //this blocks the thread abort exception when the console app closes - } - catch (InvalidOperationException) - { - // common if the port is reset/closed (e.g. mono enable/disable) - don't spew confusing info - } - catch (Exception ex) - { - _logger.LogTrace($"Exception: {ex} may mean the target connection dropped"); - } - } - - private class SerialMessage - { - private readonly IList> _segments; - - public SerialMessage(Memory segment) - { - _segments = new List>(); - _segments.Add(segment); - } - - public void AddSegment(Memory segment) - { - _segments.Add(segment); - } - - public byte[] ToArray() - { - using var ms = new MemoryStream(); - foreach (var segment in _segments) - { - // We could just call ToArray on the `Memory` but that will result in an uncontrolled allocation. - var tmp = ArrayPool.Shared.Rent(segment.Length); - segment.CopyTo(tmp); - ms.Write(tmp, 0, segment.Length); - ArrayPool.Shared.Return(tmp); - } - return ms.ToArray(); - } - } - - private async Task ReadSerialPort() - { - SerialMessage? message = null; - try - { - while (!_cts.IsCancellationRequested && _serialPort != null) - { - try - { - // Reconnection happens higher up - while (!_serialPort.IsOpen) - { - await Task.Delay(100); - } - - var b = new byte[1024]; - var receivedLength = await _serialPort.BaseStream.ReadAsync(b, 0, b.Length); - - var buffer = b.AsMemory(0, receivedLength); - while (buffer.Length > 0) - { - var messageEnd = buffer.Span.IndexOf((byte)0x00); - // We didn't find the end to a message - if (messageEnd == -1) - { - if (message == null) - message = new SerialMessage(buffer); - else - message.AddSegment(buffer); - - break; - } - else - { - // We read the whole message during this iteration - if (message == null) - { - var msg = buffer.Slice(0, messageEnd); - buffer = buffer.Slice(messageEnd + 1); - try - { - DecodeAndProcessPacket(msg, _cts.Token); - } - catch (Exception e) - { - Debug.WriteLine($"{e.Message}"); - } - } - // We had some part of the message from a previous iteration - else - { - message.AddSegment(buffer.Slice(0, messageEnd)); - buffer = buffer.Slice(messageEnd + 1); - var msg = message.ToArray(); - try - { - DecodeAndProcessPacket(msg, _cts.Token); - } - catch (Exception e) - { - Debug.WriteLine($"{e.Message}"); - } - - message = null; - } - } - } - } - catch (TimeoutException) - { - } - catch (Exception ex) - { - _logger.LogTrace(ex, "An error occurred while listening to the serial port."); - await Task.Delay(100, _cts.Token); - } - } - } - catch (ThreadAbortException) - { - //ignoring for now until we wire cancellation ... - //this blocks the thread abort exception when the console app closes - } - catch (InvalidOperationException) - { - // common if the port is reset/closed (e.g. mono enable/disable) - don't spew confusing info - } - catch (Exception ex) - { - _logger.LogTrace($"Exception: {ex} may mean the target connection dropped"); - } - } - - private bool DecodeAndProcessPacket(Memory packetBuffer, CancellationToken cancellationToken) - { - var decodedBuffer = ArrayPool.Shared.Rent(MeadowDeviceManager.MaxAllowableMsgPacketLength); - var packetLength = packetBuffer.Length; - // It's possible that we may find a series of 0x00 values in the buffer. - // This is because when the sender is blocked (because this code isn't - // running) it will attempt to send a single 0x00 before the full message. - // This allows it to test for a connection. When the connection is - // unblocked this 0x00 is sent and gets put into the buffer along with - // any others that were queued along the usb serial pipe line. - if (packetLength == 1) - { - //_logger.LogTrace("Throwing out 0x00 from buffer"); - return false; - } - - var decodedSize = CobsTools.CobsDecoding(packetBuffer, ref decodedBuffer); - - // If a message is too short it is ignored - if (decodedSize < MeadowDeviceManager.ProtocolHeaderSize) - return false; - - Debug.Assert(decodedSize <= MeadowDeviceManager.MaxAllowableMsgPacketLength); - - // Process the received packet - ParseAndProcessReceivedPacket(decodedBuffer.AsSpan(0, decodedSize).ToArray(), - cancellationToken); - - ArrayPool.Shared.Return(decodedBuffer); - return true; - } - - private IEnumerable FormatForOutput(string prefix, string message) - { - return message - .Trim() - .Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries) - .Select(m => string.IsNullOrEmpty(prefix) ? m.Trim() : $"{prefix}: {m.Trim()}"); - } - - // TODO: Convert to Memory from byte[] - private void ParseAndProcessReceivedPacket(byte[] receivedMsg, CancellationToken cancellationToken) - { - try - { - var processor = _receiveMessageFactoryManager.CreateProcessor(receivedMsg); - if (processor == null) return; - - if (processor.Execute(receivedMsg)) - { - var requestType = (HcomHostRequestType)processor.RequestType; - var responseString = processor.ToString(); - _logger.LogTrace($"Received message {requestType}, Content: {responseString}, {receivedMsg.Length} bytes"); - switch (requestType) - { - case HcomHostRequestType.HCOM_HOST_REQUEST_UNDEFINED_REQUEST: - break; - // This set are responses to request issued by this application - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_REJECTED: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.Data, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_ACCEPTED: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.Accepted)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_CONCLUDED: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.Concluded)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_ERROR: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.ErrOutput, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_INFORMATION: - foreach (var m in FormatForOutput(StdInfoPrefix, responseString)) - { - _logger.LogInformation(m); - } - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.Data, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_LIST_HEADER: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.FileListTitle, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_LIST_MEMBER: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.FileListMember, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_CRC_MEMBER: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.FileListCrcMember, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_MONO_STDOUT: - foreach (var m in FormatForOutput(StdOutPrefix, responseString)) - { - _logger.LogInformation(m); - } - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.AppOutput, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_MONO_STDERR: - foreach (var m in FormatForOutput(StdErrPrefix, responseString)) - { - _logger.LogWarning(m); - } - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.ErrOutput, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_DEVICE_INFO: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.DeviceInfo, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_TRACE_MSG: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.MeadowTrace, responseString)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_RECONNECT: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.SerialReconnect)); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_DEBUGGING_MONO_DATA: - DebuggerMessages.Add(processor.MessageData!, cancellationToken); - break; - case HcomHostRequestType.HCOM_HOST_REQUEST_FILE_START_OKAY: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.DownloadStartOkay)); - break; - - case HcomHostRequestType.HCOM_HOST_REQUEST_FILE_START_FAIL: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.DownloadStartFail)); - break; - - case HcomHostRequestType.HCOM_HOST_REQUEST_GET_INITIAL_FILE_BYTES: - { - var msg = System.Text.Encoding.UTF8.GetString(processor.MessageData); - - OnReceiveData?.Invoke( - this, - new MeadowMessageEventArgs(MeadowMessageType.InitialFileData, msg)); - - break; - } - - case HcomHostRequestType.HCOM_HOST_REQUEST_DNLD_FAIL_RESEND: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.DownloadFailed, responseString)); - break; - - case HcomHostRequestType.HCOM_HOST_REQUEST_DEVICE_PUBLIC_KEY: - OnReceiveData?.Invoke(this, new MeadowMessageEventArgs(MeadowMessageType.DevicePublicKey, responseString)); - break; - - } - } - } - catch (Exception ex) - { - _logger.LogDebug(ex, "An error occurred parsing a received packet"); - } - } - - /* - // Save for testing in case we suspect data corruption of text - // The protocol requires the first 12 bytes to be the header. The first 2 are 0x00, - // the next 10 are binary. After this the rest are ASCII text or binary. - // Test the message and if it fails it's trashed. - if(decodedBuffer[0] != 0x00 || decodedBuffer[1] != 0x00) - { - _logger.LogTrace("Corrupted message, first 2 bytes not 0x00"); - continue; - } - - int buffOffset; - for(buffOffset = MeadowDeviceManager.HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH; - buffOffset < decodedSize; - buffOffset++) - { - if(decodedBuffer[buffOffset] < 0x20 || decodedBuffer[buffOffset] > 0x7e) - { - _logger.LogTrace($"Corrupted message, non-ascii at offset:{buffOffset} value:{decodedBuffer[buffOffset]}"); - break; - } - } - - // Throw away if we found non ASCII where only text should be - if (buffOffset < decodedSize) - continue; - */ - public override void Dispose() - { - try - { - _cts.Cancel(); - _dataProcessorTask?.Dispose(); - } - catch (Exception ex) - { - _logger.LogTrace(ex, "Exception during disposal"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/DebuggingServer.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/DebuggingServer.cs deleted file mode 100644 index 43873bb1..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/DebuggingServer.cs +++ /dev/null @@ -1,318 +0,0 @@ -using System; -using System.Buffers; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Security.Cryptography; -using System.Threading; -using System.Threading.Tasks; -using Meadow.CLI.Core.Devices; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - // This TCP server directly interacts with Visual Studio debugging. - // What it receives from Visual Studio it forwards to Meadow. - // What it receives from Meadow it forwards to Visual Studio. - public class DebuggingServer : IDisposable - { - // VS 2019 - 4024 - // VS 2017 - 4022 - // VS 2015 - 4020 - public IPEndPoint LocalEndpoint { get; private set; } - - private readonly object _lck = new object(); - private CancellationTokenSource? _cancellationTokenSource; - private readonly ILogger _logger; - private readonly IMeadowDevice _meadow; - private ActiveClient? _activeClient; - private int _activeClientCount = 0; - private TcpListener _listener; - private Task? _listenerTask; - private bool _isReady; - public bool Disposed; - - // Constructor - /// - /// Create a new DebuggingServer for proxying debug data between VS and Meadow - /// - /// The to debug - /// The to listen for incoming debugger connections - /// The to logging state information - public DebuggingServer(IMeadowDevice meadow, IPEndPoint localEndpoint, ILogger logger) - { - LocalEndpoint = localEndpoint; - _meadow = meadow; - _logger = logger; - _listener = new TcpListener(LocalEndpoint); - } - - /// - /// Start the debugging server - /// - /// A that is linked internally to the running task - /// A representing the startup operation - public async Task StartListening(CancellationToken cancellationToken) - { - _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - _listenerTask = Task.Factory.StartNew(StartListener, TaskCreationOptions.LongRunning); - var startTimeout = DateTime.UtcNow.AddSeconds(60); - while (DateTime.UtcNow < startTimeout) - { - if (_isReady) - { - return; - } - - await Task.Delay(100, cancellationToken); - } - - throw new Exception("DebuggingServer did not start listening within the 60 second timeout."); - } - - /// - /// Stop the - /// - /// A representing the shutdown operation - public async Task StopListening() - { - _listener?.Stop(); - - if (_cancellationTokenSource != null) - _cancellationTokenSource?.Cancel(false); - - if (_listenerTask != null) - { - await _listenerTask; - } - } - - private async Task StartListener() - { - try - { - _listener.Start(); - LocalEndpoint = (IPEndPoint)_listener.LocalEndpoint; - _logger.LogInformation($"Listening for Visual Studio to connect on {LocalEndpoint.Address}:{LocalEndpoint.Port}" + Environment.NewLine); - _isReady = true; - - // This call will wait for the client to connect, before continuing. We shouldn't need a loop. - TcpClient tcpClient = await _listener.AcceptTcpClientAsync(); - OnConnect(tcpClient); - } - catch (SocketException soex) - { - _logger.LogError("A Socket error occurred. The port may already be in use. Try rebooting to free up the port."); - _logger.LogError($"Error:\n{soex.Message} \nStack Trace:\n{soex.StackTrace}"); - } - catch (Exception ex) - { - _logger.LogError("An unhandled exception occurred while listening for debugging connections."); - _logger.LogError($"Error:\n{ex.Message} \nStack Trace:\n{ex.StackTrace}"); - } - } - - private void OnConnect(TcpClient tcpClient) - { - try - { - lock (_lck) - { - _logger.LogInformation ("Visual Studio has Connected" + Environment.NewLine); - if (_activeClientCount > 0 && _activeClient?.Disposed == false) - { - _logger.LogDebug("Closing active client"); - Debug.Assert(_activeClientCount == 1); - Debug.Assert(_activeClient != null); - CloseActiveClient(); - } - - _activeClient = new ActiveClient(_meadow, tcpClient, _logger, _cancellationTokenSource.Token); - _activeClientCount++; - } - } - catch (Exception ex) - { - _logger.LogError(ex, "An error occurred while connecting to Visual Studio"); - } - } - - internal void CloseActiveClient() - { - _activeClient?.Dispose(); - _activeClient = null; - _activeClientCount = 0; - } - - public void Dispose() - { - lock (_lck) - { - if (Disposed) - return; - _cancellationTokenSource?.Cancel(false); - _activeClient?.Dispose(); - _listenerTask?.Dispose(); - Disposed = true; - } - } - - // Embedded class - private class ActiveClient : IDisposable - { - private readonly IMeadowDevice _meadow; - private readonly TcpClient _tcpClient; - private readonly NetworkStream _networkStream; - - private readonly CancellationTokenSource _cts; - private readonly Task _receiveVsDebugDataTask; - private readonly Task _receiveMeadowDebugDataTask; - private readonly ILogger _logger; - public bool Disposed = false; - - // Constructor - internal ActiveClient(IMeadowDevice meadow, TcpClient tcpClient, ILogger logger, CancellationToken cancellationToken) - { - _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - _logger = logger; - _meadow = meadow; - _tcpClient = tcpClient; - _networkStream = tcpClient.GetStream(); - _logger.LogDebug("Starting receive task"); - _receiveVsDebugDataTask = Task.Factory.StartNew(SendToMeadowAsync, TaskCreationOptions.LongRunning); - _receiveMeadowDebugDataTask = Task.Factory.StartNew(SendToVisualStudio, TaskCreationOptions.LongRunning); - } - - private const int RECEIVE_BUFFER_SIZE = 256; - - private async Task SendToMeadowAsync() - { - try - { - using var md5 = MD5.Create(); - // Receive from Visual Studio and send to Meadow - var receiveBuffer = ArrayPool.Shared.Rent(RECEIVE_BUFFER_SIZE); - var meadowBuffer = Array.Empty(); - while (!_cts.IsCancellationRequested) - { - if (_networkStream != null && _networkStream.CanRead) - { - int bytesRead; - do - { - bytesRead = await _networkStream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, _cts.Token); - if (bytesRead == 0 || _cts.IsCancellationRequested) - continue; - - var destIndex = meadowBuffer.Length; - Array.Resize(ref meadowBuffer, destIndex + bytesRead); - Array.Copy(receiveBuffer, 0, meadowBuffer, destIndex, bytesRead); - - // Forward the RECIEVE_BUFFER_SIZE chunk to Meadow immediately - _logger.LogTrace("Received {count} bytes from VS, will forward to HCOM/Meadow. {hash}", - meadowBuffer.Length, - BitConverter.ToString(md5.ComputeHash(meadowBuffer)) - .Replace ("-", string.Empty) - .ToLowerInvariant()); - await _meadow.ForwardVisualStudioDataToMono(meadowBuffer, 0); - meadowBuffer = Array.Empty(); - - // Ensure we read all the data in this message before passing it along - // I'm not sure this is actually needed, the whole message should get read at once. - } while (_networkStream.DataAvailable); - } - else - { - // User probably hit stop - _logger.LogInformation("Unable to Read Data from Visual Studio"); - _logger.LogTrace("Unable to Read Data from Visual Studio"); - } - } - } - catch (IOException ioe) - { - // VS client probably died - _logger.LogInformation("Visual Studio has Disconnected" + Environment.NewLine); - _logger.LogTrace(ioe, "Visual Studio has Disconnected"); - } - catch (ObjectDisposedException ode) - { - // User probably hit stop - _logger.LogInformation("Visual Studio has stopped debugging" + Environment.NewLine); - _logger.LogTrace(ode, "Visual Studio has stopped debugging"); - } - catch (Exception ex) - { - _logger.LogError($"Error receiving data from Visual Studio.{Environment.NewLine}Error: {ex.Message}{Environment.NewLine}StackTrace:{Environment.NewLine}{ex.StackTrace}"); - throw; - } - } - - private async Task SendToVisualStudio() - { - try - { - while (!_cts.IsCancellationRequested) - { - if (_networkStream != null && _networkStream.CanWrite) - { - while (_meadow.DataProcessor.DebuggerMessages.Count > 0) - { - var byteData = _meadow.DataProcessor.DebuggerMessages.Take(_cts.Token); - _logger.LogTrace("Received {count} bytes from Meadow, will forward to VS", byteData.Length); - if (!_tcpClient.Connected) - { - _logger.LogDebug("Cannot forward data, Visual Studio is not connected"); - return; - } - - await _networkStream.WriteAsync(byteData, 0, byteData.Length, _cts.Token); - _logger.LogTrace("Forwarded {count} bytes to VS", byteData.Length); - } - } - else - { - // User probably hit stop - _logger.LogInformation("Unable to Write Data from Visual Studio"); - _logger.LogTrace("Unable to Write Data from Visual Studio"); - } - } - } - catch (OperationCanceledException oce) - { - // User probably hit stop; Removed logging as User doesn't need to see this - // Keeping it as a TODO in case we find a side effect that needs logging. - // TODO _logger.LogInformation("Operation Cancelled"); - // TODO _logger.LogTrace(oce, "Operation Cancelled"); - } - catch (Exception ex) - { - _logger.LogError ($"Error sending data to Visual Studio.{Environment.NewLine}Error: {ex.Message}{Environment.NewLine}StackTrace:{Environment.NewLine}{ex.StackTrace}"); - - if (_cts.IsCancellationRequested) - throw; - } - } - - public void Dispose() - { - lock (_tcpClient) - { - if (Disposed) - return; - - _logger.LogTrace("Disposing ActiveClient"); - _cts.Cancel(false); - _receiveVsDebugDataTask.Wait(TimeSpan.FromSeconds(10)); - _receiveMeadowDebugDataTask.Wait(TimeSpan.FromSeconds(10)); - _receiveVsDebugDataTask?.Dispose(); - _receiveMeadowDebugDataTask?.Dispose(); - _tcpClient.Dispose(); - _networkStream.Dispose(); - _cts.Dispose(); - Disposed = true; - } - } - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/IReceivedMessage.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/IReceivedMessage.cs deleted file mode 100644 index a99c2e79..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/IReceivedMessage.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public interface IReceivedMessage - { - // Each derived class needs these - bool Execute(byte[] receivedMessage); - string ToString(); - - // These are in RecvHeader - ushort SeqNumber { get; } - ushort VersionNumber { get; } - ushort RequestType { get; } - ushort ExtraData { get; } - uint UserData { get; } - int HeaderLength { get; } - - byte[]? MessageData { get; } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveHeader.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveHeader.cs deleted file mode 100644 index 37a11079..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveHeader.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Security.Cryptography; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public class ReceiveHeader : IReceivedMessage - { - private readonly MD5 _hasher = MD5.Create(); - // Header 12 bytes for Header plus message data - public ushort SeqNumber { get; } - public ushort VersionNumber { get; } - public ushort RequestType { get; } - public ushort ExtraData { get; } - public uint UserData { get; } - public int HeaderLength { get ; } - - public byte[]? MessageData { get; } - public int MessageDataLength { get; } - - - public ReceiveHeader(byte[] receivedMessage) - { - // Recover the sequence number which must proceed all messages. - SeqNumber = Convert.ToUInt16(receivedMessage[HeaderLength] + (receivedMessage[HeaderLength + 1] << 8)); - HeaderLength += sizeof(ushort); - - VersionNumber = Convert.ToUInt16(receivedMessage[HeaderLength] + (receivedMessage[HeaderLength + 1] << 8)); - HeaderLength += sizeof(ushort); - - RequestType = Convert.ToUInt16(receivedMessage[HeaderLength] + (receivedMessage[HeaderLength + 1] << 8)); - HeaderLength += sizeof(ushort); - - ExtraData = Convert.ToUInt16(receivedMessage[HeaderLength] + (receivedMessage[HeaderLength + 1] << 8)); - HeaderLength += sizeof(ushort); - - UserData = Convert.ToUInt32(receivedMessage[HeaderLength] + (receivedMessage[HeaderLength + 1] << 8) + - (receivedMessage[HeaderLength + 2] << 16) + (receivedMessage[HeaderLength + 3] << 24)); - HeaderLength += sizeof(uint); - - MessageDataLength = receivedMessage.Length - HeaderLength; - if(MessageDataLength > 0) - { - MessageData = new byte[MessageDataLength]; - Array.Copy(receivedMessage, HeaderLength, MessageData, 0, MessageDataLength); - } - else - { - MessageData = null; - } - } - - public virtual bool Execute(byte[] receivedMessage) - { - return true; - } - - public override string ToString() - { - if (MessageData == null) - { - return string.Empty; - } - return BitConverter.ToString(_hasher.ComputeHash(MessageData)) - .Replace("-", string.Empty) - .ToLowerInvariant(); - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveMessageFactory.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveMessageFactory.cs deleted file mode 100644 index 84727524..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveMessageFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public abstract class ReceiveMessageFactory - { - public abstract IReceivedMessage Create(byte[] receivedMessage); - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveMessageFactoryManager.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveMessageFactoryManager.cs deleted file mode 100644 index 86dd1ec4..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveMessageFactoryManager.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Meadow.Hcom; -using System; -using System.Collections.Generic; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public class ReceiveMessageFactoryManager - { - private readonly Dictionary _factories; - private readonly ILogger _logger; - public ReceiveMessageFactoryManager(ILogger logger) - { - _logger = logger; - _factories = new Dictionary - { - {HcomHostRequestType.HCOM_HOST_REQUEST_DEBUGGING_MONO_DATA, new ReceiveSimpleBinaryFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_GET_INITIAL_FILE_BYTES, new ReceiveSimpleBinaryFactory() }, - - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_REJECTED, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_ACCEPTED, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_CONCLUDED, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_ERROR, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_INFORMATION, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_LIST_HEADER, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_LIST_MEMBER, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_CRC_MEMBER, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_MONO_STDOUT, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_DEVICE_INFO, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_TRACE_MSG, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_RECONNECT, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_TEXT_MONO_STDERR, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_FILE_START_OKAY, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_FILE_START_FAIL, new ReceiveSimpleTextFactory() }, - {HcomHostRequestType.HCOM_HOST_REQUEST_DNLD_FAIL_RESEND, new ReceiveSimpleTextFactory()}, - {HcomHostRequestType.HCOM_HOST_REQUEST_DEVICE_PUBLIC_KEY, new ReceiveSimpleTextFactory()}, - }; - } - - public IReceivedMessage? CreateProcessor(byte[] receivedMessage) - { - var requestType = HcomHostRequestType.HCOM_HOST_REQUEST_UNDEFINED_REQUEST; - try - { - requestType = FindRequestTypeValue(receivedMessage); - if (_factories.ContainsKey(requestType)) - { - ReceiveMessageFactory factory = _factories[requestType]; - return factory.Create(receivedMessage); - } - _logger.LogWarning($"An unknown request value of '0x{requestType:x}' was received."); - return null; - } - catch (KeyNotFoundException) - { - _logger.LogWarning($"An unknown request value of '0x{requestType:x}' was received."); - return null; - } - catch (Exception ex) - { - // I saw a few time, that this exception was being thrown. It was caused by - // corrupted data being processed. - _logger.LogWarning(ex, $"Request type was: 0x{requestType:x}"); - return null; - } - } - - private static HcomHostRequestType FindRequestTypeValue(IReadOnlyList receivedMessage) - { - const int requestTypeOffset = (int)HcomProtocolHeaderOffsets.HCOM_PROTOCOL_REQUEST_HEADER_RQST_TYPE_OFFSET; - return (HcomHostRequestType)Convert.ToUInt16(receivedMessage[requestTypeOffset] + (receivedMessage[requestTypeOffset + 1] << 8)); - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleBinary.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleBinary.cs deleted file mode 100644 index 56e497af..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleBinary.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Security.Cryptography; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - internal class ReceiveSimpleBinary : ReceiveHeader - { - public ReceiveSimpleBinary(byte[] receivedMessage) : base(receivedMessage) - { - } - - public override bool Execute(byte[] receivedMessage) - { - try - { - return true; - } - catch (Exception ex) - { - Console.WriteLine($"Exception:{ex.Message}"); - return false; - } - } - } -} - diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleBinaryFactory.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleBinaryFactory.cs deleted file mode 100644 index 17bbeffb..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleBinaryFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public class ReceiveSimpleBinaryFactory : ReceiveMessageFactory - { - public override IReceivedMessage Create(byte[] receivedMessage) => new ReceiveSimpleBinary(receivedMessage); - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleMessage.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleMessage.cs deleted file mode 100644 index 0af3cefa..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleMessage.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - internal class ReceiveSimpleMessage : ReceiveHeader - { - public ReceiveSimpleMessage(byte[] receivedMessage) : base(receivedMessage) - { - } - - public override bool Execute(byte[] receivedMessage) - { - try - { - return true; - } - catch (Exception ex) - { - Console.WriteLine($"Exception:{ex.Message}"); - return false; - } - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleMessageFactory.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleMessageFactory.cs deleted file mode 100644 index 2d5d6cd7..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleMessageFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public class ReceiveSimpleMessageFactory : ReceiveMessageFactory - { - public override IReceivedMessage Create(byte[] receivedMessage) => new ReceiveSimpleMessage(receivedMessage); - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleText.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleText.cs deleted file mode 100644 index 821de53c..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleText.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Text; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - internal class ReceiveSimpleText : ReceiveHeader - { - public ReceiveSimpleText(byte[] receivedMessage) : base(receivedMessage) - { - } - - public override bool Execute(byte[] receivedMessage) - { - try - { - //We actually have text based messages with 0 length - if (receivedMessage.Length < HeaderLength) - { - throw new ArgumentException($"Received {nameof(ReceiveSimpleText)} with no text data. Message Length: {receivedMessage.Length}"); - } - return true; - } - catch (Exception ex) - { - Console.WriteLine($"Exception:{ex.Message}"); - return false; - } - } - public override string ToString() - { - return MessageDataLength > 0 ? Encoding.UTF8.GetString(MessageData!) : string.Empty; - } - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleTextFactory.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleTextFactory.cs deleted file mode 100644 index 42e99ebd..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/ReceiveClasses/ReceiveSimpleTextFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication.ReceiveClasses -{ - public class ReceiveSimpleTextFactory : ReceiveMessageFactory - { - public override IReceivedMessage Create(byte[] receivedMessage) => new ReceiveSimpleText(receivedMessage); - } -} diff --git a/Meadow.CLI.Core/Internals/MeadowCommunication/SimpleCommandBuilder.cs b/Meadow.CLI.Core/Internals/MeadowCommunication/SimpleCommandBuilder.cs deleted file mode 100644 index 23ae5b3a..00000000 --- a/Meadow.CLI.Core/Internals/MeadowCommunication/SimpleCommandBuilder.cs +++ /dev/null @@ -1,121 +0,0 @@ -using Meadow.CLI.Core.DeviceManagement; -using Meadow.Hcom; -using System; - -namespace Meadow.CLI.Core.Internals.MeadowCommunication -{ - public class SimpleCommandBuilder - { - private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60); - public SimpleCommandBuilder(HcomMeadowRequestType requestType) - { - RequestType = requestType; - Timeout = DefaultTimeout; - } - - private protected MeadowMessageType? ResponseMessageType; - private protected MeadowMessageType? CompletionMessageType; - - private protected HcomMeadowRequestType RequestType { get; set; } - private protected ushort DeveloperLevel { get; set; } - private protected uint UserData { get; set; } - private protected TimeSpan Timeout { get; set; } - private protected byte[]? Data { get; set; } - private protected Predicate? ResponsePredicate { get; set; } - private protected Predicate? CompletionPredicate { get; set; } - private protected EventHandler? ResponseHandler { get; set; } - private protected bool IsAcknowledged { get; set; } = true; - - public SimpleCommandBuilder WithTimeout(TimeSpan timeout) - { - Timeout = timeout; - return this; - } - - public SimpleCommandBuilder WithDeveloperLevel(ushort level) - { - DeveloperLevel = level; - return this; - } - - public SimpleCommandBuilder WithUserData(uint userData) - { - UserData = userData; - return this; - } - - public SimpleCommandBuilder WithData(byte[] data) - { - Data = data; - return this; - } - - public SimpleCommandBuilder WithResponseType(MeadowMessageType responseMessageType) - { - ResponseMessageType = responseMessageType; - return this; - } - - public SimpleCommandBuilder WithCompletionResponseType(MeadowMessageType completionMessageType) - { - CompletionMessageType = completionMessageType; - return this; - } - - public SimpleCommandBuilder WithResponseFilter(Predicate predicate) - { - ResponsePredicate = predicate; - return this; - } - - public SimpleCommandBuilder WithCompletionFilter(Predicate predicate) - { - CompletionPredicate = predicate; - return this; - } - - public SimpleCommandBuilder WithResponseHandler(EventHandler handler) - { - ResponseHandler = handler; - return this; - } - - public SimpleCommandBuilder WithAcknowledgement(bool isAcknowledged) - { - IsAcknowledged = isAcknowledged; - return this; - } - - public Command Build() - { - if (ResponsePredicate == null) - { - if (ResponseMessageType != null) - ResponsePredicate = e => e.MessageType == ResponseMessageType; - else ResponsePredicate = e => e.MessageType == MeadowMessageType.Concluded; - } - - if (CompletionPredicate == null) - { - if (CompletionMessageType != null) - CompletionPredicate = e => e.MessageType == CompletionMessageType; - else CompletionPredicate = e => e.MessageType == MeadowMessageType.Concluded; - } - - return new Command(RequestType, Timeout, DeveloperLevel, UserData, Data, ResponsePredicate, CompletionPredicate, ResponseHandler, IsAcknowledged, ToString()); - } - - public override string ToString() - { - return $"RequestType: {RequestType} " - + $"Timeout: {Timeout} " - + $"DeveloperLevel: {DeveloperLevel} " - + $"UserData: {UserData} " - + $"ResponseType {ResponseMessageType?.ToString() ?? "none"} " - + $"CompletionMessageType: {CompletionMessageType?.ToString() ?? "none"} " - + $"ResponseHandler: {ResponseHandler != null} " - + $"CompletionPredicate: {CompletionPredicate != null} " - + $"ResponsePredicate: {ResponsePredicate != null}"; - } - } -} diff --git a/Meadow.CLI.Core/Internals/Tools/CobsTools.cs b/Meadow.CLI.Core/Internals/Tools/CobsTools.cs deleted file mode 100644 index d5d6ccf4..00000000 --- a/Meadow.CLI.Core/Internals/Tools/CobsTools.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Buffers; - -namespace Meadow.CLI.Core.DeviceManagement.Tools -{ - public static class CobsTools - { - //============================================================== - // Consistent Overhead Byte Stuffing (COBS) is a scheme to take binary data - // replace an arbituary byte value, usually 0x00, with an encoding that replaces - // this value, in a way, that allows the orginal data can be recovered while - // creating frames around the data. - // - // The following C# code was ported from a 'C' example licensed under MIT License - // https://github.com/bakercp/PacketSerial/blob/master/src/Encoding/COBS.h. - // After porting, I found errors. I referred to the original authors paper at - // http://conferences.sigcomm.org/sigcomm/1997/papers/p062.pdf for additional insights. - // Modifications were needed and adding a starting offset to support large buffers was - // added to allow sub-segments to be encoded. - // - public static int CobsEncoding(byte[] source, int startingSkip, int length, - ref byte[] encoded, int encodeSkip) - { - int sourceOffset = startingSkip; // Offset into source buffer - // Add 1 because first byte filled with first replaceValue value - int encodedOffset = 1; // Offset into destination buffer - int replaceOffset = 0; // Offset where replaceValue is being tracked - byte replaceValue = 1; // Value of the offset to the next delimiter - - while (sourceOffset < length + startingSkip) - { - // Is source value the one we must replace? - if (source[sourceOffset] == 0x00) - { - encoded[encodeSkip + replaceOffset] = replaceValue; // Replace original value with offset to replaceValue - replaceOffset = encodedOffset++; // Update replace offset and bump encoded offset - replaceValue = 1; // Reset replaceValue - } - else - { - encoded[encodeSkip + encodedOffset++] = source[sourceOffset]; // Just copy original value - replaceValue++; // Keep zero offset tracker - - // replaceValue has been tracking the delimiter offset. If it's 0xff then - // special action is needed, because we reached the end of a 254 byte block - // of data. And now encoding starts like at the first. - if (replaceValue == 0xff) // Signals maximum possible offset - { - encoded[encodeSkip + replaceOffset] = replaceValue; - replaceOffset = encodedOffset++; - replaceValue = 1; - } - } - sourceOffset++; // Point to next source value - } - - // Last character - encoded[encodeSkip + replaceOffset] = replaceValue; - return encodedOffset; // Number of bytes written to result buffer - } - - //--------------------------------------------------------------------------- - public static int CobsDecoding(byte[] encoded, int length, ref byte[] decoded) - { - int encodedOffset = 0; // Offset into original (encoded) buffer - int decodedOffset = 0; // Offset into destination (decoded) buffer - byte replaceValue = 0; // Value that will be inserted to indicate replaced value - - while (encodedOffset < length) - { - replaceValue = encoded[encodedOffset]; // Grab next byte - - if (((encodedOffset + replaceValue) > length) && (replaceValue != 1)) - return 0; - - encodedOffset++; // Point to next source - - // Copy all unchanged bytes - // C# would Array.Copy be noticably better? - for (int i = 1; i < replaceValue; i++) - decoded[decodedOffset++] = encoded[encodedOffset++]; - - // Sometimes don't need a trailing delimiter added - if (replaceValue < 0xff && encodedOffset != length) - decoded[decodedOffset++] = 0x00; - } - - return decodedOffset; - } - - //--------------------------------------------------------------------------- - public static int CobsDecoding(Memory encoded, ref byte[] decoded) - { - int encodedOffset = 0; // Offset into original (encoded) buffer - int decodedOffset = 0; // Offset into destination (decoded) buffer - byte replaceValue = 0; // Value that will be inserted to indicate replaced value - - while (encodedOffset < encoded.Length) - { - replaceValue = encoded.Span[encodedOffset]; // Grab next byte - - if (((encodedOffset + replaceValue) > encoded.Length) && (replaceValue != 1)) - return 0; - - encodedOffset++; // Point to next source - - // Copy all unchanged bytes - // C# would Array.Copy be noticably better? - for (int i = 1; i < replaceValue; i++) - decoded[decodedOffset++] = encoded.Span[encodedOffset++]; - - // Sometimes don't need a trailing delimiter added - if (replaceValue < 0xff && encodedOffset != encoded.Length) - decoded[decodedOffset++] = 0x00; - } - - return decodedOffset; - } - - public static int CobsDecoding(ReadOnlySequence encoded, ref byte[] decoded) - { - int decodedOffset = 0; // Offset into destination (decoded) buffer - - foreach (var sequence in encoded) - { - var encodedOffset = 0; // Offset into original (encoded) buffer - while (encodedOffset < encoded.Length) - { - var replaceValue = - sequence.Span[ - encodedOffset]; // Value that will be inserted to indicate replaced value - - if (((encodedOffset + replaceValue) > encoded.Length) - && (replaceValue != 1)) - return 0; - - encodedOffset++; // Point to next source - - // Copy all unchanged bytes - // C# would Array.Copy be noticeably better? - for (var i = 1; i < replaceValue; i++) - decoded[decodedOffset++] = sequence.Span[encodedOffset++]; - - // Sometimes don't need a trailing delimiter added - if (replaceValue < 0xff && encodedOffset != encoded.Length) - decoded[decodedOffset++] = 0x00; - } - } - - return decodedOffset; - } - } -} diff --git a/Meadow.CLI.Core/Internals/Tools/CrcTools.cs b/Meadow.CLI.Core/Internals/Tools/CrcTools.cs deleted file mode 100644 index 7726a9b3..00000000 --- a/Meadow.CLI.Core/Internals/Tools/CrcTools.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.IO; -using System.IO.Hashing; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core.DeviceManagement.Tools -{ - public static class CrcTools - { - //============================================================== - // The following crc32 table and calculation code was copied from - // '...\nuttx\libs\libc\misc\lib_crc32.c'. Minor changes have been made. - // The file’s title block contains the following text: - //* The logic in this file was developed by Gary S.Brown: - //* COPYRIGHT (C) 1986 Gary S.Brown.You may use this program, or code or tables - //* extracted from it, as desired without restriction. - static readonly uint[] crc32_tab = - { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - - //--------------------------------------------------------------------- - // Calculate the checksum of a buffer starting at an offset - public static uint Crc32part(byte[] buffer, int length, int offset, uint crc32val) - { - for (int i = offset; i < length + offset; i++) - { - crc32val = crc32_tab[(crc32val & 0xff) ^ buffer[i]] ^ (crc32val >> 8); - } - return crc32val; - } - - //--------------------------------------------------------------------- - // Calculate the checksum of a buffer starting at the beginning - public static uint Crc32part(byte[] buffer, int length, uint crc32val) - { - return Crc32part(buffer, length, 0, crc32val); - } - - public static async Task CalculateCrc32FileHash(string filePath) - { - var crc32 = new Crc32(); - - using (var fs = File.OpenRead(filePath)) - { - await crc32.AppendAsync(fs); - } - - var checkSum = crc32.GetCurrentHash(); - Array.Reverse(checkSum); // make big endian - return BitConverter.ToString(checkSum).Replace("-", "").ToLower(); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Internals/Tools/ModuleWeaver.cs b/Meadow.CLI.Core/Internals/Tools/ModuleWeaver.cs deleted file mode 100644 index 32e2f090..00000000 --- a/Meadow.CLI.Core/Internals/Tools/ModuleWeaver.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using Mono.Cecil; - -namespace Meadow.CLI.Core.Internals.Tools -{ - public class WeaverCRC - { - public Action LogDebug { get; set; } - public Action LogInfo { get; set; } - - public ModuleDefinition? ModuleDefinition { get; set; } - public IAssemblyResolver? AssemblyResolver { get; set; } - - public WeaverCRC() - { - LogDebug = s => { }; //Debug.WriteLine(s); }; - LogInfo = s => { }; // Debug.WriteLine(s); }; - } - - public Guid GetCrcGuid(string fileName) - { - var assembly = AssemblyDefinition.ReadAssembly(fileName); - - var guid = GetCrcGuid(assembly.MainModule); - - assembly.Dispose(); - - return guid; - } - - public Guid GetCrcGuid(ModuleDefinition module) - { - // for calculating hash - HashAlgorithm hash = SHA256.Create(); - CryptoStream cryptoStream = new CryptoStream(System.IO.Stream.Null, hash, CryptoStreamMode.Write); - - // hash input (will consist of non-private types and methods) - var hashInputList = new List(); - - foreach (TypeDefinition type in module.Types) - { - if (type.IsNotPublic) - { - continue; - } - - foreach (MethodDefinition method in type.Methods) - { - if (method.IsPrivate || method.IsAssembly) { continue; } - - var paramTypes = new StringBuilder(); - foreach (ParameterDefinition p in method.Parameters) - { - paramTypes.AppendFormat("{0}.", p.ParameterType.FullName); - } - hashInputList.Add(type.Name + "." + method.Name + "." + paramTypes.ToString()); - } - - foreach (FieldDefinition field in type.Fields) - { - if (field.IsPrivate || field.IsAssembly) { continue; } - hashInputList.Add(type.Name + "." + field.Name); - } - - - // feed module name and sorted list of non-private types/methods to hash generator - LogDebug("Generating MVID with following non-private Types/Methods from " + module.Name + ":"); - cryptoStream.Write(Encoding.ASCII.GetBytes(module.Name), 0, module.Name.Length); - foreach (string hashInput in hashInputList.OrderBy(k => k)) - { - LogDebug(" " + hashInput); - cryptoStream.Write(Encoding.ASCII.GetBytes(hashInput), 0, hashInput.Length); - } - } - - // finalize and generate GUID from hash value - cryptoStream.FlushFinalBlock(); - Guid guid = Guid.Parse(BitConverter.ToString(hash.Hash).Replace("-", string.Empty).Substring(0, 32)); - /* var mvidVersion = Assembly.GetExecutingAssembly().GetName().Version; - LogInfo($"Mvid.SieExtensions.Fody ver {mvidVersion}"); - LogInfo($"Generated MVID ({ModuleDefinition.Name}) : {guid}"); - ModuleDefinition.Mvid = guid; */ - - return guid; - } - - public void WriteGuidToFile(Guid guid, string filename, string path) - { - File.WriteAllBytes(Path.Combine(path, filename), guid.ToByteArray()); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Managers/DownloadManager.cs b/Meadow.CLI.Core/Managers/DownloadManager.cs deleted file mode 100644 index 01f609a5..00000000 --- a/Meadow.CLI.Core/Managers/DownloadManager.cs +++ /dev/null @@ -1,402 +0,0 @@ -using Meadow.CLI.Core.Common; -using System; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net.Http; -using System.Net.NetworkInformation; -using System.Reflection; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Core -{ - public class DownloadManager - { - public static readonly string FirmwareDownloadsFilePathRoot = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "WildernessLabs", - "Firmware"); - - public static string FirmwareLatestVersion - { - get - { - string latest_txt = Path.Combine(FirmwareDownloadsFilePathRoot, "latest.txt"); - if (File.Exists(latest_txt)) - return File.ReadAllText(latest_txt); - else - throw new FileNotFoundException("OS download was not found."); - } - } - - public static string FirmwareDownloadsFilePath => FirmwarePathForVersion(FirmwareLatestVersion); - - public static string FirmwarePathForVersion(string firmwareVersion) - { - return Path.Combine(FirmwareDownloadsFilePathRoot, firmwareVersion); - } - - public static readonly string WildernessLabsTemp = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "WildernessLabs", - "temp"); - - public static readonly string OsFilename = "Meadow.OS.bin"; - public static readonly string RuntimeFilename = "Meadow.OS.Runtime.bin"; - public static readonly string NetworkBootloaderFilename = "bootloader.bin"; - public static readonly string NetworkMeadowCommsFilename = "MeadowComms.bin"; - public static readonly string NetworkPartitionTableFilename = "partition-table.bin"; - internal static readonly string VersionCheckUrlRoot = - "https://s3-us-west-2.amazonaws.com/downloads.wildernesslabs.co/Meadow_Beta/"; - - public static readonly string UpdateCommand = "dotnet tool update WildernessLabs.Meadow.CLI --global"; - - private static readonly HttpClient Client = new() - { - Timeout = TimeSpan.FromMinutes(5) - }; - - private readonly ILogger _logger; - - public DownloadManager(ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public DownloadManager(ILogger logger) - { - _logger = logger; - } - - internal async Task DownloadMeadowOSVersionFile(string? version, CancellationToken cancellationToken) - { - string versionCheckUrl; - if (version is null || string.IsNullOrWhiteSpace(version)) - { - _logger.LogInformation("Downloading latest version file" + Environment.NewLine); - versionCheckUrl = VersionCheckUrlRoot + "latest.json"; - } - else - { - _logger.LogInformation("Downloading version file for Meadow OS " + version + Environment.NewLine); - versionCheckUrl = VersionCheckUrlRoot + version + ".json"; - } - - string versionCheckFile; - - try - { - versionCheckFile = await DownloadFile(new Uri(versionCheckUrl), cancellationToken); - } - catch - { - return null; - } - - return versionCheckFile; - } - - bool CreateFolder(string path, bool eraseIfExists) - { - if (Directory.Exists(path)) - { - if (eraseIfExists) - { - CleanPath(path); - } - else - { - return false; - } - } - else - { - Directory.CreateDirectory(path); - } - return true; - } - - //ToDo rename this method - DownloadOSAsync? - public async Task DownloadOsBinaries(string? version = null, bool force = false, CancellationToken cancellationToken = default) - { - string local_path; - if (!string.IsNullOrEmpty(version)) - { - local_path = Path.Combine(FirmwareDownloadsFilePathRoot, version); - - if (!force - && Directory.Exists(local_path) - && Directory.EnumerateFiles(local_path).Any()) - { - _logger.LogInformation($"Meadow OS version {version} was previously downloaded to: {local_path}.{Environment.NewLine}"); - return; - } - } - - // Check if there is an active internet connection - if (!NetworkInterface.GetIsNetworkAvailable()) - { - _logger.LogError($"No internet connection! Cannot download Meadow OS version {version}. Please retry once an internet connection is available.{Environment.NewLine}"); - return; - } - - var versionCheckFilePath = await DownloadMeadowOSVersionFile(version, cancellationToken); - - if (versionCheckFilePath == null) - { - _logger.LogError($"Meadow OS {version} cannot be downloaded or is not available"); - return; - } - - var payload = File.ReadAllText(versionCheckFilePath); - var release = JsonSerializer.Deserialize(payload); - - if (release == null) - { - _logger.LogError($"Unable to read release details for Meadow OS {version}. Payload: {payload}"); - return; - } - - CreateFolder(FirmwareDownloadsFilePathRoot, false); - //we'll write latest.txt regardless of version if it doesn't exist - File.WriteAllText(Path.Combine(FirmwareDownloadsFilePathRoot, "latest.txt"), release.Version); - - if (string.IsNullOrWhiteSpace(version)) - { - version = release.Version; - } - - local_path = Path.Combine(FirmwareDownloadsFilePathRoot, version); - - if (!CreateFolder(local_path, force) && Directory.EnumerateFiles(local_path).Any()) - { - _logger.LogInformation($"Meadow OS version {version} was previously downloaded to: {local_path}.{Environment.NewLine}"); - return; - } - - try - { - _logger.LogInformation($"Downloading Meadow OS version {release.Version}.{Environment.NewLine}"); - await DownloadAndExtractFile(new Uri(release.DownloadURL), local_path); - } - catch - { - _logger.LogError($"Unable to download Meadow OS {version}"); - return; - } - - try - { - _logger.LogInformation($"Downloading coprocessor firmware.{Environment.NewLine}"); - await DownloadAndExtractFile(new Uri(release.NetworkDownloadURL), local_path); - } - catch - { - _logger.LogError($"Unable to download coprocessor firmware {version}"); - return; - } - - _logger.LogInformation($"Downloaded and extracted OS version {release.Version} to: {local_path}.{Environment.NewLine}"); - } - - public async Task InstallDfuUtil(bool is64Bit = true, - CancellationToken cancellationToken = default) - { - try - { - _logger.LogInformation("Installing dfu-util..."); - - if (Directory.Exists(WildernessLabsTemp)) - { - Directory.Delete(WildernessLabsTemp, true); - } - - Directory.CreateDirectory(WildernessLabsTemp); - - const string downloadUrl = "https://s3-us-west-2.amazonaws.com/downloads.wildernesslabs.co/public/dfu-util-0.11-binaries.zip"; - - var downloadFileName = downloadUrl.Substring(downloadUrl.LastIndexOf("/", StringComparison.Ordinal) + 1); - var response = await Client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken); - - if (response.IsSuccessStatusCode == false) - { - throw new Exception("Failed to download dfu-util"); - } - - using (var stream = await response.Content.ReadAsStreamAsync()) - using (var downloadFileStream = new DownloadFileStream(stream, _logger)) - using (var fs = File.OpenWrite(Path.Combine(WildernessLabsTemp, downloadFileName))) - { - await downloadFileStream.CopyToAsync(fs); - } - - ZipFile.ExtractToDirectory( - Path.Combine(WildernessLabsTemp, downloadFileName), - WildernessLabsTemp); - - var dfuUtilExe = new FileInfo( - Path.Combine(WildernessLabsTemp, - is64Bit ? "win64" : "win32", - "dfu-util.exe")); - - var libUsbDll = new FileInfo( - Path.Combine( - WildernessLabsTemp, - is64Bit ? "win64" : "win32", - "libusb-1.0.dll")); - - var targetDir = is64Bit - ? Environment.GetFolderPath(Environment.SpecialFolder.System) - : Environment.GetFolderPath( - Environment.SpecialFolder.SystemX86); - - File.Copy(dfuUtilExe.FullName, Path.Combine(targetDir, dfuUtilExe.Name), true); - File.Copy(libUsbDll.FullName, Path.Combine(targetDir, libUsbDll.Name), true); - - // clean up from previous version - var dfuPath = Path.Combine(@"C:\Windows\System", dfuUtilExe.Name); - var libUsbPath = Path.Combine(@"C:\Windows\System", libUsbDll.Name); - if (File.Exists(dfuPath)) - { - File.Delete(dfuPath); - } - - if (File.Exists(libUsbPath)) - { - File.Delete(libUsbPath); - } - - _logger.LogInformation("dfu-util 0.11 installed"); - } - catch (Exception ex) - { - _logger.LogError( - ex, - ex.Message.Contains("Access to the path") - ? $"Run terminal as administrator and try again." - : "Unexpected error"); - } - finally - { - if (Directory.Exists(WildernessLabsTemp)) - { - Directory.Delete(WildernessLabsTemp, true); - } - } - } - - public async Task<(bool updateExists, string latestVersion, string currentVersion)> CheckForUpdates() - { - try - { - var packageId = "WildernessLabs.Meadow.CLI"; - var appVersion = Assembly.GetEntryAssembly()! - .GetCustomAttribute() - .Version; - - var json = await Client.GetStringAsync( - $"https://api.nuget.org/v3-flatcontainer/{packageId.ToLower()}/index.json"); - - var result = JsonSerializer.Deserialize(json); - - if (!string.IsNullOrEmpty(result?.Versions.LastOrDefault())) - { - var latest = result!.Versions!.Last(); - return (latest.ToVersion() > appVersion.ToVersion(), latest, appVersion); - } - } - catch (Exception ex) - { - _logger.LogDebug(ex, "Error checking for updates to Meadow.CLI"); - } - - return (false, string.Empty, string.Empty); - } - - private async Task DownloadFile(Uri uri, CancellationToken cancellationToken = default) - { - var downloadFileName = string.Empty; - - try - { - using var request = new HttpRequestMessage(HttpMethod.Get, uri); - using var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); - - response.EnsureSuccessStatusCode(); - - downloadFileName = Path.GetTempFileName(); - - using (var stream = await response.Content.ReadAsStreamAsync()) - using (var downloadFileStream = new DownloadFileStream(stream, _logger)) - { - _logger.LogDebug($"Copying downloaded file to temp file {downloadFileName}"); - using (var firmwareFile = File.OpenWrite(downloadFileName)) - { - await downloadFileStream.CopyToAsync(firmwareFile); - } - } - - _logger.LogDebug($"Downloaded file to temp file {downloadFileName}"); - return downloadFileName; - } - catch (Exception ex) - { - _logger.LogError(ex, $"Error downloading file from {uri}"); - - if (File.Exists(downloadFileName)) - File.Delete(downloadFileName); - throw; - } - } - - private async Task DownloadAndExtractFile(Uri uri, string target_path, CancellationToken cancellationToken = default) - { - var downloadFileName = await DownloadFile(uri, cancellationToken); - - _logger.LogDebug("Extracting firmware to {path}", target_path); - ZipFile.ExtractToDirectory( - downloadFileName, - target_path); - try - { - File.Delete(downloadFileName); - } - catch (Exception ex) - { - _logger.LogWarning("Unable to delete temporary file"); - _logger.LogDebug(ex, "Unable to delete temporary file"); - } - } - - private void CleanPath(string path) - { - var di = new DirectoryInfo(path); - foreach (FileInfo file in di.GetFiles()) - { - try - { - file.Delete(); - } - catch (Exception ex) - { - _logger.LogWarning("Failed to delete file {file} in firmware path", file.FullName); - _logger.LogDebug(ex, "Failed to delete file"); - } - } - foreach (DirectoryInfo dir in di.GetDirectories()) - { - try - { - dir.Delete(true); - } - catch (Exception ex) - { - _logger.LogWarning("Failed to delete directory {directory} in firmware path", dir.FullName); - _logger.LogDebug(ex, "Failed to delete directory"); - } - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Managers/PackageManager.cs b/Meadow.CLI.Core/Managers/PackageManager.cs deleted file mode 100644 index aeeaf713..00000000 --- a/Meadow.CLI.Core/Managers/PackageManager.cs +++ /dev/null @@ -1,171 +0,0 @@ -using GlobExpressions; -using Meadow.CLI.Core.DeviceManagement; -using System; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text.Json; -using System.Threading.Tasks; -using System.Xml; - -namespace Meadow.CLI.Core -{ - public class PackageManager - { - public PackageManager(ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - private readonly ILogger _logger; - private string _mpakExtension = ".mpak"; - private string _info_json = "info.json"; - - public async Task CreatePackage(string projectPath, string osVersion, string mpakName, string globPath) - { - // build project - var projectPathInfo = new FileInfo(projectPath); - BuildProject(projectPath); - - // get target framework and App.dll path - var targetFramework = GetProjectTargetFramework(projectPath); - var targetFrameworkDir = Path.Combine(projectPathInfo.DirectoryName, "bin", "Debug", targetFramework); - string appDllPath = Path.Combine(targetFrameworkDir, "App.dll"); - - await TrimDependencies(appDllPath, osVersion); - - // create mpak file - var postlinkBinDir = Path.Combine(targetFrameworkDir, "postlink_bin"); - return CreateMpak(postlinkBinDir, mpakName, osVersion, globPath); - } - - private void BuildProject(string projectPath) - { - var proc = new Process(); - proc.StartInfo.FileName = "dotnet"; - proc.StartInfo.Arguments = $"build \"{projectPath}\""; - - proc.StartInfo.CreateNoWindow = true; - proc.StartInfo.ErrorDialog = false; - proc.StartInfo.RedirectStandardError = true; - proc.StartInfo.RedirectStandardOutput = true; - proc.StartInfo.UseShellExecute = false; - - proc.ErrorDataReceived += (sendingProcess, errorLine) => Console.WriteLine(errorLine.Data); - proc.OutputDataReceived += (sendingProcess, dataLine) => Console.WriteLine(dataLine.Data); - - proc.Start(); - proc.BeginErrorReadLine(); - proc.BeginOutputReadLine(); - - proc.WaitForExit(); - var exitCode = proc.ExitCode; - proc.Close(); - - if (exitCode != 0) - { - _logger.LogError("Build failed. Package creation aborted."); - Environment.Exit(0); - } - } - - private string GetProjectTargetFramework(string projectPath) - { - XmlDocument doc = new XmlDocument(); - doc.Load(projectPath); - var targetFramework = - doc?.DocumentElement?.SelectSingleNode("/Project/PropertyGroup/TargetFramework")?.InnerText; - - return string.IsNullOrEmpty(targetFramework) - ? throw new ArgumentException("Could not find TargetFrame in project file.") - : targetFramework; - } - - private async Task TrimDependencies(string appDllPath, string osVersion) - { - FileInfo projectAppDll = new FileInfo(appDllPath); - - var dependencies = AssemblyManager - .GetDependencies(projectAppDll.Name, projectAppDll.DirectoryName, osVersion) - .Where(x => x.Contains("App.") == false) - .ToList(); - - await AssemblyManager.TrimDependencies(projectAppDll.Name, projectAppDll.DirectoryName, - dependencies, null, null, false, verbose: false); - } - - private string CreateMpak(string postlinkBinDir, string mpakName, string osVersion, string globPath) - { - if (string.IsNullOrEmpty(mpakName)) - { - mpakName = $"{DateTime.UtcNow.ToString("yyyyMMdd")}{DateTime.UtcNow.Millisecond.ToString()}{_mpakExtension}"; - } - - if (!mpakName.EndsWith(_mpakExtension)) - { - mpakName += _mpakExtension; - } - - var mpakPath = Path.Combine(Environment.CurrentDirectory, mpakName); - - if (File.Exists(mpakPath)) - { - Console.WriteLine($"{mpakPath} already exists. Do you wish to overwrite? (Y/n)"); - - while (true) - { - Console.Write("> "); - var input = Console.ReadKey(); - Console.WriteLine(); - switch (input.Key) - { - case ConsoleKey.Y: - File.Delete(mpakPath); - break; - case ConsoleKey.N: - Environment.Exit(0); - break; - default: - continue; - } - - break; - } - } - - var appFiles = Glob.Files(postlinkBinDir, globPath, GlobOptions.CaseInsensitive).ToArray(); - using var archive = ZipFile.Open(mpakPath, ZipArchiveMode.Create); - - foreach (var fPath in appFiles) - { - CreateEntry(archive, Path.Combine(postlinkBinDir, fPath), Path.Combine("app", Path.GetFileName(fPath))); - } - - // write a metadata file info.json in the mpak - PackageInfo info = new PackageInfo() - { - Version = "1", - OsVersion = osVersion - }; - var infoJson = JsonSerializer.Serialize(info); - File.WriteAllText(_info_json, infoJson); - CreateEntry(archive, _info_json, Path.GetFileName(_info_json)); - - return mpakPath; - } - - private void CreateEntry(ZipArchive archive, string fromFile, string entryPath) - { - // Windows '\' Path separator character will be written to the zip which meadow os does not properly unpack - // See: https://github.com/dotnet/runtime/issues/41914 - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - entryPath = entryPath.Replace('\\', '/'); - } - - archive.CreateEntryFromFile(fromFile, entryPath); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/Meadow.CLI.Core.6.0.0.csproj b/Meadow.CLI.Core/Meadow.CLI.Core.6.0.0.csproj deleted file mode 100644 index 560411ac..00000000 --- a/Meadow.CLI.Core/Meadow.CLI.Core.6.0.0.csproj +++ /dev/null @@ -1,74 +0,0 @@ - - - - net6.0 - AnyCPU - true - MeadowCLIKey.snk - false - false - false - preview - enable - True - 1.9.4.0 - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - - - - - - - diff --git a/Meadow.CLI.Core/Meadow.CLI.Core.Classic.csproj b/Meadow.CLI.Core/Meadow.CLI.Core.Classic.csproj deleted file mode 100644 index b1a86252..00000000 --- a/Meadow.CLI.Core/Meadow.CLI.Core.Classic.csproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - net6.0 - AnyCPU - true - MeadowCLIKey.snk - false - false - false - preview - enable - True - 1.9.4.0 - - - - true - - - - ..\Meadow.CLI.Core.Classic\bin\Debug - TRACE;WIN_10;DEBUG;NET;NET6_0;NETCOREAPP - 4 - false - - - true - ..\Meadow.CLI.Core.Classic\bin\Release - TRACE;RELEASE;NET;NET6_0;NETCOREAPP;WIN_10 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - - - - - - - diff --git a/Meadow.CLI.Core/Meadow.CLI.Core.VS2019.csproj b/Meadow.CLI.Core/Meadow.CLI.Core.VS2019.csproj deleted file mode 100644 index fa42c2ad..00000000 --- a/Meadow.CLI.Core/Meadow.CLI.Core.VS2019.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - - netstandard2.0 - AnyCPU;x64;x86 - true - MeadowCLIKey.snk - false - false - false - preview - enable - True - 1.9.4.0 - - - - true - - - - TRACE;VS2019 - Meadow.CLI.Core - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/Meadow.CLI.Core/Meadow.CLI.Core.csproj b/Meadow.CLI.Core/Meadow.CLI.Core.csproj deleted file mode 100644 index 87a00c67..00000000 --- a/Meadow.CLI.Core/Meadow.CLI.Core.csproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - netstandard2.0 - AnyCPU - true - MeadowCLIKey.snk - false - false - false - preview - enable - True - 1.9.4.0 - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - - - - diff --git a/Meadow.CLI.Core/PackageInfo.cs b/Meadow.CLI.Core/PackageInfo.cs deleted file mode 100644 index 83694df7..00000000 --- a/Meadow.CLI.Core/PackageInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core; - -public class PackageInfo -{ - [JsonPropertyName("v")] - public string Version { get; set; } - [JsonPropertyName("osVersion")] - public string OsVersion { get; set; } -} \ No newline at end of file diff --git a/Meadow.CLI.Core/PackageVersions.cs b/Meadow.CLI.Core/PackageVersions.cs deleted file mode 100644 index e83a639f..00000000 --- a/Meadow.CLI.Core/PackageVersions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core -{ - public class PackageVersions - { - [JsonPropertyName("versions")] - public string[] Versions { get; set; } - } -} diff --git a/Meadow.CLI.Core/ReleaseMetadata.cs b/Meadow.CLI.Core/ReleaseMetadata.cs deleted file mode 100644 index 95d44a8e..00000000 --- a/Meadow.CLI.Core/ReleaseMetadata.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.Json.Serialization; - -namespace Meadow.CLI.Core -{ - public class ReleaseMetadata - { - [JsonPropertyName("version")] - public string Version { get; set; } - [JsonPropertyName("minCLIVersion")] - public string MinCLIVersion { get; set; } - [JsonPropertyName("downloadUrl")] - public string DownloadURL { get; set; } - [JsonPropertyName("networkDownloadUrl")] - public string NetworkDownloadURL { get; set; } - - } -} diff --git a/Meadow.CLI.Core/Settings.cs b/Meadow.CLI.Core/Settings.cs deleted file mode 100644 index 91c9cfcf..00000000 --- a/Meadow.CLI.Core/Settings.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.IO; -using System.Linq; -using System.Text.Json; - -namespace Meadow.CLI.Core -{ - public static class SettingsManager - { - private static readonly string Path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WildernessLabs", "clisettings.json"); - - public static string? GetSetting(Setting setting) - { - var settings = GetSettings(); - return settings.TryGetValue(setting.ToString(), out var ret) ? ret : null; - } - - public static void SaveSetting(Setting setting, string value) - { - var settings = GetSettings(); - if (settings.ContainsKey(setting.ToString())) - { - settings[setting.ToString()] = value; - } - else - { - settings.Add(setting.ToString(), value); - } - - FileInfo fi = new FileInfo(Path); - if (!Directory.Exists(fi.Directory.FullName)) - { - Directory.CreateDirectory(fi.Directory.FullName); - } - - var json = JsonSerializer.Serialize(settings); - File.WriteAllText(Path, json); - } - - public static string GetAppSetting(string name) - { - if (ConfigurationManager.AppSettings.AllKeys.Contains(name)) - { - return ConfigurationManager.AppSettings[name]; - } - else - { - throw new ArgumentException($"{name} setting not found."); - } - } - - private static Settings GetSettings() - { - if (File.Exists(Path)) - { - var json = File.ReadAllText(Path); - var settings = JsonSerializer.Deserialize(json); - return settings ?? new Settings(); - } - else - { - return new Settings(); - } - } - } - - public class Settings : Dictionary - { - } - - public enum Setting - { - PORT, - LastUpdateCheck, - LatestVersion - } - -} diff --git a/Meadow.CLI.Core/images/icon.png b/Meadow.CLI.Core/images/icon.png deleted file mode 100644 index db364bce..00000000 Binary files a/Meadow.CLI.Core/images/icon.png and /dev/null differ diff --git a/Meadow.CLI.Core/lib/meadow_link.xml b/Meadow.CLI.Core/lib/meadow_link.xml deleted file mode 100644 index c1ef95b6..00000000 --- a/Meadow.CLI.Core/lib/meadow_link.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Meadow.CLI.Core/libusb-1.0.dll b/Meadow.CLI.Core/libusb-1.0.dll deleted file mode 100644 index 137897ca..00000000 Binary files a/Meadow.CLI.Core/libusb-1.0.dll and /dev/null differ diff --git a/Meadow.CLI.Core/libusb-1.0.dylib b/Meadow.CLI.Core/libusb-1.0.dylib deleted file mode 100644 index a96a7a97..00000000 Binary files a/Meadow.CLI.Core/libusb-1.0.dylib and /dev/null differ diff --git a/Meadow.CLI.Test/Fixtures/Meadow.OS.Runtime.bin b/Meadow.CLI.Test/Fixtures/Meadow.OS.Runtime.bin deleted file mode 100644 index eb049580..00000000 Binary files a/Meadow.CLI.Test/Fixtures/Meadow.OS.Runtime.bin and /dev/null differ diff --git a/Meadow.CLI.Test/Fixtures/Meadow.OS.bin b/Meadow.CLI.Test/Fixtures/Meadow.OS.bin deleted file mode 100644 index e9b679f1..00000000 Binary files a/Meadow.CLI.Test/Fixtures/Meadow.OS.bin and /dev/null differ diff --git a/Meadow.CLI.Test/Fixtures/MeadowComms.bin b/Meadow.CLI.Test/Fixtures/MeadowComms.bin deleted file mode 100644 index 6d889c0a..00000000 Binary files a/Meadow.CLI.Test/Fixtures/MeadowComms.bin and /dev/null differ diff --git a/Meadow.CLI.Test/Fixtures/bootloader.bin b/Meadow.CLI.Test/Fixtures/bootloader.bin deleted file mode 100644 index a1746c2a..00000000 Binary files a/Meadow.CLI.Test/Fixtures/bootloader.bin and /dev/null differ diff --git a/Meadow.CLI.Test/Fixtures/partition-table.bin b/Meadow.CLI.Test/Fixtures/partition-table.bin deleted file mode 100644 index b8fa03b4..00000000 Binary files a/Meadow.CLI.Test/Fixtures/partition-table.bin and /dev/null differ diff --git a/Meadow.CLI.Test/IdentityManagerTest.cs b/Meadow.CLI.Test/IdentityManagerTest.cs deleted file mode 100644 index ab54bf18..00000000 --- a/Meadow.CLI.Test/IdentityManagerTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using NUnit.Framework; - -namespace Meadow.CLI.Test -{ - [TestFixture] - public class IdentityManagerTest - { - IdentityManager _identityManager; - - public IdentityManagerTest(IdentityManager identityManager) - { - _identityManager = identityManager; - } - - [Test] - public void CredentialStoreTest() - { - string name = $"cli-test-{Guid.NewGuid():N}"; - string username = Guid.NewGuid().ToString("N"); - string password = Guid.NewGuid().ToString("N"); - - var saveResult = _identityManager.SaveCredential(name, username, password); - - Assert.IsTrue(saveResult); - - var credentialResult = _identityManager.GetCredentials(name); - - Assert.AreEqual(username, credentialResult.username); - Assert.AreEqual(password, credentialResult.password); - - _identityManager.DeleteCredential(name); - } - } -} diff --git a/Meadow.CLI.Test/Meadow.CLI.Test.csproj b/Meadow.CLI.Test/Meadow.CLI.Test.csproj deleted file mode 100644 index 8a523559..00000000 --- a/Meadow.CLI.Test/Meadow.CLI.Test.csproj +++ /dev/null @@ -1,44 +0,0 @@ - - - - net6.0 - - false - - AnyCPU - - - - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - Always - - - - - - - diff --git a/Meadow.CLI/AssemblyInfo.cs b/Meadow.CLI/AssemblyInfo.cs deleted file mode 100644 index d4091319..00000000 --- a/Meadow.CLI/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -[assembly: System.Reflection.AssemblyFileVersion(Meadow.CLI.Core.Constants.CLI_VERSION)] -[assembly: System.Reflection.AssemblyVersion(Meadow.CLI.Core.Constants.CLI_VERSION)] -[assembly: System.Reflection.AssemblyInformationalVersion(Meadow.CLI.Core.Constants.CLI_VERSION)] - diff --git a/Meadow.CLI/CliFxConsoleLoggerProvider.cs b/Meadow.CLI/CliFxConsoleLoggerProvider.cs deleted file mode 100644 index 80497377..00000000 --- a/Meadow.CLI/CliFxConsoleLoggerProvider.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Concurrent; -using CliFx.Infrastructure; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI -{ - public class CliFxConsoleLogger : ILogger - { - private readonly CliFxConsoleLoggerProviderConfig _config; - private readonly string _name; - private readonly IConsole _console; - - public CliFxConsoleLogger( - IConsole console, - string name, - CliFxConsoleLoggerProviderConfig config) => - (_console, _name, _config) = (console, name, config); - - - public void Log(LogLevel logLevel, - EventId eventId, - TState state, - Exception exception, - Func formatter) - { - if (!IsEnabled(logLevel)) - return; - _console.Output.WriteLine(formatter(state, exception)); - } - - public bool IsEnabled(LogLevel logLevel) => - logLevel >= _config.LogLevel; - - public IDisposable BeginScope(TState state) => default; - } - - public sealed class CliFxConsoleLoggerProvider : ILoggerProvider - { - private readonly CliFxConsoleLoggerProviderConfig _config; - private readonly IConsole _console; - private readonly ConcurrentDictionary _loggers = - new ConcurrentDictionary(); - - public CliFxConsoleLoggerProvider(CliFxConsoleLoggerProviderConfig config, IConsole console) => - (_config, _console) = (config, console); - - public ILogger CreateLogger(string categoryName) => - _loggers.GetOrAdd(categoryName, name => new CliFxConsoleLogger(_console, name, _config)); - - public void Dispose() => _loggers.Clear(); - } - - public class CliFxConsoleLoggerProviderConfig - { - public LogLevel LogLevel {get; init; } - } -} diff --git a/Meadow.CLI/Commands/App/DeployAppCommand.cs b/Meadow.CLI/Commands/App/DeployAppCommand.cs deleted file mode 100644 index d15a2423..00000000 --- a/Meadow.CLI/Commands/App/DeployAppCommand.cs +++ /dev/null @@ -1,65 +0,0 @@ -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.App -{ - [Command("app deploy", Description = "Deploy the specified app to the Meadow")] - public class DeployAppCommand : MeadowSerialCommand - { - [CommandOption( - "file", - 'f', - Description = "The path to the application to deploy to the app", - IsRequired = true)] - public string File { get; init; } - - [CommandOption( - "nolink", - 'n', - Description = "A list of assemblies to skip linking (trimming) on", - IsRequired = false)] - public IList NoLink { get; init; } = null; - - [CommandOption("includePdbs", 'i', Description = "Include the PDB files on deploy to enable debugging", IsRequired = false)] - public bool IncludePdbs { get; init; } = false; - - public DeployAppCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - var cancellationToken = console.RegisterCancellationHandler(); - - // check to see if the app exists before continuing - if (!System.IO.File.Exists(File)) - { - Logger.LogError($"Application file '{File}' not found"); - } - - // what OS version is on the target? - var osVersion = await Meadow.GetOSVersion(TimeSpan.FromSeconds(30), cancellationToken); - - try - { - // make sure we have the same locally because we will do linking/trimming against that runtime - await new DownloadManager(LoggerFactory).DownloadOsBinaries(osVersion, cancellationToken: cancellationToken); - } - catch - { //OS binaries failed to download - //Either no internet connection or we're depoying to a pre-release OS version - console.Output.WriteLine("Meadow assemblies download failed, using local copy"); - } - - await Meadow.DeployApp(fileName: File, includePdbs: IncludePdbs, noLink: NoLink, verbose: Verbose, cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/CloudCommand.cs b/Meadow.CLI/Commands/Cloud/CloudCommand.cs deleted file mode 100644 index 147b80c6..00000000 --- a/Meadow.CLI/Commands/Cloud/CloudCommand.cs +++ /dev/null @@ -1,26 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Exceptions; -using CliFx.Infrastructure; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("cloud", Description = "Provides Meadow.Cloud service related commands.")] - public class CloudCommand : ICommand - { - public ValueTask ExecuteAsync(IConsole console) - { - throw new CommandException("Please use one of the cloud subcommands.", showHelp: true); - } - } - - [Command("cloud command", Description = "Provides command & control related commands for devices.")] - public class CloudCommandCommand : ICommand - { - public ValueTask ExecuteAsync(IConsole console) - { - throw new CommandException("Please use one of the cloud command subcommands.", showHelp: true); - } - } -} diff --git a/Meadow.CLI/Commands/Cloud/Collection/ListCollectionCommand.cs b/Meadow.CLI/Commands/Cloud/Collection/ListCollectionCommand.cs deleted file mode 100644 index 39d39632..00000000 --- a/Meadow.CLI/Commands/Cloud/Collection/ListCollectionCommand.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.Exceptions; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Cloud.Collection; - -public class ListCollectionCommand -{ - [Command("collection list", Description = "List Meadow Collections")] - public class ListCommand : ICommand - { - private readonly ILogger _logger; - UserService _userService; - private CollectionService _collectionService; - IConfiguration _config; - - public ListCommand(ILoggerFactory loggerFactory, UserService userService, CollectionService collectionService, - IConfiguration config) - { - _logger = loggerFactory.CreateLogger(); - _userService = userService; - _collectionService = collectionService; - _config = config; - } - - [CommandOption("orgId", 'o', Description = "Organization Id", IsRequired = false)] - public string OrgId { get; set; } - [CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)] - public string Host { get; set; } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - - try - { - var userOrgs = await _userService.GetUserOrgs(Host, cancellationToken).ConfigureAwait(false); - if (!userOrgs.Any()) - { - _logger.LogInformation($"Please visit {_config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]} to register your account."); - return; - } - else if (userOrgs.Count() > 1 && string.IsNullOrEmpty(OrgId)) - { - _logger.LogInformation($"Please specify the orgId."); - return; - } - else if (userOrgs.Count() == 1 && string.IsNullOrEmpty(OrgId)) - { - OrgId = userOrgs.First().Id; - } - - if (!userOrgs.Select(x => x.Id).Contains(OrgId)) - { - _logger.LogInformation($"Invalid orgId: {OrgId}"); - return; - } - } - catch (MeadowCloudAuthException) - { - _logger.LogInformation($"You must be signed in to execute this command."); - return; - } - - var collections = await _collectionService.GetOrgCollections(OrgId, Host, cancellationToken); - - if (collections == null || collections.Count() == 0) - { - _logger.LogInformation("No collections found."); - } - - foreach (var collection in collections) - { - _logger.LogInformation($"{collection.Id} | {collection.Name}"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/Command/JsonDocumentBindingConverter.cs b/Meadow.CLI/Commands/Cloud/Command/JsonDocumentBindingConverter.cs deleted file mode 100644 index 3165481b..00000000 --- a/Meadow.CLI/Commands/Cloud/Command/JsonDocumentBindingConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using CliFx.Exceptions; -using CliFx.Extensibility; -using System.Text.Json; - -namespace Meadow.CLI.Commands.Cloud.Command -{ - public class JsonDocumentBindingConverter : BindingConverter - { - public override JsonDocument Convert(string rawValue) - { - try { return JsonDocument.Parse(rawValue); } - catch (JsonException ex) - { - throw new CommandException($"Provided arguments is not valid JSON: {ex.Message}", showHelp: false, innerException: ex); - } - } - } -} diff --git a/Meadow.CLI/Commands/Cloud/Command/PublishCommand.cs b/Meadow.CLI/Commands/Cloud/Command/PublishCommand.cs deleted file mode 100644 index 29ad93fd..00000000 --- a/Meadow.CLI/Commands/Cloud/Command/PublishCommand.cs +++ /dev/null @@ -1,106 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Exceptions; -using CliFx.Infrastructure; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System.Linq; -using System.Text.Json; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Cloud.Command -{ - public enum QualityOfService - { - AtLeastOnce = 0, - AtMostOnce = 1, - ExactlyOnce = 2 - } - - [Command("cloud command publish", Description = "Publish a command to Meadow devices via the Meadow Service")] - public class PublishCommand : ICommand - { - private readonly ILogger _logger; - private readonly CommandService _commandService; - private readonly IdentityManager _identityManager; - IConfiguration _config; - - public PublishCommand(ILoggerFactory loggerFactory, CommandService commandService, IdentityManager identityManager, IConfiguration config) - { - _logger = loggerFactory.CreateLogger(); - _commandService = commandService; - _identityManager = identityManager; - _config = config; - } - - [CommandParameter(0, Description = "The name of the command", IsRequired = true, Name = "COMMAND_NAME")] - public string CommandName { get; set; } - - [CommandOption("collectionId", 'c', Description = "The target collection for publishing the command")] - public string CollectionId { get; set; } - - [CommandOption("deviceIds", 'd', Description = "The target devices for publishing the command")] - public string[] DeviceIds { get; set; } - - [CommandOption("args", 'a', Description = "The arguments for the command as a JSON string", Converter = typeof(JsonDocumentBindingConverter))] - public JsonDocument Arguments { get; set; } - - [CommandOption("qos", 'q', Description = "The MQTT-defined quality of service for the command")] - public QualityOfService QualityOfService { get; set; } - - [CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)")] - public string Host { get; set; } - - public async ValueTask ExecuteAsync(IConsole console) - { - if (string.IsNullOrWhiteSpace(CollectionId) && (DeviceIds == null || DeviceIds.Length == 0)) - { - throw new CommandException("Either a collection ID (-c|--collectionId) or a list of device IDs (-d|--deviceIds) must be specified.", showHelp: true); - } - - if (!string.IsNullOrWhiteSpace(CollectionId) && (DeviceIds != null && DeviceIds.Length > 0)) - { - throw new CommandException("Cannot specify both a collection ID (-c|--collectionId) and list of device IDs (-d|--deviceIds). Only one is allowed.", showHelp: true); - } - - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - - var token = await _identityManager.GetAccessToken(cancellationToken); - if (string.IsNullOrWhiteSpace(token)) - { - throw new CommandException("You must be signed into Meadow.Cloud to execute this command. Run 'meadow cloud login' to do so."); - } - - try - { - _logger.LogInformation($"Publishing '{CommandName}' command to Meadow.Cloud. Please wait..."); - if (!string.IsNullOrWhiteSpace(CollectionId)) - { - await _commandService.PublishCommandForCollection(CollectionId, CommandName, Arguments, (int)QualityOfService, Host, cancellationToken); - } - else if (DeviceIds.Any()) - { - await _commandService.PublishCommandForDevices(DeviceIds, CommandName, Arguments, (int)QualityOfService, Host, cancellationToken); - } - else - { - throw new CommandException("Cannot specify both a collection ID (-c|--collectionId) and list of device IDs (-d|--deviceIds). Only one is allowed."); - } - _logger.LogInformation("Publish command successful."); - } - catch (MeadowCloudAuthException ex) - { - throw new CommandException("You must be signed in to execute this command.", innerException: ex); - } - catch (MeadowCloudException ex) - { - throw new CommandException($"Publish command failed: {ex.Message}", innerException: ex); - } - } - } -} diff --git a/Meadow.CLI/Commands/Cloud/LoginCommand.cs b/Meadow.CLI/Commands/Cloud/LoginCommand.cs deleted file mode 100644 index c112a6da..00000000 --- a/Meadow.CLI/Commands/Cloud/LoginCommand.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("cloud login", Description = "Log into the Meadow Service")] - public class LoginCommand : ICommand - { - [CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)] - public string Host { get; set; } - - private readonly ILogger _logger; - IdentityManager _identityManager; - UserService _userService; - - public LoginCommand(ILoggerFactory loggerFactory, IdentityManager identityManager, UserService userService) - { - _logger = loggerFactory.CreateLogger(); - _identityManager = identityManager; - _userService = userService; - } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - var loginResult = await _identityManager.Login(Host, cancellationToken); - - if (loginResult) - { - var user = await _userService.GetMe(Host, cancellationToken); - _logger.LogInformation(user != null - ? $"Signed in as {user.Email}" - : "There was a problem retrieving your account information."); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/LogoutCommand.cs b/Meadow.CLI/Commands/Cloud/LogoutCommand.cs deleted file mode 100644 index cafec463..00000000 --- a/Meadow.CLI/Commands/Cloud/LogoutCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("cloud logout", Description = "Logout of the Meadow Service")] - public class LogoutCommand : ICommand - { - private readonly ILogger _logger; - IdentityManager _identityManager; - - public LogoutCommand(ILoggerFactory loggerFactory, IdentityManager identityManager) - { - _logger = loggerFactory.CreateLogger(); - _identityManager = identityManager; - } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - _identityManager.Logout(); - - _logger.LogInformation($"Signed out of Meadow Service"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/Package/CreatePackageCommand.cs b/Meadow.CLI/Commands/Cloud/Package/CreatePackageCommand.cs deleted file mode 100644 index 29eeab0f..00000000 --- a/Meadow.CLI/Commands/Cloud/Package/CreatePackageCommand.cs +++ /dev/null @@ -1,63 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("package create", Description = "Create Meadow Package")] - public class CreateCommand : ICommand - { - private readonly ILogger _logger; - PackageManager _packageManager; - - public CreateCommand(ILoggerFactory loggerFactory, PackageManager packageManager) - { - _logger = loggerFactory.CreateLogger(); - _packageManager = packageManager; - } - - [CommandOption("projectFilePath", 'p', Description = "The path to the project file (ie .csproj)", - IsRequired = true)] - public string ProjectPath { get; init; } = default!; - - [CommandOption("osVersion", 'v', Description = "Target OS version for the app", IsRequired = true)] - public string OsVersion { get; init; } = default!; - - [CommandOption("name", 'n', Description = "Name of the mpak file to be created", IsRequired = false)] - public string MpakName { get; init; } = default!; - - [CommandOption("filter", 'f', Description = "Glob pattern to filter files. ex ('app.dll', 'app*','{app.dll,meadow.dll}')", - IsRequired = false)] - public string Filter { get; init; } = "*"; - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - - try - { - var mpak = await _packageManager.CreatePackage(ProjectPath, OsVersion, MpakName, Filter); - if (!string.IsNullOrEmpty(mpak)) - { - _logger.LogInformation($"{mpak} created."); - } - } - catch (ArgumentException ex) - { - _logger.LogError(ex.Message); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/Package/ListPackagesCommand.cs b/Meadow.CLI/Commands/Cloud/Package/ListPackagesCommand.cs deleted file mode 100644 index 06cca826..00000000 --- a/Meadow.CLI/Commands/Cloud/Package/ListPackagesCommand.cs +++ /dev/null @@ -1,95 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Reflection; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("package list", Description = "List Meadow Packages")] - public class ListCommand : ICommand - { - private readonly ILogger _logger; - UserService _userService; - PackageService _packageService; - IConfiguration _config; - - public ListCommand(ILoggerFactory loggerFactory, UserService userService, PackageService packageService, IConfiguration config) - { - _logger = loggerFactory.CreateLogger(); - _userService = userService; - _packageService = packageService; - _config = config; - } - - [CommandOption("orgId", 'o', Description = "Organization Id", IsRequired = false)] - public string OrgId { get; set; } - [CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)] - public string Host { get; set; } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - - try - { - var userOrgs = await _userService.GetUserOrgs(Host, cancellationToken).ConfigureAwait(false); - if (!userOrgs.Any()) - { - _logger.LogInformation($"Please visit {_config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]} to register your account."); - return; - } - else if (userOrgs.Count() > 1 && string.IsNullOrEmpty(OrgId)) - { - _logger.LogInformation($"Please specify the orgId."); - return; - } - else if (userOrgs.Count() == 1 && string.IsNullOrEmpty(OrgId)) - { - OrgId = userOrgs.First().Id; - } - - if (!userOrgs.Select(x => x.Id).Contains(OrgId)) - { - _logger.LogInformation($"Invalid orgId: {OrgId}"); - return; - } - - } - catch (MeadowCloudAuthException) - { - _logger.LogInformation($"You must be signed in to execute this command."); - return; - } - - var packages = await _packageService.GetOrgPackages(OrgId, Host, cancellationToken); - - if(packages == null || packages.Count() == 0) - { - _logger.LogInformation("No packages found."); - } - foreach (var package in packages) - { - _logger.LogInformation($"{package.Id} | {package.Name} | {package.Description}"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/Package/PublishPackageCommand.cs b/Meadow.CLI/Commands/Cloud/Package/PublishPackageCommand.cs deleted file mode 100644 index 4449c6f3..00000000 --- a/Meadow.CLI/Commands/Cloud/Package/PublishPackageCommand.cs +++ /dev/null @@ -1,62 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("package publish", Description = "List Meadow Packages")] - public class PublishCommand : ICommand - { - private readonly ILogger _logger; - PackageService _packageService; - - public PublishCommand(ILoggerFactory loggerFactory, PackageService packageService) - { - _logger = loggerFactory.CreateLogger(); - _packageService = packageService; - } - - [CommandOption("packageId", 'p', Description = "ID of the package to publish", IsRequired = true)] - public string PackageId { get; init; } - - [CommandOption("collectionId", 'c', Description = "The target collection for publishing", IsRequired = true)] - public string CollectionId { get; set; } - [CommandOption("metadata", 'm', Description = "Pass through metadata", IsRequired = false)] - public string Metadata { get; set; } - [CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)] - public string Host { get; set; } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - - try - { - await _packageService.PublishPackage(PackageId, CollectionId, Metadata, Host, cancellationToken); - _logger.LogInformation("Publish successful."); - } - catch(MeadowCloudException mex) - { - _logger.LogInformation($"Publish failed: {mex.Message}"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Cloud/Package/UploadPackageCommand.cs b/Meadow.CLI/Commands/Cloud/Package/UploadPackageCommand.cs deleted file mode 100644 index b01db5b7..00000000 --- a/Meadow.CLI/Commands/Cloud/Package/UploadPackageCommand.cs +++ /dev/null @@ -1,99 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Cloud -{ - [Command("package upload", Description = "Upload Meadow Package")] - public class UploadCommand : ICommand - { - private readonly ILogger _logger; - UserService _userService; - PackageService _packageService; - IConfiguration _config; - - public UploadCommand(ILoggerFactory loggerFactory, UserService userService, PackageService packageService, IConfiguration config) - { - _logger = loggerFactory.CreateLogger(); - _userService = userService; - _packageService = packageService; - _config = config; - } - - [CommandOption("mpakPath", 'p', Description = "The full path of the mpak file", IsRequired = true)] - public string MpakPath { get; init; } - - [CommandOption("orgId", 'o', Description = "OrgId to upload to", IsRequired = false)] - public string OrgId { get; set; } - - [CommandOption("description", 'd', Description = "Description of the package", IsRequired = false)] - public string Description { get; set; } - [CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)] - public string Host { get; set; } - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await Task.Yield(); - - try - { - var userOrgs = await _userService.GetUserOrgs(Host, cancellationToken).ConfigureAwait(false); - if (!userOrgs.Any()) - { - _logger.LogInformation($"Please visit {_config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]} to register your account."); - return; - } - else if (userOrgs.Count() > 1 && string.IsNullOrEmpty(OrgId)) - { - _logger.LogInformation($"Please specify the orgId."); - return; - } - else if (userOrgs.Count() == 1 && string.IsNullOrEmpty(OrgId)) - { - OrgId = userOrgs.First().Id; - } - - if (!userOrgs.Select(x => x.Id).Contains(OrgId)) - { - _logger.LogInformation($"Invalid orgId: {OrgId}"); - return; - } - - } - catch (MeadowCloudAuthException) - { - _logger.LogInformation($"You must be signed in to execute this command."); - return; - } - - try - { - var package = await _packageService.UploadPackage(MpakPath, OrgId, Description, Host, cancellationToken); - _logger.LogInformation($"Upload complete. Package Id: {package.Id}"); - } - catch (MeadowCloudException mex) - { - _logger.LogError($"Upload failed: {mex.Message}"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/DeviceManagement/FlashEspCommand.cs b/Meadow.CLI/Commands/DeviceManagement/FlashEspCommand.cs deleted file mode 100644 index 12ba5ca2..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/FlashEspCommand.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Exceptions; -using Microsoft.Extensions.Logging; -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.DeviceManagement -{ - [Command("flash esp", Description = "Flash the ESP co-processor")] - public class FlashEspCommand : MeadowSerialCommand - { - [CommandOption("osVersion", 'v', Description = "Flash the ESP from a specific downloaded OS version - x.x.x.x")] - public string OSVersion { get; init; } - - public FlashEspCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.MonoDisable(false, cancellationToken); - - try - { - await Meadow.FlashEsp(osVersion: string.IsNullOrWhiteSpace(OSVersion) ? null : OSVersion, - cancellationToken: cancellationToken); - } - catch (FileNotFoundException) - { - Logger.LogError("Unable to flash ESP: Requested File Not Found"); - return; - } - catch (MeadowCommandException mce) - { - Logger.LogError($"Unable to flash ESP: Command failed with '{mce.MeadowMessage ?? "no message"}'"); - return; - } - catch (Exception ex) - { - Logger.LogError($"Unable to flash ESP: {ex.Message}"); - return; - } - - await Meadow.ResetMeadow(cancellationToken); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/DeviceManagement/FlashOsCommand.cs b/Meadow.CLI/Commands/DeviceManagement/FlashOsCommand.cs deleted file mode 100644 index 84e02e6b..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/FlashOsCommand.cs +++ /dev/null @@ -1,269 +0,0 @@ -using CliFx.Attributes; -using CliFx.Infrastructure; -#if WIN_10 -using LibUsbDotNet.Main; -#else -using LibUsbDotNet.LibUsb; -#endif -using Meadow.CLI.Commands.Utility; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Devices; -using Meadow.CLI.Core.Exceptions; -using Meadow.CLI.Core.Internals.Dfu; -using Microsoft.Extensions.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.DeviceManagement -{ - [Command("flash os", Description = "Update the OS on the Meadow Board")] - public class FlashOsCommand : MeadowSerialCommand - { - private const string MINIMUM_OS_VERSION = "0.6.1.0"; - - public FlashOsCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - } - - [CommandOption("osFile", 'o', Description = "Path to the Meadow OS binary")] - public string OSFile { get; init; } - - [CommandOption("runtimeFile", 'r', Description = "Path to the Meadow Runtime binary")] - public string RuntimeFile { get; init; } - - [CommandOption("skipDfu", 'd', Description = "Skip DFU flash")] - public bool SkipOS { get; init; } - - [CommandOption("skipEsp", 'e', Description = "Skip ESP flash")] - public bool SkipEsp { get; init; } - - [CommandOption("skipRuntime", 'k', Description = "Skip updating the runtime")] - public bool SkipRuntime { get; init; } - - [CommandOption("dontPrompt", 'p', Description = "Don't show bulk erase prompt")] - public bool DontPrompt { get; init; } - - [CommandOption("osVersion", 'v', Description = "Flash a specific downloaded OS version - x.x.x.x")] - public string OSVersion { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - Meadow?.Dispose(); - - var serialNumber = string.Empty; - - if (SkipOS == false) - { - try - { - // ToDo - restore two lines below when OS is fixed to succesfully set Dfu mode - broken as of RC2 - // await SetMeadowToDfuMode(SerialPortName, cancellationToken); - // await Task.Delay(2000, cancellationToken); - await FlashOsInDfuMode(); - serialNumber = GetSerialNumber(); - } - catch (Exception ex) - { - Logger.LogInformation($"Unable to flash Meadow OS: {ex.Message}"); - return; - } - } - else - { - Logger.LogInformation("Skipping step to flash Meadow OS"); - } - - await Task.Delay(2000, cancellationToken); - - Meadow = await FindCurrentMeadowDevice(SerialPortName, serialNumber, cancellationToken); - - var eraseFlash = await ValidateVersionAndPromptUserToEraseFlash(console, cancellationToken); - - if (eraseFlash) - { - // TODO We may want to move this into Meadow.EraseFlash() so the behaviour is centralised - var spinnerCancellationTokenSource = new CancellationTokenSource(); - var consoleSpinner = new ConsoleSpinner(); - Task consoleSpinnerTask = consoleSpinner.Turn(250, spinnerCancellationTokenSource.Token); - - await Meadow.EraseFlash(cancellationToken); - - // Cancel the spinner as soon as EraseFlash finishes - spinnerCancellationTokenSource.Cancel(); - - // Let's start spinning - await consoleSpinnerTask; - - Meadow?.Dispose(); - Meadow = null; - - await Task.Delay(2000, cancellationToken); - - Meadow = await FindCurrentMeadowDevice(SerialPortName, serialNumber, cancellationToken); - } - - await Meadow.WriteRuntimeAndEspBins(RuntimeFile, OSVersion, SkipRuntime, SkipEsp, cancellationToken); - - Meadow?.Dispose(); - } - - async Task ValidateVersionAndPromptUserToEraseFlash(IConsole console, CancellationToken cancellationToken) - { - // We just flashed the OS so it will show the current version - // But the runtime hasn't been updated yet so should match the previous OS version - System.Version previousOsVersion; - string checkName; - - try - { - var runtimeVersion = Meadow.DeviceInfo?.RuntimeVersion; - if (string.IsNullOrWhiteSpace(runtimeVersion) || (!string.IsNullOrWhiteSpace(runtimeVersion) && runtimeVersion.Equals("Unknown"))) - { - // Let's force a flash - return true; - } - else - { - previousOsVersion = new System.Version(runtimeVersion.Split(' ')[0]); - } - checkName = "runtime"; - } - catch - { - previousOsVersion = new System.Version(MINIMUM_OS_VERSION); - checkName = "OS"; - } - - // If less that B6.1 flash - if (previousOsVersion.CompareTo(new System.Version(MINIMUM_OS_VERSION)) <= 0) - { - // Ask User 1st before wiping - Logger.LogInformation($"Your {checkName} version is older than {MINIMUM_OS_VERSION} (or unreadable). A flash erase is highly recommended."); - var yesOrNo = "y"; - - if (!DontPrompt) - { - Logger.LogInformation($"Proceed? (Y/N) Press Y to erase flash, N to continue install without erasing"); - yesOrNo = await console.Input.ReadLineAsync(); - } - - if (yesOrNo.ToLower() == "y") - { - return true; - } - } - return false; - } - - async Task FindCurrentMeadowDevice(string serialPortName, string serialNumber, CancellationToken cancellationToken) - { - IMeadowDevice meadow = null; - - if (string.IsNullOrWhiteSpace(SerialPortName) == false) - { - meadow = await MeadowDeviceManager.GetMeadowForSerialPort( - serialPortName, - true, - Logger); - } - - if (meadow == null) - { - meadow = await MeadowDeviceManager.FindMeadowBySerialNumber( - serialNumber, - Logger, - cancellationToken: cancellationToken); - } - - return new MeadowDeviceHelper(meadow, Logger); - } - - async Task SetMeadowToDfuMode(string serialPortName, CancellationToken cancellationToken) - { - var dfuAttempts = 0; -#if WIN_10 - UsbRegistry dfuDevice; -#else - IUsbDevice dfuDevice; -#endif - while (true) - { - try - { - try - { - dfuDevice = DfuUtils.GetDeviceInBootloaderMode(); - break; - } - catch (MultipleDfuDevicesException) - { // Can't determine device to flash - throw; - } - catch (DeviceNotFoundException) - { // ignore and continue - } - - // No DFU devices found - attempt to set the meadow to DFU mode - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(serialPortName, false); - - if (device != null) - { - Logger.LogInformation("Entering DFU Mode"); - await device.EnterDfuMode(cancellationToken); - } - } - catch (Exception ex) - { - Logger.LogDebug( - "An exception occurred while switching device to DFU Mode. Exception: {0}", ex); - } - - switch (dfuAttempts) - { - case 5: - Logger.LogInformation( - "Having trouble putting Meadow in DFU Mode, please press RST button on Meadow and press enter to try again"); - - Console.ReadKey(); - break; - case 10: - Logger.LogInformation( - "Having trouble putting Meadow in DFU Mode, please hold BOOT button, press RST button and release BOOT button on Meadow and press enter to try again"); - - Console.ReadKey(); - break; - case > 15: - throw new Exception( - "Unable to place device in DFU mode, please disconnect the Meadow, hold the BOOT button, reconnect the Meadow, release the BOOT button and try again."); - } - - await Task.Delay(1000, cancellationToken); - - dfuAttempts++; - } - } - - async Task FlashOsInDfuMode() - { - if (string.IsNullOrEmpty(OSFile) == false) - { - await DfuUtils.FlashFile(fileName: OSFile, logger: Logger, format: DfuUtils.DfuFlashFormat.ConsoleOut); - } - else if (string.IsNullOrEmpty(OSVersion) == false) - { - await DfuUtils.FlashVersion(version: OSVersion, logger: Logger, DfuUtils.DfuFlashFormat.ConsoleOut); - } - else - { - await DfuUtils.FlashLatest(logger: Logger, format: DfuUtils.DfuFlashFormat.ConsoleOut); - } - } - - string GetSerialNumber() => DfuUtils.LastSerialNumber; - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/DeviceManagement/GetDeviceInfoCommand.cs b/Meadow.CLI/Commands/DeviceManagement/GetDeviceInfoCommand.cs deleted file mode 100644 index 06c3f328..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/GetDeviceInfoCommand.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement -{ - [Command("device info", Description = "Get the device info")] - public class GetDeviceInfoCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public GetDeviceInfoCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - var cancellationToken = console.RegisterCancellationHandler(); - - var deviceInfo = await Meadow.GetDeviceInfo(TimeSpan.FromSeconds(60), cancellationToken); - _logger.LogInformation(deviceInfo.ToString()); - } - } -} diff --git a/Meadow.CLI/Commands/DeviceManagement/GetDeviceMacAddressCommand.cs b/Meadow.CLI/Commands/DeviceManagement/GetDeviceMacAddressCommand.cs deleted file mode 100644 index e94f5dcb..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/GetDeviceMacAddressCommand.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement -{ - [Command("device mac", Description = "Read the ESP32's MAC address")] - public class GetDeviceMacAddressCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public GetDeviceMacAddressCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - var macAddress = await Meadow.GetDeviceMacAddress(cancellationToken); - if (macAddress == null) - { - _logger.LogInformation("Unable to retrieve device mac address"); - } - else - { - _logger.LogInformation("Device MAC: {macAddress}", macAddress); - } - } - } -} diff --git a/Meadow.CLI/Commands/DeviceManagement/GetDeviceNameCommand.cs b/Meadow.CLI/Commands/DeviceManagement/GetDeviceNameCommand.cs deleted file mode 100644 index 8ee5459c..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/GetDeviceNameCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement -{ - [Command("device name", Description = "Get the name of the Meadow")] - public class GetDeviceNameCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public GetDeviceNameCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - var deviceName = await Meadow.GetDeviceName(TimeSpan.FromSeconds(60), cancellationToken: cancellationToken); - - _logger.LogInformation($"Device Name: {deviceName}"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/DeviceManagement/ProvisionDeviceCommand.cs b/Meadow.CLI/Commands/DeviceManagement/ProvisionDeviceCommand.cs deleted file mode 100644 index f1d1af33..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/ProvisionDeviceCommand.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Logging; -using Meadow.CLI.Commands; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.IdentityModel.Tokens; -using Meadow.CLI.Core.CloudServices; -using System; -using System.Linq; -using System.Security.Cryptography.X509Certificates; -using System.Diagnostics; -using Meadow.CLI.Core.Exceptions; -using Microsoft.Extensions.Configuration; - -namespace Meadow.CommandLine.Commands.Cloud -{ - [Command("device provision", Description = "Registers and prepares connected device for use with Meadow Cloud")] - public class ProvisionDeviceCommand : MeadowSerialCommand - { - DeviceService _deviceService; - UserService _userService; - private readonly ILogger _logger; - IConfiguration _config; - - public ProvisionDeviceCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager, IConfiguration config, DeviceService deviceService, UserService userService) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - _config = config; - _deviceService = deviceService; - _userService = userService; - } - - [CommandOption("orgId", 'o', Description = "The target org for device registration", IsRequired = false)] - public string OrgId { get; set; } - [CommandOption("collectionId", 'c', Description = "The target collection for device registration", IsRequired = false)] - public string CollectionId { get; set; } - [CommandOption("name", 'n', Description = "Device friendly name", IsRequired = false)] - public string Name { get; set; } - [CommandOption("host", 'h', Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)] - public string Host { get; set; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - var cancellationToken = console.RegisterCancellationHandler(); - - try - { - var userOrgs = await _userService.GetUserOrgs(Host, cancellationToken).ConfigureAwait(false); - if (!userOrgs.Any()) - { - _logger.LogInformation($"Please visit {_config[Constants.MEADOW_CLOUD_HOST_CONFIG_NAME]} to register your account."); - return; - } - else if (userOrgs.Count() > 1 && string.IsNullOrEmpty(OrgId)) - { - _logger.LogInformation($"Please specify the orgId for this device provisioning."); - return; - } - else if (userOrgs.Count() == 1 && string.IsNullOrEmpty(OrgId)) - { - OrgId = userOrgs.First().Id; - } - - if (!userOrgs.Select(x => x.Id).Contains(OrgId)) - { - _logger.LogInformation($"Invalid orgId: {OrgId}"); - return; - } - } - catch (MeadowCloudAuthException) - { - _logger.LogInformation($"You must be signed in to execute this command."); - _logger.LogInformation($"Please run \"meadow cloud login\" to sign in to Meadow.Cloud."); - return; - } - - - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(this.SerialPortName, true, _logger); - var publicKey = await device.CloudRegisterDevice(cancellationToken); - var delim = "-----END PUBLIC KEY-----\n"; - publicKey = publicKey.Substring(0, publicKey.IndexOf(delim) + delim.Length); - - var result = await _deviceService.AddDevice(OrgId, device.DeviceInfo.ProcessorId, publicKey, CollectionId, Name, Host); - - if (result.isSuccess) - { - _logger.LogInformation("Device provisioned successfully"); - } - else - { - _logger.LogInformation(result.message); - } - - return; - } - } -} diff --git a/Meadow.CLI/Commands/DeviceManagement/UsePortCommand.cs b/Meadow.CLI/Commands/DeviceManagement/UsePortCommand.cs deleted file mode 100644 index 95ce255d..00000000 --- a/Meadow.CLI/Commands/DeviceManagement/UsePortCommand.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement -{ - [Command("use port", Description = "Set the preferred serial port")] - public class UsePortCommand : MeadowCommand - { - private readonly ILogger _logger; - - [CommandParameter(0)] - public string PortName { get; set; } - - public UsePortCommand(DownloadManager manager, ILoggerFactory loggerFactory) - : base(manager, loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public override ValueTask ExecuteAsync(IConsole console) - { - _logger.LogInformation($"Setting port to {PortName}"); - SettingsManager.SaveSetting(Setting.PORT, PortName); - return ValueTask.CompletedTask; - } - } -} diff --git a/Meadow.CLI/Commands/Esp32/RestartEsp32Command.cs b/Meadow.CLI/Commands/Esp32/RestartEsp32Command.cs deleted file mode 100644 index af4078c1..00000000 --- a/Meadow.CLI/Commands/Esp32/RestartEsp32Command.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Esp32 -{ - [Command("esp32 restart", Description = "Restart the ESP32")] - public class RestartEsp32Command : MeadowSerialCommand - { - private readonly ILogger _logger; - - public RestartEsp32Command(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.RestartEsp32(cancellationToken); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Esp32/WriteEsp32FileCommand.cs b/Meadow.CLI/Commands/Esp32/WriteEsp32FileCommand.cs deleted file mode 100644 index eadcb67c..00000000 --- a/Meadow.CLI/Commands/Esp32/WriteEsp32FileCommand.cs +++ /dev/null @@ -1,81 +0,0 @@ -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Esp32 -{ - [Command("esp32 file write", Description = "Write files to the ESP File System")] - public class WriteEsp32FileCommand : MeadowSerialCommand - { - [CommandOption( - "file", - 'f', - Description = "The file to write to the Meadow's ESP32 File System", - IsRequired = true)] - public string Filename { get; init; } - - [CommandOption( - "targetFile", - 't', - Description = "The filename to use on the Meadow's ESP32 File System")] - public string TargetFilename { get; init; } - - [CommandOption("McuDestAddress", Description = "Where file is stored in MCU's internal flash e.g. 0x10000", IsRequired = true)] - public string McuDestAddress { get; init; } - - private readonly ILogger _logger; - - public WriteEsp32FileCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - try - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - var targetFileName = string.IsNullOrWhiteSpace(TargetFilename) - ? GetTargetFileName() - : TargetFilename; - - _logger.LogInformation($"Writing {Filename} as {targetFileName} to ESP32"); - - _logger.LogDebug("Translated {filename} to {targetFileName}", Filename, targetFileName); - - System.Diagnostics.Trace.Assert( - string.IsNullOrWhiteSpace(targetFileName) == false, - "string.IsNullOrWhiteSpace(targetFileName)"); - - if (!File.Exists(Filename)) - { - _logger.LogInformation("Cannot find {filename}", Filename); - } - else - { - await Meadow.WriteFileToEspFlash(Filename, 0, McuDestAddress, cancellationToken); - - _logger.LogDebug("File written successfully"); - } - } - catch (Exception ex) - { - _logger.LogInformation($"Write failed {ex.Message}"); - } - } - - private string GetTargetFileName() - { - return new FileInfo(Filename).Name; - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/FileSystem/FormatFileSystemCommand.cs b/Meadow.CLI/Commands/FileSystem/FormatFileSystemCommand.cs deleted file mode 100644 index e1222f09..00000000 --- a/Meadow.CLI/Commands/FileSystem/FormatFileSystemCommand.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -/* This command isn't supported - -namespace Meadow.CLI.Commands.FileSystem -{ - [Command("fs format", Description = "Format a File System on the Meadow Board")] - public class FormatFileSystemCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public FormatFileSystemCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Formatting file system on partition {Partition}"); - - await Meadow.FormatFileSystem(cancellationToken: cancellationToken); - } - } -} - -*/ \ No newline at end of file diff --git a/Meadow.CLI/Commands/FileSystem/RenewFileSystemCommand.cs b/Meadow.CLI/Commands/FileSystem/RenewFileSystemCommand.cs deleted file mode 100644 index f9d93da7..00000000 --- a/Meadow.CLI/Commands/FileSystem/RenewFileSystemCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.FileSystem -{ - [Command("fs renew", Description = "Create a File System on the Meadow Board")] - public class RenewFileSystemCommand : MeadowSerialCommand - { - public RenewFileSystemCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await console.Output.WriteLineAsync("Renewing file system on the Meadow."); - - await Meadow.RenewFileSystem(cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Files/DeleteAllFilesCommand.cs b/Meadow.CLI/Commands/Files/DeleteAllFilesCommand.cs deleted file mode 100644 index 08ea3b15..00000000 --- a/Meadow.CLI/Commands/Files/DeleteAllFilesCommand.cs +++ /dev/null @@ -1,59 +0,0 @@ -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Files -{ - [Command("file delete all", Description = "Delete all files from the Meadow File System")] - public class DeleteAllFilesCommand : MeadowSerialCommand - { - public IList Files { get; init; } - -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public DeleteAllFilesCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Getting files on partition {Partition}"); - - var files = await Meadow.GetFilesAndCrcs( - TimeSpan.FromSeconds(60), - Partition, - cancellationToken); - - if (files.Any() == false) - { - _logger.LogInformation($"No files found on partition {Partition}"); - return; - } - - foreach (var file in files) - { - _logger.LogInformation($"Deleting {file} from partition {Partition}"); - - await Meadow.DeleteFile(file.FileName, (uint)Partition, cancellationToken); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Files/DeleteFileCommand.cs b/Meadow.CLI/Commands/Files/DeleteFileCommand.cs deleted file mode 100644 index 01264c09..00000000 --- a/Meadow.CLI/Commands/Files/DeleteFileCommand.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Files -{ - [Command("file delete", Description = "Delete files from the Meadow File System")] - public class DeleteFileCommand : MeadowSerialCommand - { - [CommandOption( - "files", - 'f', - Description = "The file(s) to delete from the Meadow Files System", - IsRequired = true)] - public IList Files { get; init; } - -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public uint Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public DeleteFileCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - foreach (var file in Files.Where(file => string.IsNullOrWhiteSpace(file) == false)) - { - if (!string.IsNullOrEmpty(file)) - { - _logger.LogInformation($"Deleting {file} from partition {Partition}"); - - await Meadow.DeleteFile(file, Partition, cancellationToken); - } - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Files/InitialFileBytesCommand.cs b/Meadow.CLI/Commands/Files/InitialFileBytesCommand.cs deleted file mode 100644 index 0eb39474..00000000 --- a/Meadow.CLI/Commands/Files/InitialFileBytesCommand.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Files -{ - [Command("file initial", Description = "Get the initial bytes from a file")] - public class InitialFileBytesCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to list the files")] -#endif - public uint Partition { get; init; } = 0; - - [CommandOption( - "file", - 'f', - Description = "The file to get the bytes from", - IsRequired = true)] - public string Filename { get; init; } - - private readonly ILogger _logger; - - public InitialFileBytesCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Getting files on partition {Partition}"); - - var res = await Meadow.GetInitialBytesFromFile(Filename, Partition, cancellationToken); - if (res != null) - { - _logger.LogInformation("Read {size} bytes from {filename}: {bytes}", - res.Length, - Filename, - res); - } - else - { - _logger.LogInformation("Failed to retrieve bytes from {filename}", Filename); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Files/ListFilesCommand.cs b/Meadow.CLI/Commands/Files/ListFilesCommand.cs deleted file mode 100644 index 27b60778..00000000 --- a/Meadow.CLI/Commands/Files/ListFilesCommand.cs +++ /dev/null @@ -1,96 +0,0 @@ -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Files -{ - [Command("file list", Description = "List files in the on-board filesystem")] - public class ListFilesCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to list the files")] -#endif - public const int FileSystemBlockSize = 4096; - - public int Partition { get; init; } = 0; - - [CommandOption("includeCrcs", 'i', Description = "Include the CRCs of the files")] - public bool IncludeCrcs { get; init; } - - private readonly ILogger _logger; - - public ListFilesCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Getting files on partition {Partition}"); - - var files = await Meadow.GetFilesAndCrcs( - TimeSpan.FromSeconds(60), - Partition, - cancellationToken); - - if (files.Any()) - { - var longestFileName = files.Select(x => x.FileName.Length) - .OrderByDescending(x => x) - .FirstOrDefault(); - - var totalBytesUsed = 0; - var totalBlocksUsed = 0; - - foreach (var file in files) - { - totalBytesUsed += file.FileSize; - totalBlocksUsed += (file.FileSize / FileSystemBlockSize) + 1; - - var line = $"{file.FileName.PadRight(longestFileName)}"; - - if (IncludeCrcs) - { - line = $"{line}\t{file.Crc:x8}"; - } - - if (file.FileSize > 1000000) - { - line = $"{line}\t{file.FileSize / 1000000d,7:0.0} MB "; - } - else if (file.FileSize > 1000) - { - line = $"{line}\t{file.FileSize / 1000,7:0} kB "; - } - else - { - line = $"{line}\t{file.FileSize,7} bytes"; - } - - _logger.LogInformation(line); - } - - _logger.LogInformation( - $"\nSummary:\n" + - $"\t{files.Count} files\n" + - $"\t{totalBytesUsed / 1000000d:0.00}MB of file data\n" + - $"\tSpanning {totalBlocksUsed} blocks\n" + - $"\tConsuming {totalBlocksUsed * FileSystemBlockSize / 1000000d:0.00}MB on disk"); - } - else - { - _logger.LogInformation("No files found."); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Files/WriteFileCommand.cs b/Meadow.CLI/Commands/Files/WriteFileCommand.cs deleted file mode 100644 index a7726ceb..00000000 --- a/Meadow.CLI/Commands/Files/WriteFileCommand.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Files -{ - [Command("file write", Description = "Write files to the Meadow File System")] - public class WritesFileCommand : MeadowSerialCommand - { - [CommandOption( - "files", - 'f', - Description = "The file(s) to write to the Meadow Files System", - IsRequired = true)] - public IList Files { get; init; } - - [CommandOption( - "targetFiles", - 't', - Description = "The filename(s) to use on the Meadow File System")] - public IList TargetFileNames { get; init; } = Array.Empty(); - -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public WritesFileCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogDebug( - $"{Files.Count} files and {TargetFileNames.Count} target files specified."); - - if (TargetFileNames.Any() && Files.Count != TargetFileNames.Count) - { - _logger.LogInformation( - $"Number of files to write ({Files.Count}) does not match the number of target file names ({TargetFileNames.Count})."); - - return; - } - - for (var i = 0; i < Files.Count; i++) - { - var targetFileName = GetTargetFileName(i); - _logger.LogDebug($"Translated {Files[i]} to {targetFileName}"); - - System.Diagnostics.Trace.Assert( - string.IsNullOrWhiteSpace(targetFileName) == false, - "string.IsNullOrWhiteSpace(targetFileName)"); - - if (!File.Exists(Files[i])) - { - _logger.LogInformation($"Cannot find {Files[i]}"); - } - else - { - _logger.LogInformation( - $"Writing {Files[i]} as {targetFileName} to partition {Partition}"); - - var result = await Meadow.WriteFile( - Files[i], - targetFileName, - TimeSpan.FromSeconds(60), - cancellationToken); - - _logger.LogDebug($"File written successfully? {result}"); - } - } - } - - private string GetTargetFileName(int i) - { - if (TargetFileNames.Any() - && TargetFileNames.Count >= i - && string.IsNullOrWhiteSpace(TargetFileNames[i]) == false) - { - return TargetFileNames[i]; - } - - return new FileInfo(Files[i]).Name; - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/MeadowCommand.cs b/Meadow.CLI/Commands/MeadowCommand.cs deleted file mode 100644 index 24ccb3b9..00000000 --- a/Meadow.CLI/Commands/MeadowCommand.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Reflection; -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands -{ - public abstract class MeadowCommand : ICommand - { - private protected ILoggerFactory LoggerFactory; - private protected DownloadManager DownloadManager; - - private protected MeadowCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory) - { - DownloadManager = downloadManager; - LoggerFactory = loggerFactory; - } - - [CommandOption("LogVerbosity", 'g', Description = "Log verbosity")] - public string[] Verbosity { get; init; } - - public virtual async ValueTask ExecuteAsync(IConsole console) - { - var logger = LoggerFactory.CreateLogger(typeof(MeadowCommand)); - var lastUpdateCheckString = SettingsManager.GetSetting(Setting.LastUpdateCheck); - var lastUpdateCheck = string.IsNullOrWhiteSpace(lastUpdateCheckString) - ? DateTimeOffset.MinValue - : DateTimeOffset.FromUnixTimeSeconds(long.Parse(lastUpdateCheckString)); - - bool updateExists; - Version currentVersion, latestVersion; - if (lastUpdateCheck.AddDays(1) < DateTimeOffset.UtcNow || SettingsManager.GetSetting(Setting.LatestVersion) == null) - { - var (ue, lv, cv) = await DownloadManager.CheckForUpdates(); - SettingsManager.SaveSetting(Setting.LastUpdateCheck, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()); - SettingsManager.SaveSetting(Setting.LatestVersion, lv); - updateExists = ue; - latestVersion = lv.ToVersion(); - currentVersion = cv.ToVersion(); - } - else - { - var currentVersionString = Assembly.GetEntryAssembly()! - .GetCustomAttribute()? - .Version; - - if (string.IsNullOrWhiteSpace(currentVersionString)) - { - logger.LogWarning("Cannot determine current application version."); - return; - } - - var latestVersionString = SettingsManager.GetSetting(Setting.LatestVersion); - if (latestVersionString == null) - { - logger.LogWarning("Cannot determine latest application version."); - return; - } - - currentVersion = currentVersionString.ToVersion(); - latestVersion = latestVersionString.ToVersion(); - updateExists = latestVersion > currentVersion; - } - - if (updateExists) - { - logger.LogInformation( - "A Meadow.CLI update is available. Current Version {currentVersion} Latest Version {latestVersion}.", - currentVersion, - latestVersion); - logger.LogInformation($"Run `dotnet tool update WildernessLabs.Meadow.CLI --global` to update. {Environment.NewLine}"); - } - } - } -} diff --git a/Meadow.CLI/Commands/MeadowSerialCommand.cs b/Meadow.CLI/Commands/MeadowSerialCommand.cs deleted file mode 100644 index c37ea420..00000000 --- a/Meadow.CLI/Commands/MeadowSerialCommand.cs +++ /dev/null @@ -1,105 +0,0 @@ -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Devices; -using Microsoft.Extensions.Logging; -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands -{ - public abstract class MeadowSerialCommand : MeadowCommand, ICommand, IDisposable - { - private protected ILogger Logger; - private protected MeadowDeviceManager MeadowDeviceManager; - private protected MeadowDeviceHelper Meadow; - - private protected MeadowSerialCommand(DownloadManager downloadManager, - ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory) - { - Logger = loggerFactory.CreateLogger(); - MeadowDeviceManager = meadowDeviceManager; - } - - [CommandOption("verbose", Description = "Provide Verbose Output")] - public bool Verbose { get; set; } = false; - - [CommandOption("SerialPort", 's', Description = "Meadow COM port")] - public string SerialPortName - { - get => GetSerialPort(); - set => SetSerialPort(value); - } - - //[CommandOption("listen", 'k', Description = "Keep port open to listen for output")] - //public bool Listen {get; init;} - - private string _serialPort; - - private string GetSerialPort() - { - if (string.IsNullOrWhiteSpace(_serialPort)) - { - // TODO: VALIDATE THE INPUT HERE, INPUT IS UNVALIDATED - var port = SettingsManager.GetSetting(Setting.PORT); - if (!string.IsNullOrWhiteSpace(port)) - SerialPortName = port.Trim(); - } - - return _serialPort; - } - - private bool PortExists(string name) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - // windows is case-insensitive - return System.IO.Ports.SerialPort.GetPortNames().Contains(name, StringComparer.InvariantCultureIgnoreCase); - } - - return System.IO.Ports.SerialPort.GetPortNames().Contains(name); - } - - private void SetSerialPort(string value) - { - _serialPort = value; - SettingsManager.SaveSetting(Setting.PORT, _serialPort); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - if (string.IsNullOrEmpty(SerialPortName)) - { - LoggerFactory.CreateLogger().LogError("No serial port selected. Use 'meadow use port' to select a port"); - Environment.Exit(-2); - } - if (!PortExists(SerialPortName)) - { - LoggerFactory.CreateLogger().LogError($"Selected serial port ({SerialPortName}) does not exist. Use 'meadow list ports' to view available options and 'meadow use port' to select a valid port"); - Environment.Exit(-2); - } - - await base.ExecuteAsync(console); - var meadow = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, logger: Logger); - if (meadow == null) - { - LoggerFactory.CreateLogger().LogCritical("Unable to find Meadow."); - Environment.Exit(-1); - } - - Meadow = new MeadowDeviceHelper(meadow, Logger); - } - - public void Dispose() - { - LoggerFactory?.Dispose(); - Meadow?.Dispose(); - } - } -} diff --git a/Meadow.CLI/Commands/Mono/MonoDisableCommand.cs b/Meadow.CLI/Commands/Mono/MonoDisableCommand.cs deleted file mode 100644 index 41c530d6..00000000 --- a/Meadow.CLI/Commands/Mono/MonoDisableCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Mono -{ - [Command("mono disable", Description = "Sets mono to NOT run on the Meadow board then resets it")] - public class MonoDisableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public MonoDisableCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - [CommandOption("force",'f', Description = "Send the Mono Disable Command even if Mono is already disabled")] - public bool Force { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.MonoDisable(Force, cancellationToken); - _logger.LogInformation("Mono Disabled Successfully"); - } - } -} diff --git a/Meadow.CLI/Commands/Mono/MonoEnableCommand.cs b/Meadow.CLI/Commands/Mono/MonoEnableCommand.cs deleted file mode 100644 index 0ce39fdd..00000000 --- a/Meadow.CLI/Commands/Mono/MonoEnableCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Mono -{ - [Command("mono enable", Description = "Sets mono to run on the Meadow board and then resets it")] - public class MonoEnableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public MonoEnableCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - [CommandOption("force",'f', Description = "Send the Mono Enable Command even if Mono is already enabled")] - public bool Force { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.MonoEnable(Force, cancellationToken); - _logger.LogInformation("Mono Enabled Successfully"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Mono/MonoFlashCommand.cs b/Meadow.CLI/Commands/Mono/MonoFlashCommand.cs deleted file mode 100644 index bcf074d2..00000000 --- a/Meadow.CLI/Commands/Mono/MonoFlashCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Mono -{ - [Command("mono flash", Description = "Uploads the mono runtime file to the Meadow device. Does NOT move it into place")] - public class MonoFlashCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public MonoFlashCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.MonoFlash(cancellationToken); - - _logger.LogInformation($"Mono Flashed Successfully"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Mono/MonoRunStateCommand.cs b/Meadow.CLI/Commands/Mono/MonoRunStateCommand.cs deleted file mode 100644 index e226117b..00000000 --- a/Meadow.CLI/Commands/Mono/MonoRunStateCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Mono -{ - [Command("mono state", Description = "Returns whether or not mono is enabled or disabled on the Meadow device")] - public class MonoRunStateCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public MonoRunStateCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - var runState = await Meadow.GetMonoRunState(cancellationToken); - - _logger.LogInformation($"Mono Run State: {(runState ? "Enabled" : "Disabled")}"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Mono/MonoUpdateRuntimeCommand.cs b/Meadow.CLI/Commands/Mono/MonoUpdateRuntimeCommand.cs deleted file mode 100644 index d6434373..00000000 --- a/Meadow.CLI/Commands/Mono/MonoUpdateRuntimeCommand.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Mono -{ - [Command("mono update rt", Description = "Uploads the mono runtime files to the Meadow device and moves it into place")] - public class MonoUpdateRuntimeCommand : MeadowSerialCommand - { - [CommandOption("filename",'f', Description = "The local name of the mono runtime file - Default is empty")] - public string Filename {get; init;} - - [CommandOption("osVersion", 'v', Description = "Flash the mono runtime from a specific downloaded OS version - x.x.x.x")] - public string OSVersion { get; init; } - - private readonly ILogger _logger; - - public MonoUpdateRuntimeCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.UpdateMonoRuntime(Filename, OSVersion, cancellationToken: cancellationToken); - - await Meadow.ResetMeadow(cancellationToken); - - _logger.LogInformation("Mono Flashed Successfully"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Nsh/NshDisableCommand.cs b/Meadow.CLI/Commands/Nsh/NshDisableCommand.cs deleted file mode 100644 index dc07883d..00000000 --- a/Meadow.CLI/Commands/Nsh/NshDisableCommand.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Nsh -{ - [Command("nsh disable", Description = "Disables NSH on the Meadow device")] - public class NshDisableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public NshDisableCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.NshDisable(cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Nsh/NshEnableCommand.cs b/Meadow.CLI/Commands/Nsh/NshEnableCommand.cs deleted file mode 100644 index 6c80b263..00000000 --- a/Meadow.CLI/Commands/Nsh/NshEnableCommand.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Nsh -{ - [Command("nsh enable", Description = "Enables NSH on the Meadow device")] - public class NshEnableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public NshEnableCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.NshEnable(cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Qspi/QspiInitCommand.cs b/Meadow.CLI/Commands/Qspi/QspiInitCommand.cs deleted file mode 100644 index e3bdbc0e..00000000 --- a/Meadow.CLI/Commands/Qspi/QspiInitCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Qspi -{ - [Command("qspi init", Description = "Init the QSPI on the Meadow")] - public class QspiInitCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - [CommandOption("value",'v', Description = "The QSPI Value to initialize", IsRequired = true)] - public int Value {get; init;} - - public QspiInitCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.QspiInit(Value, cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Qspi/QspiReadCommand.cs b/Meadow.CLI/Commands/Qspi/QspiReadCommand.cs deleted file mode 100644 index f4414d68..00000000 --- a/Meadow.CLI/Commands/Qspi/QspiReadCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Qspi -{ - [Command("qspi read", Description = "Read a QSPI value from the Meadow")] - public class QspiReadCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - [CommandOption("value",'v', Description = "The QSPI Value to read", IsRequired = true)] - public int Value {get; init;} - - public QspiReadCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.QspiRead(Value, cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Qspi/QspiWriteCommand.cs b/Meadow.CLI/Commands/Qspi/QspiWriteCommand.cs deleted file mode 100644 index 0904e57f..00000000 --- a/Meadow.CLI/Commands/Qspi/QspiWriteCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Qspi -{ - [Command("qspi write", Description = "Write a QSPI value to the Meadow")] - public class QspiWriteCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - [CommandOption("value",'v', Description = "The QSPI Value to write", IsRequired = true)] - public int Value {get; init;} - - public QspiWriteCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.QspiWrite(Value, cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Storage/EraseFlashCommand.cs b/Meadow.CLI/Commands/Storage/EraseFlashCommand.cs deleted file mode 100644 index 3b7ce0e2..00000000 --- a/Meadow.CLI/Commands/Storage/EraseFlashCommand.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Storage -{ - [Command("flash erase", Description = "Erase the flash on the Meadow Board")] - public class EraseFlashCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public EraseFlashCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation("Erasing flash."); - await Meadow.EraseFlash(cancellationToken); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Storage/VerifyFlashCommand.cs b/Meadow.CLI/Commands/Storage/VerifyFlashCommand.cs deleted file mode 100644 index 212d7ef9..00000000 --- a/Meadow.CLI/Commands/Storage/VerifyFlashCommand.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Storage -{ - [Command("flash verify", Description = "Verify the contents of the flash were deleted")] - public class VerifyFlashCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public VerifyFlashCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation("Verifying flash"); - await Meadow.VerifyErasedFlash(cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Trace/SetDeveloperValueCommand.cs b/Meadow.CLI/Commands/Trace/SetDeveloperValueCommand.cs deleted file mode 100644 index bad4be30..00000000 --- a/Meadow.CLI/Commands/Trace/SetDeveloperValueCommand.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Trace -{ - [Command("set developer", Description = "Set developer value")] - public class SetDeveloperValueCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public SetDeveloperValueCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - [CommandOption("developer", 'd', Description = "The developer value to set.")] - public ushort DeveloperLevel { get; set; } - - [CommandOption("value", 'v', Description = "The value to apply to the developer value. Valid values are 0 to 4,294,967,295")] - public uint Value { get; set; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - try - { - - await Meadow.SetDeveloper(DeveloperLevel, Value, cancellationToken); - } - catch (Exception ex) - { - _logger.LogError($"Error Setting Developer : {ex.Message}"); - } - } - } -} diff --git a/Meadow.CLI/Commands/Trace/TraceDisableCommand.cs b/Meadow.CLI/Commands/Trace/TraceDisableCommand.cs deleted file mode 100644 index b1f02dd6..00000000 --- a/Meadow.CLI/Commands/Trace/TraceDisableCommand.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Trace -{ - [Command("trace disable", Description = "Disable Trace Logging on the Meadow")] - public class TraceDisableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public TraceDisableCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.TraceDisable(cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Trace/TraceEnableCommand.cs b/Meadow.CLI/Commands/Trace/TraceEnableCommand.cs deleted file mode 100644 index 6593eb46..00000000 --- a/Meadow.CLI/Commands/Trace/TraceEnableCommand.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Trace -{ - [Command("trace enable", Description = "Enable trace logging on the Meadow")] - public class TraceEnableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public TraceEnableCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - [CommandOption("Level", 'l', Description = "The desired trace level")] - public uint? TraceLevel { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation("Enabling trace."); - await Meadow.TraceEnable(cancellationToken); - - if (TraceLevel.HasValue) - { - _logger.LogInformation("Setting trace level"); - await Meadow.SetTraceLevel(TraceLevel.Value, cancellationToken); - } - _logger.LogInformation("Trace enabled successfully"); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Trace/TraceLevelCommand.cs b/Meadow.CLI/Commands/Trace/TraceLevelCommand.cs deleted file mode 100644 index 2de264bb..00000000 --- a/Meadow.CLI/Commands/Trace/TraceLevelCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Trace -{ - [Command("trace level", Description = "Enable trace logging on the Meadow")] - public class TraceLevelCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public TraceLevelCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - [CommandOption("TraceLevel",'t', Description = "The desired trace level")] - public uint TraceLevel { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - await Meadow.SetTraceLevel(TraceLevel, cancellationToken); - } - } -} diff --git a/Meadow.CLI/Commands/Trace/UartTraceCommand.cs b/Meadow.CLI/Commands/Trace/UartTraceCommand.cs deleted file mode 100644 index 3d71c72b..00000000 --- a/Meadow.CLI/Commands/Trace/UartTraceCommand.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Trace -{ - [Command("uart trace", Description = "Configure trace logs to go to UART")] - public class UartTraceCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public UartTraceCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - [CommandOption("enable", 'e', Description = "Enable trace output to UART")] - public bool Enable { get; set; } = false; - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - if (Enable) - { - await Meadow.Uart1Trace(cancellationToken); - - _logger.LogInformation("Sending trace output to UART"); - } - else - { - await Meadow.Uart1Apps(cancellationToken); - _logger.LogInformation("Sending App output to UART"); - } - } - } -} diff --git a/Meadow.CLI/Commands/Utility/ConsoleSpinner.cs b/Meadow.CLI/Commands/Utility/ConsoleSpinner.cs deleted file mode 100644 index bd30deb0..00000000 --- a/Meadow.CLI/Commands/Utility/ConsoleSpinner.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Meadow.CLI.Commands.Utility -{ - public class ConsoleSpinner - { - private int counter = 0; - private char[] sequence = { '|', '/', '-', '\\' }; - - public async Task Turn(int delay = 100, CancellationToken cancellationToken = default) - { - while (!cancellationToken.IsCancellationRequested) - { - counter++; - Console.Write(sequence[counter % 4]); - Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); - await Task.Delay(delay, CancellationToken.None); // Not propogating the token intentionally. - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Utility/DebugCommand.cs b/Meadow.CLI/Commands/Utility/DebugCommand.cs deleted file mode 100644 index 818787c0..00000000 --- a/Meadow.CLI/Commands/Utility/DebugCommand.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Utility -{ - [Command("debug", Description = "Debug a Meadow Application")] - public class DebugCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public DebugCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = loggerFactory.CreateLogger(); - } - - // VS 2019 - 4024 - // VS 2017 - 4022 - // VS 2015 - 4020 - [CommandOption("DebugPort", 'p', Description = "The port to run the debug server on")] - public int Port { get; init; } = 4024; - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - using (var server = await Meadow.StartDebuggingSession(Port, cancellationToken)) - { - _logger.LogInformation("Debugging server started. Press enter to exit"); - await console.Input.ReadLineAsync(); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Utility/DownloadOsCommand.cs b/Meadow.CLI/Commands/Utility/DownloadOsCommand.cs deleted file mode 100644 index 6067ee45..00000000 --- a/Meadow.CLI/Commands/Utility/DownloadOsCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Utility -{ - [Command("download os", Description = "Downloads the latest Meadow.OS to the host PC")] - public class DownloadOsCommand : MeadowCommand - { - public DownloadOsCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory) : base(downloadManager, loggerFactory) - { - } - - [CommandOption("force", 'f', Description = "Force re-download of the OS", IsRequired = false)] - public bool Force { get; init; } = false; - - [CommandOption("osVersion", 'v', Description = "Download a specific OS version - x.x.x.x", IsRequired = false)] - public string OsVersion { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - await DownloadManager.DownloadOsBinaries(OsVersion, Force); - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Utility/InstallDfuUtilCommand.cs b/Meadow.CLI/Commands/Utility/InstallDfuUtilCommand.cs deleted file mode 100644 index b7eaf7d2..00000000 --- a/Meadow.CLI/Commands/Utility/InstallDfuUtilCommand.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; -using System.Security.Principal; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Utility -{ - [Command("install dfu-util", Description = "Install the DfuUtil utility")] - public class InstallDfuUtilCommand : MeadowCommand - { - private readonly ILogger _logger; - public InstallDfuUtilCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory) :base(downloadManager, loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - await base.ExecuteAsync(console); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - if(IsAdministrator()) - { - await DownloadManager.InstallDfuUtil(Environment.Is64BitOperatingSystem, cancellationToken); - } - else - { - _logger.LogInformation("To install dfu-util on Windows you'll need to open a Command Prompt or Terminal as an administrator and re-run the `meadow install dfu-util` command again."); - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - _logger.LogInformation("To install on macOS, run: brew install dfu-util"); - } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - _logger.LogInformation( - "To install on Linux, use the package manager to install the dfu-util package"); - } - } - - private static bool IsAdministrator() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var identity = WindowsIdentity.GetCurrent(); - var principal = new WindowsPrincipal(identity); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } - else - { - return false; - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Utility/ListPortsCommand.cs b/Meadow.CLI/Commands/Utility/ListPortsCommand.cs deleted file mode 100644 index aa5ce60e..00000000 --- a/Meadow.CLI/Commands/Utility/ListPortsCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; - -using CliFx.Attributes; -using CliFx.Infrastructure; - -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; - -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Utility -{ - [Command("list ports", Description = "List available COM ports")] - public class ListPortsCommand : MeadowCommand - { - private readonly ILogger _logger; - - public ListPortsCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory) : base(downloadManager, loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - foreach (var port in await MeadowDeviceManager.GetSerialPorts()) - { - _logger.LogInformation("Found Meadow: {port}", port); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Commands/Utility/ListenCommand.cs b/Meadow.CLI/Commands/Utility/ListenCommand.cs deleted file mode 100644 index 8dcae080..00000000 --- a/Meadow.CLI/Commands/Utility/ListenCommand.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core; -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Internals.MeadowCommunication; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.Utility -{ - [Command("listen", Description = "Listen for console output from Meadow")] - public class ListenCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public ListenCommand(DownloadManager downloadManager, ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(downloadManager, loggerFactory, meadowDeviceManager) - { - _logger = loggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - await base.ExecuteAsync(console); - - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation("Listening for Meadow Console output. Press Ctrl+C to exit"); - void ResponseHandler(object s, MeadowMessageEventArgs e) - { - var msg = string.IsNullOrWhiteSpace(e.Message) ? "[empty]" : e.Message; - - switch (e.MessageType) - { - case MeadowMessageType.Data: - _logger?.LogDebug(msg); // We may not need this - break; - case MeadowMessageType.ErrOutput: - _logger?.LogError(msg); - break; - default: - break; - } - }; - Meadow.MeadowDevice.DataProcessor.OnReceiveData += ResponseHandler; - try - { - await Task.Delay(-1, cancellationToken); - } - catch - { - // ignored - } - finally - { - Meadow.MeadowDevice.DataProcessor.OnReceiveData -= ResponseHandler; - } - } - } -} \ No newline at end of file diff --git a/Meadow.CLI/Meadow.CLI.Classic.csproj b/Meadow.CLI/Meadow.CLI.Classic.csproj deleted file mode 100644 index a6b63123..00000000 --- a/Meadow.CLI/Meadow.CLI.Classic.csproj +++ /dev/null @@ -1,74 +0,0 @@ - - - - Exe - net6.0 - true - Wilderness Labs, Inc - meadow - WildernessLabs.Meadow.CLI - Peter Moody, Adrian Stevens, Brian Kim, Pete Garafano, Dominique Louis - Wilderness Labs, Inc - true - 1.9.4.0 - AnyCPU - http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/ - icon.png - https://github.com/WildernessLabs/Meadow.CLI - Meadow, Meadow.Foundation, Meadow.CLI - Command-line interface for Meadow - false - false - false - false - meadow - latest - Copyright 2020-2023 Wilderness Labs - - - - ..\Meadow.CLI.Classic\bin\Debug - TRACE;DEBUG;NET;NETCOREAPP;WIN_10 - 4 - - - true - ..\Meadow.CLI.Classic\bin\Release - TRACE;WIN_10;RELEASE;NET;NETCOREAPP - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Always - - - - - - - diff --git a/Meadow.CLI/Meadow.CLI.csproj b/Meadow.CLI/Meadow.CLI.csproj deleted file mode 100644 index 02241e2c..00000000 --- a/Meadow.CLI/Meadow.CLI.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - - Exe - net6.0 - true - Wilderness Labs, Inc - meadow - WildernessLabs.Meadow.CLI - Peter Moody, Adrian Stevens, Brian Kim, Pete Garafano, Dominique Louis - Wilderness Labs, Inc - true - 1.9.4.0 - AnyCPU - http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/ - icon.png - https://github.com/WildernessLabs/Meadow.CLI - Meadow, Meadow.Foundation, Meadow.CLI - Command-line interface for Meadow - false - false - false - false - meadow - latest - Copyright 2020-2023 Wilderness Labs - - - - - - - - - - - - - - - - - - - - - - - - - - - - Always - - - - - - - diff --git a/Meadow.CLI/Program.cs b/Meadow.CLI/Program.cs deleted file mode 100644 index b0250e21..00000000 --- a/Meadow.CLI/Program.cs +++ /dev/null @@ -1,111 +0,0 @@ -using CliFx; -using Meadow.CLI.Commands; -using Meadow.CLI.Commands.Cloud.Command; -using Meadow.CLI.Core; -using Meadow.CLI.Core.CloudServices; -using Meadow.CLI.Core.DeviceManagement; -using Meadow.CLI.Core.Identity; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Serilog; -using Serilog.Events; -using System; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; - -namespace Meadow.CLI -{ - public class Program - { - public static async Task Main(string[] args) - { - var config = new ConfigurationBuilder() - .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) - .AddJsonFile("appsettings.json") - .Build(); - - var logLevel = LogEventLevel.Information; - - if (args.Contains("--verbose")) - logLevel = LogEventLevel.Verbose; - - var outputTemplate = logLevel == LogEventLevel.Verbose - ? "[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}" - : "{Message:lj}{NewLine}{Exception}"; - Log.Logger = new LoggerConfiguration().MinimumLevel.Verbose() - .WriteTo.Console(logLevel, outputTemplate) - .CreateLogger(); - - // Log that we're using a log level other than default of Information - if (logLevel != LogEventLevel.Information) - { - Console.WriteLine($"Using log level {logLevel}"); - } - - var services = new ServiceCollection(); - - services.AddLogging( - builder => - { - builder.AddSerilog(Log.Logger, dispose: true); - }); - - services.AddScoped(_ => config); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - AddCommandsAsServices(services); - - var serviceProvider = services.BuildServiceProvider(); - - try - { - await new CliApplicationBuilder().AddCommandsFromThisAssembly() - .UseTypeActivator(serviceProvider.GetService) - .SetExecutableName("meadow") - .Build() - .RunAsync(); - } - catch (Exception ex) - { - Console.WriteLine($"Operation failed: {ex.Message}"); -#if DEBUG - throw; //debug spew for debug builds -#endif - } - - Console.WriteLine("Done!"); - - Environment.Exit(0); - return 0; - } - - private static void AddCommandsAsServices(IServiceCollection services) - { - var assembly = System.Reflection.Assembly.GetAssembly(typeof(Program)); - Trace.Assert(assembly != null); - var types = assembly.GetTypes(); - - var commands = types.Where( - x => x.IsAssignableTo(typeof(MeadowSerialCommand)) - || x.IsAssignableTo(typeof(MeadowCommand)) - || x.IsAssignableTo(typeof(ICommand))) - .Where(x => !x.IsAbstract); - - foreach (var command in commands) - { - services.AddTransient(command); - } - } - } -} diff --git a/Meadow.CLI/Properties/launchSettings.json b/Meadow.CLI/Properties/launchSettings.json deleted file mode 100644 index 8260665f..00000000 --- a/Meadow.CLI/Properties/launchSettings.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "profiles": { - "AppDeploy": { - "commandName": "Project", - "commandLineArgs": "app deploy -f /Users/briankim/gh/OtaSample/bin/Debug/netstandard2.1/App.dll" - }, - "CloudLogin": { - "commandName": "Project", - "commandLineArgs": "cloud login --host https://staging.meadowcloud.dev" - }, - "CloudLogout": { - "commandName": "Project", - "commandLineArgs": "cloud logout" - }, - "DeviceProvision": { - "commandName": "Project", - "commandLineArgs": "device provision -o 5b1d2b0dab744a04b79b245d881e18b8" - }, - "DeviceInfo": { - "commandName": "Project", - "commandLineArgs": "device info" - }, - "DownloadOs": { - "commandName": "Project", - "commandLineArgs": "download os" - }, - "FileDelete": { - "commandName": "Project", - "commandLineArgs": "file delete -f dns.conf" - }, - "FileList": { - "commandName": "Project", - "commandLineArgs": "file list -i" - }, - "FileWrite": { - "commandName": "Project", - "commandLineArgs": "file write -f \"f:\\temp\\test.txt\"" - }, - "FlashErase": { - "commandName": "Project", - "commandLineArgs": "flash erase" - }, - "FlashEsp": { - "commandName": "Project", - "commandLineArgs": "flash esp" - }, - "FlashOS": { - "commandName": "Project", - "commandLineArgs": "flash os -d -k" - }, - "Help": { - "commandName": "Project", - "commandLineArgs": "-h" - }, - "InstallDfuUtil": { - "commandName": "Project", - "commandLineArgs": "install dfu-util" - }, - "ListenPort": { - "commandName": "Project", - "commandLineArgs": "listen -s COM16" - }, - "ListPorts": { - "commandName": "Project", - "commandLineArgs": "list ports" - }, - "MonoDisable": { - "commandName": "Project", - "commandLineArgs": "mono disable" - }, - "MonoEnable": { - "commandName": "Project", - "commandLineArgs": "mono enable" - }, - "MonoUpdateRt": { - "commandName": "Project", - "commandLineArgs": "mono update rt" - }, - "Package Create": { - "commandName": "Project", - "commandLineArgs": "package create -p /Users/briankim/gh/OtaSample/OtaSample.csproj -v 1.2.0.1" - }, - "Package List": { - "commandName": "Project", - "commandLineArgs": "package list -o 5b1d2b0dab744a04b79b245d881e18b8" - }, - "Package Publish": { - "commandName": "Project", - "commandLineArgs": "package publish -p 7aedf4b3e304482e97f2a43041ebc30b -c 4965ba4d6b504c879928494e9bbe415d -m \"this is my metadata\"" - }, - "Package Upload": { - "commandName": "Project", - "commandLineArgs": "package upload -p awesome_app.mpak -o 5b1d2b0dab744a04b79b245d881e18b8" - }, - "Collection List": { - "commandName": "Project", - "commandLineArgs": "collection list" - }, - "RegisterDevice": { - "commandName": "Project", - "commandLineArgs": "--RegisterDevice -s COM12" - }, - "StartDebugging": { - "commandName": "Project", - "commandLineArgs": "debug" - }, - "UsePort": { - "commandName": "Project", - "commandLineArgs": "use port COM7" - }, - "Version": { - "commandName": "Project", - "commandLineArgs": "version" - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/CliFxConsoleLoggerProvider.cs b/Meadow.CommandLine/CliFxConsoleLoggerProvider.cs deleted file mode 100644 index 76e6d233..00000000 --- a/Meadow.CommandLine/CliFxConsoleLoggerProvider.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Concurrent; -using CliFx.Infrastructure; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine -{ - public class CliFxConsoleLogger : ILogger - { - private readonly CliFxConsoleLoggerProviderConfig _config; - private readonly string _name; - private readonly IConsole _console; - - public CliFxConsoleLogger( - IConsole console, - string name, - CliFxConsoleLoggerProviderConfig config) => - (_console, _name, _config) = (console, name, config); - - - public void Log(LogLevel logLevel, - EventId eventId, - TState state, - Exception exception, - Func formatter) - { - if (!IsEnabled(logLevel)) - return; - _console.Output.WriteLine(formatter(state, exception)); - } - - public bool IsEnabled(LogLevel logLevel) => - logLevel >= _config.LogLevel; - - public IDisposable BeginScope(TState state) => default; - } - - public sealed class CliFxConsoleLoggerProvider : ILoggerProvider - { - private readonly CliFxConsoleLoggerProviderConfig _config; - private readonly IConsole _console; - private readonly ConcurrentDictionary _loggers = - new ConcurrentDictionary(); - - public CliFxConsoleLoggerProvider(CliFxConsoleLoggerProviderConfig config, IConsole console) => - (_config, _console) = (config, console); - - public ILogger CreateLogger(string categoryName) => - _loggers.GetOrAdd(categoryName, name => new CliFxConsoleLogger(_console, name, _config)); - - public void Dispose() => _loggers.Clear(); - } - - public class CliFxConsoleLoggerProviderConfig - { - public LogLevel LogLevel {get; init; } - } -} diff --git a/Meadow.CommandLine/Commands/Cloud/LoginCommand.cs b/Meadow.CommandLine/Commands/Cloud/LoginCommand.cs deleted file mode 100644 index ce7303f8..00000000 --- a/Meadow.CommandLine/Commands/Cloud/LoginCommand.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.Auth; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Cloud -{ - [Command("cloud login", Description = "Log into the Meadow Service")] - public class LoginCommand : ICommand - { - private readonly ILogger _logger; - - public LoginCommand(ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - var identityManager = new IdentityManager(); - var loginResult = await identityManager.LoginAsync(cancellationToken) - .ConfigureAwait(false); - - if (loginResult) - { - var cred = identityManager.GetCredentials(identityManager.WLRefreshCredentialName); - _logger.LogInformation($"Signed in as {cred.username}"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Cloud/LogoutCommand.cs b/Meadow.CommandLine/Commands/Cloud/LogoutCommand.cs deleted file mode 100644 index 715e585f..00000000 --- a/Meadow.CommandLine/Commands/Cloud/LogoutCommand.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.Auth; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Cloud -{ - [Command("cloud logout", Description = "Logout of the Meadow Service")] - public class LogoutCommand : ICommand - { - private readonly ILogger _logger; - - public LogoutCommand(ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - var identityManager = new IdentityManager(); - identityManager.Logout(); - - _logger.LogInformation($"Signed out of Meadow Service"); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/DeviceManagement/FlashEspCommand.cs b/Meadow.CommandLine/Commands/DeviceManagement/FlashEspCommand.cs deleted file mode 100644 index f8272e2d..00000000 --- a/Meadow.CommandLine/Commands/DeviceManagement/FlashEspCommand.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.DeviceManagement -{ - [Command("flash esp", Description = "Flash the ESP co-processor")] - public class FlashEspCommand : MeadowSerialCommand - { - public FlashEspCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - await device.FlashEsp(cancellationToken) - .ConfigureAwait(false); - - await device.ResetMeadow(cancellationToken) - .ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/DeviceManagement/FlashOsCommand.cs b/Meadow.CommandLine/Commands/DeviceManagement/FlashOsCommand.cs deleted file mode 100644 index db77e59c..00000000 --- a/Meadow.CommandLine/Commands/DeviceManagement/FlashOsCommand.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using LibUsbDotNet.Main; -using Meadow.CLI.Core; -using Meadow.CLI.Core.Internals.Dfu; -using MeadowCLI; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.DeviceManagement -{ - [Command("flash os", Description = "Update the OS on the Meadow Board")] - public class FlashOsCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public FlashOsCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = loggerFactory.CreateLogger(); - } - - [CommandOption("BinPath", 'b', Description = "Path to the Meadow OS binary")] - public string BinPath { get; init; } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - var dfuAttempts = 0; - UsbRegistry dfuDevice = null; - while (true) - { - try - { - try - { - dfuDevice = DfuUtils.GetDevice(); - break; - } - catch (MultipleDfuDevicesException) - { - // This is bad, we can't just blindly flash with multiple devices, let the user know - throw; - } - catch (DeviceNotFoundException) - { - // eat it. - } - - // No DFU device found, lets try to set the meadow to DFU mode. - using var device = await MeadowDeviceManager.GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken); - - _logger.LogInformation("Entering DFU Mode"); - await device.EnterDfuMode(cancellationToken) - .ConfigureAwait(false); - } - catch (FileNotFoundException) - { - _logger.LogError("Failed to find Serial Port."); - } - catch (Exception ex) - { - _logger.LogDebug( - "An exception occurred while switching device to DFU Mode. Exception: {0}", - ex); - } - - switch (dfuAttempts) - { - case 5: - _logger.LogInformation( - "Having trouble putting Meadow in DFU Mode, please press RST button on Meadow and press enter to try again"); - - await console.Input.ReadLineAsync(); - break; - case 10: - _logger.LogInformation( - "Having trouble putting Meadow in DFU Mode, please hold BOOT button, press RST button and release BOOT button on Meadow and press enter to try again"); - - await console.Input.ReadLineAsync(); - break; - case > 15: - throw new Exception( - "Unable to place device in DFU mode, please disconnect the Meadow, hold the BOOT button, reconnect the Meadow, release the BOOT button and try again."); - } - - // Lets give the device a little time to settle in and get picked up - await Task.Delay(1000, cancellationToken) - .ConfigureAwait(false); - - dfuAttempts++; - } - - // Get the serial number so that later we can pick the right device if the system has multiple meadow plugged in - var serialNumber = DfuUtils.GetDeviceSerial(dfuDevice); - - _logger.LogInformation("Device in DFU Mode, flashing OS"); - await DfuUtils.FlashOsAsync(device: dfuDevice, logger: _logger); - _logger.LogInformation("Device Flashed."); - - try - { - using var device = await MeadowDeviceManager.FindMeadowBySerialNumber( - serialNumber, - cancellationToken: - cancellationToken) - .ConfigureAwait(false); - - Trace.Assert(device != null, "device != null"); - - await device.UpdateMonoRuntime(BinPath, cancellationToken: cancellationToken); - - // Again, verify that Mono is disabled - Trace.Assert( - await device.GetMonoRunState(cancellationToken) - .ConfigureAwait(false), - "Meadow was expected to have Mono Disabled"); - - _logger.LogInformation("Flashing ESP"); - await device.FlashEsp(cancellationToken) - .ConfigureAwait(false); - - // Reset the meadow again to ensure flash worked. - await device.ResetMeadow(cancellationToken) - .ConfigureAwait(false); - - _logger.LogInformation("Enabling Mono and Resetting."); - while (await device.GetMonoRunState(cancellationToken) - .ConfigureAwait(false) - == false) - { - await device.MonoEnable(cancellationToken); - } - - // TODO: Verify that the device info returns the expected version - var deviceInfoString = await device - .GetDeviceInfo(cancellationToken: cancellationToken) - .ConfigureAwait(false); - - if (string.IsNullOrWhiteSpace(deviceInfoString)) - { - throw new Exception("Unable to retrieve device info."); - } - - var deviceInfo = new MeadowDeviceInfo(deviceInfoString); - _logger.LogInformation( - $"Updated Meadow to OS: {deviceInfo.MeadowOSVersion} ESP: {deviceInfo.CoProcessorOs}"); - - Environment.Exit(0); - } - catch (Exception ex) - { - console.Output.WriteLine(ex); - Environment.Exit(-1); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/DeviceManagement/GetDeviceInfoCommand.cs b/Meadow.CommandLine/Commands/DeviceManagement/GetDeviceInfoCommand.cs deleted file mode 100644 index 23a115ff..00000000 --- a/Meadow.CommandLine/Commands/DeviceManagement/GetDeviceInfoCommand.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.DeviceManagement -{ - [Command("device info", Description = "Get the device info")] - public class GetDeviceInfoCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public GetDeviceInfoCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - var deviceInfoString = await device.GetDeviceInfo(cancellationToken: cancellationToken).ConfigureAwait(false); - if (string.IsNullOrWhiteSpace(deviceInfoString)) - throw new Exception("Unable to retrieve device info"); - var deviceInfo = new MeadowDeviceInfo(deviceInfoString); - _logger.LogInformation(deviceInfo.ToString()); - } - } -} diff --git a/Meadow.CommandLine/Commands/DeviceManagement/GetDeviceNameCommand.cs b/Meadow.CommandLine/Commands/DeviceManagement/GetDeviceNameCommand.cs deleted file mode 100644 index f825321a..00000000 --- a/Meadow.CommandLine/Commands/DeviceManagement/GetDeviceNameCommand.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.DeviceManagement -{ - [Command("device name", Description = "Get the name of the Meadow")] - public class GetDeviceNameCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public GetDeviceNameCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - var deviceName = await device.GetDeviceName(cancellationToken: cancellationToken) - .ConfigureAwait(false); - - _logger.LogInformation($"Device Name: {deviceName}"); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/FileSystem/CreateFileSystemCommand.cs b/Meadow.CommandLine/Commands/FileSystem/CreateFileSystemCommand.cs deleted file mode 100644 index 83a810dd..00000000 --- a/Meadow.CommandLine/Commands/FileSystem/CreateFileSystemCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.FileSystem -{ - [Command("filesystem create", Description = "Create a File System on the Meadow Board")] - public class CreateFileSystemCommand : MeadowSerialCommand - { - public CreateFileSystemCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await console.Output.WriteLineAsync("Creating a file system on the Meadow."); - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken) - .ConfigureAwait(false); - - await device.CreateFileSystem(cancellationToken: cancellationToken).ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/FileSystem/FormatFileSystemCommand.cs b/Meadow.CommandLine/Commands/FileSystem/FormatFileSystemCommand.cs deleted file mode 100644 index c5999bd9..00000000 --- a/Meadow.CommandLine/Commands/FileSystem/FormatFileSystemCommand.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.FileSystem -{ - [Command("filesystem format", Description = "Format a File System on the Meadow Board")] - public class FormatFileSystemCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public FormatFileSystemCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Formatting file system on partition {Partition}"); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - await device.FormatFileSystem(cancellationToken: cancellationToken) - .ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/FileSystem/InitializeFileSystemCommand.cs b/Meadow.CommandLine/Commands/FileSystem/InitializeFileSystemCommand.cs deleted file mode 100644 index 50bb828b..00000000 --- a/Meadow.CommandLine/Commands/FileSystem/InitializeFileSystemCommand.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.FileSystem -{ - [Command("filesystem init", Description = "Mount the File System on the Meadow Board")] - public class InitializeFileSystemCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - public InitializeFileSystemCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Initializing filesystem in partition {Partition}"); - - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken) - .ConfigureAwait(false); - - await device.InitializeFileSystem(Partition, cancellationToken).ConfigureAwait(false); - } - - - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/FileSystem/MountFileSystemCommand.cs b/Meadow.CommandLine/Commands/FileSystem/MountFileSystemCommand.cs deleted file mode 100644 index 497d1eb3..00000000 --- a/Meadow.CommandLine/Commands/FileSystem/MountFileSystemCommand.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.FileSystem -{ - [Command("filesystem mount", Description = "Mount the File System on the Meadow Board")] - public class MountFileSystemCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public MountFileSystemCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Mounting partition {Partition}"); - - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken) - .ConfigureAwait(false); - - await device.MountFileSystem(Partition, cancellationToken) - .ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/FileSystem/PartitionFileSystemCommand.cs b/Meadow.CommandLine/Commands/FileSystem/PartitionFileSystemCommand.cs deleted file mode 100644 index 2a0f813b..00000000 --- a/Meadow.CommandLine/Commands/FileSystem/PartitionFileSystemCommand.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.FileSystem -{ - [Command("filesystem partition", Description = "Create a File System on the Meadow Board")] - public class PartitionFileSystemCommand : MeadowSerialCommand - { - -#if USE_PARTITIONS - [CommandOption("NumberOfPartitions", 'p', Description = "The number of partitions to create on the Meadow")] -#endif - public int NumberOfPartitions { get; init; } = 1; - - private readonly ILogger _logger; - public PartitionFileSystemCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation( - $"Partitioning filesystem into {NumberOfPartitions} partition(s)"); - - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken) - .ConfigureAwait(false); - - await device.PartitionFileSystem(NumberOfPartitions, cancellationToken) - .ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/FileSystem/RenewFileSystemCommand.cs b/Meadow.CommandLine/Commands/FileSystem/RenewFileSystemCommand.cs deleted file mode 100644 index b3f81395..00000000 --- a/Meadow.CommandLine/Commands/FileSystem/RenewFileSystemCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.FileSystem -{ - [Command("filesystem renew", Description = "Create a File System on the Meadow Board")] - public class RenewFileSystemCommand : MeadowSerialCommand - { - public RenewFileSystemCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - await console.Output.WriteLineAsync("Renewing file system on the Meadow."); - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken) - .ConfigureAwait(false); - - await device.RenewFileSystem(cancellationToken: cancellationToken).ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Files/DeleteFileCommand.cs b/Meadow.CommandLine/Commands/Files/DeleteFileCommand.cs deleted file mode 100644 index 63d20ecd..00000000 --- a/Meadow.CommandLine/Commands/Files/DeleteFileCommand.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Exceptions; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Files -{ - [Command("files delete", Description = "Delete files from the Meadow File System")] - public class DeleteFileCommand : MeadowSerialCommand - { - [CommandOption( - "files", - 'f', - Description = "The file(s) to delete from the Meadow Files System", - IsRequired = true)] - public IList Files { get; init; } - -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public DeleteFileCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - foreach (var file in Files.Where(file => string.IsNullOrWhiteSpace(file) == false)) - { - if (!string.IsNullOrEmpty(file)) - { - _logger.LogInformation($"Deleting {file} from partition {Partition}"); - - await device.DeleteFile(file, Partition, cancellationToken) - .ConfigureAwait(false); - } - } - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Files/ListFilesCommand.cs b/Meadow.CommandLine/Commands/Files/ListFilesCommand.cs deleted file mode 100644 index ae2f55a1..00000000 --- a/Meadow.CommandLine/Commands/Files/ListFilesCommand.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Files -{ - [Command("files list", Description = "List files in the on-board filesystem")] - public class ListFilesCommand : MeadowSerialCommand - { -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to list the files")] -#endif - public int Partition { get; init; } = 0; - - [CommandOption("includeCrcs", 'i', Description = "Include the CRCs of the files")] - public bool IncludeCrcs { get; init; } - - private readonly ILogger _logger; - - public ListFilesCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation($"Getting files on partition {Partition}"); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - var files = await device.GetFilesAndCrcs( - Partition, - cancellationToken: cancellationToken) - .ConfigureAwait(false); - - var longestFileName = files.Keys.Select(x => x.Length).OrderByDescending(x => x) - .FirstOrDefault(); - - if (IncludeCrcs) - { - foreach (var file in files) - _logger.LogInformation($"{file.Key.PadRight(longestFileName)}\t{file.Value:x8}"); - } - else - { - foreach (var file in files) - _logger.LogInformation($"{file.Key}"); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Files/WriteFileCommand.cs b/Meadow.CommandLine/Commands/Files/WriteFileCommand.cs deleted file mode 100644 index 9cffbe62..00000000 --- a/Meadow.CommandLine/Commands/Files/WriteFileCommand.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Files -{ - [Command("files write", Description = "Write files to the Meadow File System")] - public class WritesFileCommand : MeadowSerialCommand - { - [CommandOption( - "files", - 'f', - Description = "The file(s) to write to the Meadow Files System", - IsRequired = true)] - public IList Files { get; init; } - - [CommandOption( - "targetFiles", - 't', - Description = "The filename(s) to use on the Meadow File System")] - public IList TargetFileNames { get; init; } = Array.Empty(); - -#if USE_PARTITIONS - [CommandOption("Partition", 'p', Description = "The partition to write to on the Meadow")] -#endif - public int Partition { get; init; } = 0; - - private readonly ILogger _logger; - - public WritesFileCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - _logger.LogDebug( - $"{Files.Count} files and {TargetFileNames.Count} target files specified."); - - if (TargetFileNames.Any() && Files.Count != TargetFileNames.Count) - { - _logger.LogInformation( - $"Number of files to write ({Files.Count}) does not match the number of target file names ({TargetFileNames.Count})."); - - return; - } - - for (var i = 0; i < Files.Count; i++) - { - var targetFileName = GetTargetFileName(i); - _logger.LogDebug($"Translated {Files[i]} to {targetFileName}"); - - Trace.Assert( - string.IsNullOrWhiteSpace(targetFileName) == false, - "string.IsNullOrWhiteSpace(targetFileName)"); - - if (!File.Exists(Files[i])) - { - _logger.LogInformation($"Cannot find {Files[i]}"); - } - else - { - _logger.LogInformation( - $"Writing {Files[i]} as {targetFileName} to partition {Partition}"); - - var result = await device.WriteFile(Files[i], targetFileName, Partition, cancellationToken) - .ConfigureAwait(false); - - _logger.LogDebug($"File written successfully? {result}"); - } - } - } - - private string GetTargetFileName(int i) - { - if (TargetFileNames.Any() - && TargetFileNames.Count >= i - && string.IsNullOrWhiteSpace(TargetFileNames[i]) == false) - { - return TargetFileNames[i]; - } - - return new FileInfo(Files[i]).Name; - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/MeadowSerialCommand.cs b/Meadow.CommandLine/Commands/MeadowSerialCommand.cs deleted file mode 100644 index e9dd7de7..00000000 --- a/Meadow.CommandLine/Commands/MeadowSerialCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands -{ - public abstract class MeadowSerialCommand : ICommand - { - private protected ILoggerFactory LoggerFactory; - private protected MeadowDeviceManager MeadowDeviceManager; - - private protected MeadowSerialCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - { - LoggerFactory = loggerFactory; - MeadowDeviceManager = meadowDeviceManager; - } - - [CommandOption('v', Description = "Log verbosity")] - public string[] Verbosity { get; init; } - - [CommandOption("port", 's', Description = "Meadow COM port", IsRequired = true)] - public string SerialPortName { get; init; } - - [CommandOption("listen", 'k', Description = "Keep port open to listen for output")] - public bool Listen {get; init;} - - //private protected CancellationToken CancellationToken { get; init; } - - public abstract ValueTask ExecuteAsync(IConsole console); - } -} diff --git a/Meadow.CommandLine/Commands/Mono/MonoDisableCommand.cs b/Meadow.CommandLine/Commands/Mono/MonoDisableCommand.cs deleted file mode 100644 index dd475de2..00000000 --- a/Meadow.CommandLine/Commands/Mono/MonoDisableCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Mono -{ - [Command("mono disable", Description = "Disable Mono on the Meadow")] - public class MonoDisableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public MonoDisableCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.MonoDisable(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Mono/MonoEnableCommand.cs b/Meadow.CommandLine/Commands/Mono/MonoEnableCommand.cs deleted file mode 100644 index 43763471..00000000 --- a/Meadow.CommandLine/Commands/Mono/MonoEnableCommand.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Mono -{ - [Command("mono enable", Description = "Enable Mono on the Meadow Board")] - public class MonoEnableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public MonoEnableCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - await device.MonoEnable(cancellationToken) - .ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Mono/MonoFlashCommand.cs b/Meadow.CommandLine/Commands/Mono/MonoFlashCommand.cs deleted file mode 100644 index c96e1f1c..00000000 --- a/Meadow.CommandLine/Commands/Mono/MonoFlashCommand.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Mono -{ - [Command("mono flash", Description = "Get the Mono Run State on the Meadow Board")] - public class MonoFlashCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public MonoFlashCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - await device.MonoFlash(cancellationToken) - .ConfigureAwait(false); - - _logger.LogInformation($"Mono Flashed Successfully"); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Mono/MonoRunStateCommand.cs b/Meadow.CommandLine/Commands/Mono/MonoRunStateCommand.cs deleted file mode 100644 index d3981c53..00000000 --- a/Meadow.CommandLine/Commands/Mono/MonoRunStateCommand.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Mono -{ - [Command("mono state", Description = "Get the Mono Run State on the Meadow Board")] - public class MonoRunStateCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public MonoRunStateCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - var runState = await device.GetMonoRunState(cancellationToken) - .ConfigureAwait(false); - - _logger.LogInformation($"Mono Run State: {(runState ? "Enabled" : "Disabled")}"); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Mono/MonoUpdateRuntimeCommand.cs b/Meadow.CommandLine/Commands/Mono/MonoUpdateRuntimeCommand.cs deleted file mode 100644 index 15f52e84..00000000 --- a/Meadow.CommandLine/Commands/Mono/MonoUpdateRuntimeCommand.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Mono -{ - [Command("mono update rt", Description = "Get the Mono Run State on the Meadow Board")] - public class MonoUpdateRuntimeCommand : MeadowSerialCommand - { - [CommandOption("filename",'f', Description = "The local name of the mono runtime file. Default is empty.")] - public string Filename {get; init;} - - private readonly ILogger _logger; - - public MonoUpdateRuntimeCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - await device.UpdateMonoRuntime(Filename, cancellationToken: cancellationToken); - - await device.ResetMeadow(cancellationToken) - .ConfigureAwait(false); - - _logger.LogInformation($"Mono Flashed Successfully"); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Nsh/NshDisableCommand.cs b/Meadow.CommandLine/Commands/Nsh/NshDisableCommand.cs deleted file mode 100644 index c61413c7..00000000 --- a/Meadow.CommandLine/Commands/Nsh/NshDisableCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Nsh -{ - [Command("nsh disable", Description = "Disable Mono on the Meadow")] - public class NshDisableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public NshDisableCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.NshDisable(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Nsh/NshEnableCommand.cs b/Meadow.CommandLine/Commands/Nsh/NshEnableCommand.cs deleted file mode 100644 index fd835e10..00000000 --- a/Meadow.CommandLine/Commands/Nsh/NshEnableCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Nsh -{ - [Command("nsh enable", Description = "Disable Mono on the Meadow")] - public class NshEnableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public NshEnableCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.NshEnable(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Qspi/QspiInitCommand.cs b/Meadow.CommandLine/Commands/Qspi/QspiInitCommand.cs deleted file mode 100644 index c1419799..00000000 --- a/Meadow.CommandLine/Commands/Qspi/QspiInitCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Qspi -{ - [Command("qspi write", Description = "Write a QSPI value to the Meadow")] - public class QspiInitCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - [CommandOption("value",'v', Description = "The QSPI Value to initialize", IsRequired = true)] - public int Value {get; init;} - - public QspiInitCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.QspiInit(Value, cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Qspi/QspiReadCommand.cs b/Meadow.CommandLine/Commands/Qspi/QspiReadCommand.cs deleted file mode 100644 index 1b5d5b5a..00000000 --- a/Meadow.CommandLine/Commands/Qspi/QspiReadCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Qspi -{ - [Command("qspi read", Description = "Read a QSPI value from the Meadow")] - public class QspiReadCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - [CommandOption("value",'v', Description = "The QSPI Value to read", IsRequired = true)] - public int Value {get; init;} - - public QspiReadCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.QspiRead(Value, cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Qspi/QspiWriteCommand.cs b/Meadow.CommandLine/Commands/Qspi/QspiWriteCommand.cs deleted file mode 100644 index d72a29b9..00000000 --- a/Meadow.CommandLine/Commands/Qspi/QspiWriteCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Qspi -{ - [Command("qspi write", Description = "Write a QSPI value to the Meadow")] - public class QspiWriteCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - [CommandOption("value",'v', Description = "The QSPI Value to write", IsRequired = true)] - public int Value {get; init;} - - public QspiWriteCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.QspiWrite(Value, cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Storage/EraseFlashCommand.cs b/Meadow.CommandLine/Commands/Storage/EraseFlashCommand.cs deleted file mode 100644 index 21d096da..00000000 --- a/Meadow.CommandLine/Commands/Storage/EraseFlashCommand.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Storage -{ - [Command("flash erase", Description = "Erase the flash on the Meadow Board")] - public class EraseFlashCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - - public EraseFlashCommand(ILoggerFactory loggerFactory, - MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation("Erasing flash."); - using var device = await MeadowDeviceManager - .GetMeadowForSerialPort( - SerialPortName, - true, - cancellationToken) - .ConfigureAwait(false); - - await device.EraseFlash(cancellationToken) - .ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Commands/Storage/VerifyFlashCommand.cs b/Meadow.CommandLine/Commands/Storage/VerifyFlashCommand.cs deleted file mode 100644 index 81c87eb9..00000000 --- a/Meadow.CommandLine/Commands/Storage/VerifyFlashCommand.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Storage -{ - [Command("flash verify", Description = "Erase the flash on the Meadow Board")] - public class VerifyFlashCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public VerifyFlashCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - _logger.LogInformation("Verifying flash"); - using var device = await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - await device.VerifyErasedFlash(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/TraceCommands/TraceDisableCommand.cs b/Meadow.CommandLine/Commands/TraceCommands/TraceDisableCommand.cs deleted file mode 100644 index 5c6eaf84..00000000 --- a/Meadow.CommandLine/Commands/TraceCommands/TraceDisableCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.TraceCommands -{ - [Command("trace disable", Description = "Disable Trace Logging on the Meadow")] - public class TraceDisableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public TraceDisableCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.TraceDisable(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/TraceCommands/TraceEnableCommand.cs b/Meadow.CommandLine/Commands/TraceCommands/TraceEnableCommand.cs deleted file mode 100644 index 5c7e987f..00000000 --- a/Meadow.CommandLine/Commands/TraceCommands/TraceEnableCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI.Core.NewDeviceManagement; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.TraceCommands -{ - [Command("trace enable", Description = "Enable trace logging on the Meadow")] - public class TraceEnableCommand : MeadowSerialCommand - { - private readonly ILogger _logger; - public TraceEnableCommand(ILoggerFactory loggerFactory, MeadowDeviceManager meadowDeviceManager) - : base(loggerFactory, meadowDeviceManager) - { - _logger = LoggerFactory.CreateLogger(); - } - - public override async ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - using var device = - await MeadowDeviceManager.GetMeadowForSerialPort(SerialPortName, true, cancellationToken).ConfigureAwait(false); - - await device.TraceEnable(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Meadow.CommandLine/Commands/Utility/InstallDfuUtilCommand.cs b/Meadow.CommandLine/Commands/Utility/InstallDfuUtilCommand.cs deleted file mode 100644 index 57b7314e..00000000 --- a/Meadow.CommandLine/Commands/Utility/InstallDfuUtilCommand.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Runtime.Versioning; -using System.Security.Principal; -using System.Threading.Tasks; -using CliFx; -using CliFx.Attributes; -using CliFx.Infrastructure; -using Meadow.CLI; -using Microsoft.Extensions.Logging; - -namespace Meadow.CommandLine.Commands.Utility -{ - [Command("install dfu-util", Description = "Install the DfuUtil utility")] - public class InstallDfuUtilCommand : ICommand - { - private readonly ILogger _logger; - public InstallDfuUtilCommand(ILoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } - - public ValueTask ExecuteAsync(IConsole console) - { - var cancellationToken = console.RegisterCancellationHandler(); - - if (OperatingSystem.IsWindows() && IsAdministrator()) - { - var downloadManager = new DownloadManager(); - downloadManager.InstallDfuUtil(Environment.Is64BitOperatingSystem); - } - else if (OperatingSystem.IsMacOS()) - { - _logger.LogInformation("To install on macOS, run: brew install dfu-util"); - } else if (OperatingSystem.IsLinux()) - { - _logger.LogInformation( - "To install on Linux, use the package manager to install the dfu-util package"); - } - return ValueTask.CompletedTask; - } - - [SupportedOSPlatform("windows")] - private static bool IsAdministrator() - { - var identity = WindowsIdentity.GetCurrent(); - var principal = new WindowsPrincipal(identity); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } - } -} diff --git a/Meadow.CommandLine/Meadow.CommandLine.csproj b/Meadow.CommandLine/Meadow.CommandLine.csproj deleted file mode 100644 index c9fee628..00000000 --- a/Meadow.CommandLine/Meadow.CommandLine.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - net5.0 - - - - - - - - - - - - - - diff --git a/Meadow.CommandLine/Program.cs b/Meadow.CommandLine/Program.cs deleted file mode 100644 index 02a083b3..00000000 --- a/Meadow.CommandLine/Program.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using CliFx; -using Meadow.CLI.Core.NewDeviceManagement; -using Meadow.CommandLine.Commands; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Console; - -namespace Meadow.CommandLine -{ - public class Program - { - public static async Task Main(string[] args) - { - var services = new ServiceCollection(); - services.AddLogging( - builder => - { - var logLevel = LogLevel.Information; - var logModifier = args.FirstOrDefault(a => a.Contains("-v")) - ?.Count(x => x == 'v') ?? 0; - - logLevel -= logModifier; - if (logLevel < 0) - { - logLevel = 0; - } - - Console.WriteLine($"Using log level {logLevel}"); - builder.AddSimpleConsole(c => - { - c.ColorBehavior = LoggerColorBehavior.Enabled; - c.SingleLine = true; - c.UseUtcTimestamp = true; - }).SetMinimumLevel(logLevel); - }); - - services.AddSingleton(); - AddCommandsAsServices(services); - var serviceProvider = services.BuildServiceProvider(); - return await new CliApplicationBuilder().AddCommandsFromThisAssembly() - .UseTypeActivator(serviceProvider.GetService) - .Build() - .RunAsync(); - } - - private static void AddCommandsAsServices(IServiceCollection services) - { - var assembly = System.Reflection.Assembly.GetAssembly(typeof(Program)); - Trace.Assert(assembly != null); - var types = assembly.GetTypes(); - - var commands = types.Where( - x => x.IsAssignableTo(typeof(MeadowSerialCommand)) - || x.IsAssignableTo(typeof(ICommand))) - .Where(x => !x.IsAbstract); - - foreach (var command in commands) - { - services.AddTransient(command); - } - } - } -} \ No newline at end of file diff --git a/Meadow.CommandLine/Properties/launchSettings.json b/Meadow.CommandLine/Properties/launchSettings.json deleted file mode 100644 index b7401ddb..00000000 --- a/Meadow.CommandLine/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "Meadow.CommandLine": { - "commandName": "Project", - "commandLineArgs": "flash os -s COM14" - } - } -} \ No newline at end of file diff --git a/Meadow.Hcom/HcomHostRequestType.cs b/Meadow.Hcom/HcomHostRequestType.cs deleted file mode 100644 index fec2a5bd..00000000 --- a/Meadow.Hcom/HcomHostRequestType.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Meadow.Hcom -{ - /// - /// Messages sent from meadow to host - /// - public enum HcomHostRequestType : ushort - { - HCOM_HOST_REQUEST_UNDEFINED_REQUEST = 0x00 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_UNDEFINED, - - // Simple with some text message - HCOM_HOST_REQUEST_TEXT_REJECTED = 0x01 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_ACCEPTED = 0x02 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_CONCLUDED = 0x03 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_ERROR = 0x04 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_INFORMATION = 0x05 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_LIST_HEADER = 0x06 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_LIST_MEMBER = 0x07 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_CRC_MEMBER = 0x08 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_MONO_STDOUT = 0x09 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_DEVICE_INFO = 0x0A | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_TRACE_MSG = 0x0B | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_RECONNECT = 0x0C | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_TEXT_MONO_STDERR = 0x0d | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_FILE_START_OKAY = 0x0e | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_FILE_START_FAIL = 0x0f | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - - // The Meadow file name is enclosed in single quotes 'filename' and CLI will - // need to workout what file was being downloaded and start the download over - HCOM_HOST_REQUEST_DNLD_FAIL_RESEND = 0x12 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_HOST_REQUEST_DEVICE_PUBLIC_KEY = 0x13 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - - // Simple with debugger message from Meadow - HCOM_HOST_REQUEST_DEBUGGING_MONO_DATA = 0x01 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_BINARY, - HCOM_HOST_REQUEST_GET_INITIAL_FILE_BYTES = 0x02 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_BINARY, - } -} diff --git a/Meadow.Hcom/HcomMeadowRequestType.cs b/Meadow.Hcom/HcomMeadowRequestType.cs deleted file mode 100644 index 04bb2671..00000000 --- a/Meadow.Hcom/HcomMeadowRequestType.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace Meadow.Hcom -{ - /// - /// Messages to be sent to Meadow board from host - /// - public enum HcomMeadowRequestType : ushort - { - HCOM_MDOW_REQUEST_UNDEFINED_REQUEST = 0x00 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_UNDEFINED, - - HCOM_MDOW_REQUEST_CREATE_ENTIRE_FLASH_FS = 0x01 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_CHANGE_TRACE_LEVEL = 0x02 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_FORMAT_FLASH_FILE_SYS = 0x03 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_END_FILE_TRANSFER = 0x04 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_RESET_PRIMARY_MCU = 0x05 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_VERIFY_ERASED_FLASH = 0x06 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_PARTITION_FLASH_FS = 0x07 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MOUNT_FLASH_FS = 0x08 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_INITIALIZE_FLASH_FS = 0x09 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_BULK_FLASH_ERASE = 0x0a | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_ENTER_DFU_MODE = 0x0b | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_ENABLE_DISABLE_NSH = 0x0c | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_LIST_PARTITION_FILES = 0x0d | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_LIST_PART_FILES_AND_CRC = 0x0e | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_DISABLE = 0x0f | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_ENABLE = 0x10 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_RUN_STATE = 0x11 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_GET_DEVICE_INFORMATION = 0x12 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_PART_RENEW_FILE_SYS = 0x13 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_NO_TRACE_TO_HOST = 0x14 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_SEND_TRACE_TO_HOST = 0x15 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_END_ESP_FILE_TRANSFER = 0x16 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_READ_ESP_MAC_ADDRESS = 0x17 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_RESTART_ESP32 = 0x18 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_FLASH = 0x19 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_SEND_TRACE_TO_UART = 0x1a | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_NO_TRACE_TO_UART = 0x1b | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME = 0x1c | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_UPDATE_FILE_END = 0x1d | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_MONO_START_DBG_SESSION = 0x1e | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_GET_DEVICE_NAME = 0x1f | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_GET_INITIAL_FILE_BYTES = 0x20 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - - HCOM_MDOW_REQUEST_GET_FILES_AND_FOLDERS = 0xf3 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - - // Only used internally for testing - HCOM_MDOW_REQUEST_DEVELOPER = 0xf8 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - - HCOM_MDOW_REQUEST_S25FL_QSPI_INIT = 0xf4 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_S25FL_QSPI_WRITE = 0xf5 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_S25FL_QSPI_READ = 0xf6 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - - HCOM_MDOW_REQUEST_OTA_REGISTER_DEVICE = 0xf7 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE, - HCOM_MDOW_REQUEST_START_FILE_TRANSFER = 0x01 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_FILE_START, - HCOM_MDOW_REQUEST_DELETE_FILE_BY_NAME = 0x02 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_FILE_START, - HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER = 0x03 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_FILE_START, - - // These message are a header followed by text, one contains the texts length too - HCOM_MDOW_REQUEST_UPLOAD_FILE_INIT = 0x01 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_MDOW_REQUEST_EXEC_DIAG_APP_CMD = 0x02 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_MDOW_REQUEST_RTC_SET_TIME_CMD = 0x03 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_MDOW_REQUEST_RTC_READ_TIME_CMD = 0x04 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - HCOM_MDOW_REQUEST_RTC_WAKEUP_TIME_CMD = 0x05 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT, - - // Simple debugger message to Meadow - HCOM_MDOW_REQUEST_DEBUGGING_DEBUGGER_DATA = 0x01 | HcomProtocolHeaderTypes.HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_BINARY, - } -} diff --git a/Meadow.Hcom/HcomProtocolHeaderOffsets.cs b/Meadow.Hcom/HcomProtocolHeaderOffsets.cs deleted file mode 100644 index dcf60d45..00000000 --- a/Meadow.Hcom/HcomProtocolHeaderOffsets.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Meadow.Hcom -{ - public enum HcomProtocolHeaderOffsets - { - HCOM_PROTOCOL_REQUEST_HEADER_SEQ_OFFSET = 0, - HCOM_PROTOCOL_REQUEST_HEADER_VERSION_OFFSET = 2, - HCOM_PROTOCOL_REQUEST_HEADER_RQST_TYPE_OFFSET = 4, - HCOM_PROTOCOL_REQUEST_HEADER_EXTRA_DATA_OFFSET = 6, - HCOM_PROTOCOL_REQUEST_HEADER_USER_DATA_OFFSET = 8, - } -} diff --git a/Meadow.Hcom/HcomProtocolHeaderTypes.cs b/Meadow.Hcom/HcomProtocolHeaderTypes.cs deleted file mode 100644 index 61ab9a1c..00000000 --- a/Meadow.Hcom/HcomProtocolHeaderTypes.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Meadow.Hcom -{ - public enum HcomProtocolHeaderTypes : ushort - { - HCOM_PROTOCOL_HEADER_TYPE_UNDEFINED = 0x0000, - // Simple request types, include 4-byte user data - HCOM_PROTOCOL_HEADER_TYPE_SIMPLE = 0x0100, - // File releted request types, includes 4-byte user data (for the - // destination partition id), 4-byte file size, 4-byte checksum and - // variable length destination file name. - HCOM_PROTOCOL_HEADER_TYPE_FILE_START = 0x0200, - // Simple text. - HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_TEXT = 0x0300, - // Header followed by binary data. The size of the data can be up to - // HCOM_PROTOCOL_PACKET_MAX_SIZE minus header size - HCOM_PROTOCOL_HEADER_TYPE_SIMPLE_BINARY = 0x0400, - } -} diff --git a/Meadow.Hcom/Meadow.Hcom.6.0.0.csproj b/Meadow.Hcom/Meadow.Hcom.6.0.0.csproj deleted file mode 100644 index 434f30fe..00000000 --- a/Meadow.Hcom/Meadow.Hcom.6.0.0.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - net6.0 - enable - preview - true - MeadowCLIKey.snk - - - diff --git a/Meadow.Hcom/Meadow.Hcom.Classic.csproj b/Meadow.Hcom/Meadow.Hcom.Classic.csproj deleted file mode 100644 index 434f30fe..00000000 --- a/Meadow.Hcom/Meadow.Hcom.Classic.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - net6.0 - enable - preview - true - MeadowCLIKey.snk - - - diff --git a/Meadow.Hcom/Meadow.Hcom.csproj b/Meadow.Hcom/Meadow.Hcom.csproj deleted file mode 100644 index c8b3940b..00000000 --- a/Meadow.Hcom/Meadow.Hcom.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - netstandard2.0 - enable - preview - true - MeadowCLIKey.snk - - - diff --git a/Meadow.Hcom/MeadowCLIKey.snk b/Meadow.Hcom/MeadowCLIKey.snk deleted file mode 100644 index fea5c270..00000000 Binary files a/Meadow.Hcom/MeadowCLIKey.snk and /dev/null differ diff --git a/Meadow.Tools.code-workspace b/Meadow.Tools.code-workspace deleted file mode 100644 index 758ea169..00000000 --- a/Meadow.Tools.code-workspace +++ /dev/null @@ -1,19 +0,0 @@ -{ - "folders": [ - { - "path": "." - }, - { - "path": "../VS_Mac_Meadow_Extension" - }, - { - "path": "../VS_Win_Meadow_Extension" - }, - { - "path": "../VSCode_Meadow_Extension" - }, - { - "path": "../Meadow.Sdk" - } - ], -} \ No newline at end of file diff --git a/MeadowCLI.Classic.sln b/MeadowCLI.Classic.sln deleted file mode 100644 index db2232d9..00000000 --- a/MeadowCLI.Classic.sln +++ /dev/null @@ -1,39 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32014.148 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.CLI.Core.Classic", "Meadow.CLI.Core\Meadow.CLI.Core.Classic.csproj", "{7C3AF1F9-4FD3-45EE-844E-60D18D64CA1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.CLI.Classic", "Meadow.CLI\Meadow.CLI.Classic.csproj", "{C1ADC097-F805-4A35-9706-DF243D22E31E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.Hcom.6.0.0", "Meadow.Hcom\Meadow.Hcom.6.0.0.csproj", "{4CC9DB50-2CDA-41ED-B50E-3919243C4EC1}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7C3AF1F9-4FD3-45EE-844E-60D18D64CA1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7C3AF1F9-4FD3-45EE-844E-60D18D64CA1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7C3AF1F9-4FD3-45EE-844E-60D18D64CA1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7C3AF1F9-4FD3-45EE-844E-60D18D64CA1F}.Release|Any CPU.Build.0 = Release|Any CPU - {C1ADC097-F805-4A35-9706-DF243D22E31E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C1ADC097-F805-4A35-9706-DF243D22E31E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C1ADC097-F805-4A35-9706-DF243D22E31E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C1ADC097-F805-4A35-9706-DF243D22E31E}.Release|Any CPU.Build.0 = Release|Any CPU - {4CC9DB50-2CDA-41ED-B50E-3919243C4EC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4CC9DB50-2CDA-41ED-B50E-3919243C4EC1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4CC9DB50-2CDA-41ED-B50E-3919243C4EC1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4CC9DB50-2CDA-41ED-B50E-3919243C4EC1}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6FA96453-7A9C-4F78-89EE-676C4611C899} - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - EndGlobalSection -EndGlobal diff --git a/MeadowCLI.sln b/MeadowCLI.sln deleted file mode 100644 index dda49b96..00000000 --- a/MeadowCLI.sln +++ /dev/null @@ -1,45 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32014.148 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.CLI", "Meadow.CLI\Meadow.CLI.csproj", "{A411EB86-BBD0-47FA-B4F9-EB9CFFE63F43}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.CLI.Test", "Meadow.CLI.Test\Meadow.CLI.Test.csproj", "{0A7887E0-9DCA-4072-91D8-6409C5562243}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.Hcom.6.0.0", "Meadow.Hcom\Meadow.Hcom.6.0.0.csproj", "{197F26BB-F7CD-4ADA-9A15-ADBA36F825E1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.CLI.Core.6.0.0", "Meadow.CLI.Core\Meadow.CLI.Core.6.0.0.csproj", "{AD70EEEA-731F-445A-8AE8-6432B587D24C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A411EB86-BBD0-47FA-B4F9-EB9CFFE63F43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A411EB86-BBD0-47FA-B4F9-EB9CFFE63F43}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A411EB86-BBD0-47FA-B4F9-EB9CFFE63F43}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A411EB86-BBD0-47FA-B4F9-EB9CFFE63F43}.Release|Any CPU.Build.0 = Release|Any CPU - {0A7887E0-9DCA-4072-91D8-6409C5562243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0A7887E0-9DCA-4072-91D8-6409C5562243}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0A7887E0-9DCA-4072-91D8-6409C5562243}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0A7887E0-9DCA-4072-91D8-6409C5562243}.Release|Any CPU.Build.0 = Release|Any CPU - {197F26BB-F7CD-4ADA-9A15-ADBA36F825E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {197F26BB-F7CD-4ADA-9A15-ADBA36F825E1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {197F26BB-F7CD-4ADA-9A15-ADBA36F825E1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {197F26BB-F7CD-4ADA-9A15-ADBA36F825E1}.Release|Any CPU.Build.0 = Release|Any CPU - {AD70EEEA-731F-445A-8AE8-6432B587D24C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AD70EEEA-731F-445A-8AE8-6432B587D24C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD70EEEA-731F-445A-8AE8-6432B587D24C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AD70EEEA-731F-445A-8AE8-6432B587D24C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6FA96453-7A9C-4F78-89EE-676C4611C899} - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - EndGlobalSection -EndGlobal diff --git a/MeadowCLI.sln.DotSettings b/MeadowCLI.sln.DotSettings deleted file mode 100644 index d4a9fde6..00000000 --- a/MeadowCLI.sln.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - True \ No newline at end of file diff --git a/MeadowLogger/Abstractions/IExternalScopeProvider.cs b/MeadowLogger/Abstractions/IExternalScopeProvider.cs deleted file mode 100644 index d8d5a55a..00000000 --- a/MeadowLogger/Abstractions/IExternalScopeProvider.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Represents a storage of common scope data. - /// - public interface IExternalScopeProvider - { - /// - /// Executes callback for each currently active scope objects in order of creation. - /// All callbacks are guaranteed to be called inline from this method. - /// - /// The callback to be executed for every scope object - /// The state object to be passed into the callback - /// - void ForEachScope(Action callback, TState state); - - /// - /// Adds scope object to the list - /// - /// The scope object - /// The token that removes scope on dispose. - IDisposable Push(object state); - } -} \ No newline at end of file diff --git a/MeadowLogger/Abstractions/ILogger.cs b/MeadowLogger/Abstractions/ILogger.cs deleted file mode 100644 index 9bf53eb0..00000000 --- a/MeadowLogger/Abstractions/ILogger.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Represents a type used to perform logging. - /// - /// Aggregates most logging patterns to a single method. - public interface ILogger - { - /// - /// Writes a log entry. - /// - /// Entry will be written on this level. - /// Id of the event. - /// The entry to be written. Can be also an object. - /// The exception related to this entry. - /// Function to create a string message of the and . - void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter); - - /// - /// Checks if the given is enabled. - /// - /// level to be checked. - /// true if enabled. - bool IsEnabled(LogLevel logLevel); - - /// - /// Begins a logical operation scope. - /// - /// The identifier for the scope. - /// An IDisposable that ends the logical operation scope on dispose. - IDisposable BeginScope(TState state); - } -} \ No newline at end of file diff --git a/MeadowLogger/Abstractions/ILoggerFactory.cs b/MeadowLogger/Abstractions/ILoggerFactory.cs deleted file mode 100644 index f87b561d..00000000 --- a/MeadowLogger/Abstractions/ILoggerFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Represents a type used to configure the logging system and create instances of from - /// the registered s. - /// - public interface ILoggerFactory : IDisposable - { - /// - /// Creates a new instance. - /// - /// The category name for messages produced by the logger. - /// The . - ILogger CreateLogger(string categoryName); - - /// - /// Adds an to the logging system. - /// - /// The . - void AddProvider(ILoggerProvider provider); - } -} \ No newline at end of file diff --git a/MeadowLogger/Abstractions/ILoggerOfT.cs b/MeadowLogger/Abstractions/ILoggerOfT.cs deleted file mode 100644 index 39d1cb66..00000000 --- a/MeadowLogger/Abstractions/ILoggerOfT.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// A generic interface for logging where the category name is derived from the specified - /// type name. - /// Generally used to enable activation of a named from dependency injection. - /// - /// The type who's name is used for the logger category name. - public interface ILogger : ILogger - { - - } -} \ No newline at end of file diff --git a/MeadowLogger/Abstractions/ILoggerProvider.cs b/MeadowLogger/Abstractions/ILoggerProvider.cs deleted file mode 100644 index d61a753b..00000000 --- a/MeadowLogger/Abstractions/ILoggerProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Represents a type that can create instances of . - /// - public interface ILoggerProvider : IDisposable - { - /// - /// Creates a new instance. - /// - /// The category name for messages produced by the logger. - /// - ILogger CreateLogger(string categoryName); - } -} \ No newline at end of file diff --git a/MeadowLogger/Abstractions/ISupportExternalScope.cs b/MeadowLogger/Abstractions/ISupportExternalScope.cs deleted file mode 100644 index 7466a11f..00000000 --- a/MeadowLogger/Abstractions/ISupportExternalScope.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Represents a that is able to consume external scope information. - /// - public interface ISupportExternalScope - { - /// - /// Sets external scope information source for logger provider. - /// - /// - void SetScopeProvider(IExternalScopeProvider scopeProvider); - } -} \ No newline at end of file diff --git a/MeadowLogger/EventId.cs b/MeadowLogger/EventId.cs deleted file mode 100644 index 02fd2048..00000000 --- a/MeadowLogger/EventId.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Meadow.CLI.Core.Logging -{ - public readonly struct EventId - { - public static implicit operator EventId(int i) - { - return new EventId(i); - } - - public static bool operator ==(EventId left, EventId right) - { - return left.Equals(right); - } - - public static bool operator !=(EventId left, EventId right) - { - return !left.Equals(right); - } - - public EventId(int id, string name = null) - { - Id = id; - Name = name; - } - - public int Id { get; } - public string Name { get; } - - public override string ToString() - { - return Name ?? Id.ToString(); - } - - public bool Equals(EventId other) - { - return Id == other.Id; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - - return obj is EventId eventId && Equals(eventId); - } - - public override int GetHashCode() - { - return Id; - } - } -} \ No newline at end of file diff --git a/MeadowLogger/Extensions/LoggerExtensions.cs b/MeadowLogger/Extensions/LoggerExtensions.cs deleted file mode 100644 index 9bbd7daf..00000000 --- a/MeadowLogger/Extensions/LoggerExtensions.cs +++ /dev/null @@ -1,430 +0,0 @@ - // Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// IMeadowLogger extension methods for common scenarios. - /// - public static class MeadowLoggerExtensions - { - private static readonly Func _messageFormatter = MessageFormatter; - - //------------------------------------------DEBUG------------------------------------------// - - /// - /// Formats and writes a debug log message. - /// - /// The to write to. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogDebug(0, exception, "Error while processing request from {Address}", address) - public static void LogDebug(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Debug, eventId, exception, message, args); - } - - /// - /// Formats and writes a debug log message. - /// - /// The to write to. - /// The event id associated with the log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogDebug(0, "Processing request from {Address}", address) - public static void LogDebug(this ILogger logger, EventId eventId, string message, params object[] args) - { - logger.Log(LogLevel.Debug, eventId, message, args); - } - - /// - /// Formats and writes a debug log message. - /// - /// The to write to. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogDebug(exception, "Error while processing request from {Address}", address) - public static void LogDebug(this ILogger logger, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Debug, exception, message, args); - } - - /// - /// Formats and writes a debug log message. - /// - /// The to write to. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogDebug("Processing request from {Address}", address) - public static void LogDebug(this ILogger logger, string message, params object[] args) - { - logger.Log(LogLevel.Debug, message, args); - } - - //------------------------------------------TRACE------------------------------------------// - - /// - /// Formats and writes a trace log message. - /// - /// The to write to. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogTrace(0, exception, "Error while processing request from {Address}", address) - public static void LogTrace(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Trace, eventId, exception, message, args); - } - - /// - /// Formats and writes a trace log message. - /// - /// The to write to. - /// The event id associated with the log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogTrace(0, "Processing request from {Address}", address) - public static void LogTrace(this ILogger logger, EventId eventId, string message, params object[] args) - { - logger.Log(LogLevel.Trace, eventId, message, args); - } - - /// - /// Formats and writes a trace log message. - /// - /// The to write to. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogTrace(exception, "Error while processing request from {Address}", address) - public static void LogTrace(this ILogger logger, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Trace, exception, message, args); - } - - /// - /// Formats and writes a trace log message. - /// - /// The to write to. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogTrace("Processing request from {Address}", address) - public static void LogTrace(this ILogger logger, string message, params object[] args) - { - logger.Log(LogLevel.Trace, message, args); - } - - //------------------------------------------INFORMATION------------------------------------------// - - /// - /// Formats and writes an informational log message. - /// - /// The to write to. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogInformation(0, exception, "Error while processing request from {Address}", address) - public static void LogInformation(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Information, eventId, exception, message, args); - } - - /// - /// Formats and writes an informational log message. - /// - /// The to write to. - /// The event id associated with the log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogInformation(0, "Processing request from {Address}", address) - public static void LogInformation(this ILogger logger, EventId eventId, string message, params object[] args) - { - logger.Log(LogLevel.Information, eventId, message, args); - } - - /// - /// Formats and writes an informational log message. - /// - /// The to write to. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogInformation(exception, "Error while processing request from {Address}", address) - public static void LogInformation(this ILogger logger, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Information, exception, message, args); - } - - /// - /// Formats and writes an informational log message. - /// - /// The to write to. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogInformation("Processing request from {Address}", address) - public static void LogInformation(this ILogger logger, string message, params object[] args) - { - logger.Log(LogLevel.Information, message, args); - } - - //------------------------------------------WARNING------------------------------------------// - - /// - /// Formats and writes a warning log message. - /// - /// The to write to. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogWarning(0, exception, "Error while processing request from {Address}", address) - public static void LogWarning(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Warning, eventId, exception, message, args); - } - - /// - /// Formats and writes a warning log message. - /// - /// The to write to. - /// The event id associated with the log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogWarning(0, "Processing request from {Address}", address) - public static void LogWarning(this ILogger logger, EventId eventId, string message, params object[] args) - { - logger.Log(LogLevel.Warning, eventId, message, args); - } - - /// - /// Formats and writes a warning log message. - /// - /// The to write to. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogWarning(exception, "Error while processing request from {Address}", address) - public static void LogWarning(this ILogger logger, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Warning, exception, message, args); - } - - /// - /// Formats and writes a warning log message. - /// - /// The to write to. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogWarning("Processing request from {Address}", address) - public static void LogWarning(this ILogger logger, string message, params object[] args) - { - logger.Log(LogLevel.Warning, message, args); - } - - //------------------------------------------ERROR------------------------------------------// - - /// - /// Formats and writes an error log message. - /// - /// The to write to. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogError(0, exception, "Error while processing request from {Address}", address) - public static void LogError(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Error, eventId, exception, message, args); - } - - /// - /// Formats and writes an error log message. - /// - /// The to write to. - /// The event id associated with the log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogError(0, "Processing request from {Address}", address) - public static void LogError(this ILogger logger, EventId eventId, string message, params object[] args) - { - logger.Log(LogLevel.Error, eventId, message, args); - } - - /// - /// Formats and writes an error log message. - /// - /// The to write to. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogError(exception, "Error while processing request from {Address}", address) - public static void LogError(this ILogger logger, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Error, exception, message, args); - } - - /// - /// Formats and writes an error log message. - /// - /// The to write to. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogError("Processing request from {Address}", address) - public static void LogError(this ILogger logger, string message, params object[] args) - { - logger.Log(LogLevel.Error, message, args); - } - - //------------------------------------------CRITICAL------------------------------------------// - - /// - /// Formats and writes a critical log message. - /// - /// The to write to. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogCritical(0, exception, "Error while processing request from {Address}", address) - public static void LogCritical(this ILogger logger, EventId eventId, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Critical, eventId, exception, message, args); - } - - /// - /// Formats and writes a critical log message. - /// - /// The to write to. - /// The event id associated with the log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogCritical(0, "Processing request from {Address}", address) - public static void LogCritical(this ILogger logger, EventId eventId, string message, params object[] args) - { - logger.Log(LogLevel.Critical, eventId, message, args); - } - - /// - /// Formats and writes a critical log message. - /// - /// The to write to. - /// The exception to log. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogCritical(exception, "Error while processing request from {Address}", address) - public static void LogCritical(this ILogger logger, Exception exception, string message, params object[] args) - { - logger.Log(LogLevel.Critical, exception, message, args); - } - - /// - /// Formats and writes a critical log message. - /// - /// The to write to. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// logger.LogCritical("Processing request from {Address}", address) - public static void LogCritical(this ILogger logger, string message, params object[] args) - { - logger.Log(LogLevel.Critical, message, args); - } - - /// - /// Formats and writes a log message at the specified log level. - /// - /// The to write to. - /// Entry will be written on this level. - /// Format string of the log message. - /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, string message, params object[] args) - { - logger.Log(logLevel, 0, null, message, args); - } - - /// - /// Formats and writes a log message at the specified log level. - /// - /// The to write to. - /// Entry will be written on this level. - /// The event id associated with the log. - /// Format string of the log message. - /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, EventId eventId, string message, params object[] args) - { - logger.Log(logLevel, eventId, null, message, args); - } - - /// - /// Formats and writes a log message at the specified log level. - /// - /// The to write to. - /// Entry will be written on this level. - /// The exception to log. - /// Format string of the log message. - /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, Exception exception, string message, params object[] args) - { - logger.Log(logLevel, 0, exception, message, args); - } - - /// - /// Formats and writes a log message at the specified log level. - /// - /// The to write to. - /// Entry will be written on this level. - /// The event id associated with the log. - /// The exception to log. - /// Format string of the log message. - /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, EventId eventId, Exception exception, string message, params object[] args) - { - if (logger == null) - { - throw new ArgumentNullException(nameof(logger)); - } - - logger.Log(logLevel, eventId, new FormattedLogValues(message, args), exception, _messageFormatter); - } - - //------------------------------------------Scope------------------------------------------// - - /// - /// Formats the message and creates a scope. - /// - /// The to create the scope in. - /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" - /// An object array that contains zero or more objects to format. - /// A disposable scope object. Can be null. - /// - /// using(logger.BeginScope("Processing request from {Address}", address)) - /// { - /// } - /// - public static IDisposable BeginScope( - this ILogger logger, - string messageFormat, - params object[] args) - { - if (logger == null) - { - throw new ArgumentNullException(nameof(logger)); - } - - return logger.BeginScope(new FormattedLogValues(messageFormat, args)); - } - - //------------------------------------------HELPERS------------------------------------------// - - private static string MessageFormatter(FormattedLogValues state, Exception error) - { - return state.ToString(); - } - } -} \ No newline at end of file diff --git a/MeadowLogger/Extensions/LoggerFactoryExtensions.cs b/MeadowLogger/Extensions/LoggerFactoryExtensions.cs deleted file mode 100644 index b95890bd..00000000 --- a/MeadowLogger/Extensions/LoggerFactoryExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// ILoggerFactory extension methods for common scenarios. - /// - public static class LoggerFactoryExtensions - { - /// - /// Creates a new ILogger instance using the full name of the given type. - /// - /// The type. - /// The factory. - public static ILogger CreateLogger(this ILoggerFactory factory) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - return new Logger(factory); - } - /// - /// Creates a new ILogger instance using the full name of the given type. - /// - /// The factory. - /// The type. - public static ILogger CreateLogger(this ILoggerFactory factory, Type type) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(type)); - } - } -} \ No newline at end of file diff --git a/MeadowLogger/FormattedLogValues.cs b/MeadowLogger/FormattedLogValues.cs deleted file mode 100644 index e3e681d4..00000000 --- a/MeadowLogger/FormattedLogValues.cs +++ /dev/null @@ -1,304 +0,0 @@ - // Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// LogValues to enable formatting options supported by . - /// This also enables using {NamedformatItem} in the format string. - /// - public readonly struct FormattedLogValues : IReadOnlyList> - { - internal const int MaxCachedFormatters = 1024; - private const string NullFormat = "[null]"; - private static int _count; - private static ConcurrentDictionary _formatters = new ConcurrentDictionary(); - private readonly LogValuesFormatter _formatter; - private readonly object[] _values; - private readonly string _originalMessage; - - // for testing purposes - internal LogValuesFormatter Formatter => _formatter; - - public FormattedLogValues(string format, params object[] values) - { - if (values != null && values.Length != 0 && format != null) - { - if (_count >= MaxCachedFormatters) - { - if (!_formatters.TryGetValue(format, out _formatter)) - { - _formatter = new LogValuesFormatter(format); - } - } - else - { - _formatter = _formatters.GetOrAdd(format, f => - { - Interlocked.Increment(ref _count); - return new LogValuesFormatter(f); - }); - } - } - else - { - _formatter = null; - } - - _originalMessage = format ?? NullFormat; - _values = values; - } - - public KeyValuePair this[int index] - { - get - { - if (index < 0 || index >= Count) - { - throw new IndexOutOfRangeException(nameof(index)); - } - - if (index == Count - 1) - { - return new KeyValuePair("{OriginalFormat}", _originalMessage); - } - - return _formatter.GetValue(_values, index); - } - } - - public int Count - { - get - { - if (_formatter == null) - { - return 1; - } - - return _formatter.ValueNames.Count + 1; - } - } - - public IEnumerator> GetEnumerator() - { - for (int i = 0; i < Count; ++i) - { - yield return this[i]; - } - } - - public override string ToString() - { - if (_formatter == null) - { - return _originalMessage; - } - - return _formatter.Format(_values); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - - /// - /// Formatter to convert the named format items like {NamedformatItem} to format. - /// - public class LogValuesFormatter - { - private const string NullValue = "(null)"; - private static readonly object[] EmptyArray = new object[0]; - private static readonly char[] FormatDelimiters = { ',', ':' }; - private readonly string _format; - private readonly List _valueNames = new List(); - - public LogValuesFormatter(string format) - { - OriginalFormat = format; - - var sb = new StringBuilder(); - var scanIndex = 0; - var endIndex = format.Length; - - while (scanIndex < endIndex) - { - var openBraceIndex = FindBraceIndex(format, '{', scanIndex, endIndex); - var closeBraceIndex = FindBraceIndex(format, '}', openBraceIndex, endIndex); - - // Format item syntax : { index[,alignment][ :formatString] }. - var formatDelimiterIndex = FindIndexOfAny(format, FormatDelimiters, openBraceIndex, closeBraceIndex); - - if (closeBraceIndex == endIndex) - { - sb.Append(format, scanIndex, endIndex - scanIndex); - scanIndex = endIndex; - } - else - { - sb.Append(format, scanIndex, openBraceIndex - scanIndex + 1); - sb.Append(_valueNames.Count.ToString(CultureInfo.InvariantCulture)); - _valueNames.Add(format.Substring(openBraceIndex + 1, formatDelimiterIndex - openBraceIndex - 1)); - sb.Append(format, formatDelimiterIndex, closeBraceIndex - formatDelimiterIndex + 1); - - scanIndex = closeBraceIndex + 1; - } - } - - _format = sb.ToString(); - } - - public string OriginalFormat { get; private set; } - public List ValueNames => _valueNames; - - private static int FindBraceIndex(string format, char brace, int startIndex, int endIndex) - { - // Example: {{prefix{{{Argument}}}suffix}}. - var braceIndex = endIndex; - var scanIndex = startIndex; - var braceOccurenceCount = 0; - - while (scanIndex < endIndex) - { - if (braceOccurenceCount > 0 && format[scanIndex] != brace) - { - if (braceOccurenceCount % 2 == 0) - { - // Even number of '{' or '}' found. Proceed search with next occurence of '{' or '}'. - braceOccurenceCount = 0; - braceIndex = endIndex; - } - else - { - // An unescaped '{' or '}' found. - break; - } - } - else if (format[scanIndex] == brace) - { - if (brace == '}') - { - if (braceOccurenceCount == 0) - { - // For '}' pick the first occurence. - braceIndex = scanIndex; - } - } - else - { - // For '{' pick the last occurence. - braceIndex = scanIndex; - } - - braceOccurenceCount++; - } - - scanIndex++; - } - - return braceIndex; - } - - private static int FindIndexOfAny(string format, char[] chars, int startIndex, int endIndex) - { - var findIndex = format.IndexOfAny(chars, startIndex, endIndex - startIndex); - return findIndex == -1 ? endIndex : findIndex; - } - - public string Format(object[] values) - { - if (values != null) - { - for (int i = 0; i < values.Length; i++) - { - values[i] = FormatArgument(values[i]); - } - } - - return string.Format(CultureInfo.InvariantCulture, _format, values ?? EmptyArray); - } - - internal string Format() - { - return _format; - } - - internal string Format(object arg0) - { - return string.Format(CultureInfo.InvariantCulture, _format, FormatArgument(arg0)); - } - - internal string Format(object arg0, object arg1) - { - return string.Format(CultureInfo.InvariantCulture, _format, FormatArgument(arg0), FormatArgument(arg1)); - } - - internal string Format(object arg0, object arg1, object arg2) - { - return string.Format(CultureInfo.InvariantCulture, _format, FormatArgument(arg0), FormatArgument(arg1), FormatArgument(arg2)); - } - - public KeyValuePair GetValue(object[] values, int index) - { - if (index < 0 || index > _valueNames.Count) - { - throw new IndexOutOfRangeException(nameof(index)); - } - - if (_valueNames.Count > index) - { - return new KeyValuePair(_valueNames[index], values[index]); - } - - return new KeyValuePair("{OriginalFormat}", OriginalFormat); - } - - public IEnumerable> GetValues(object[] values) - { - var valueArray = new KeyValuePair[values.Length + 1]; - for (var index = 0; index != _valueNames.Count; ++index) - { - valueArray[index] = new KeyValuePair(_valueNames[index], values[index]); - } - - valueArray[valueArray.Length - 1] = new KeyValuePair("{OriginalFormat}", OriginalFormat); - return valueArray; - } - - private object FormatArgument(object value) - { - if (value == null) - { - return NullValue; - } - - // since 'string' implements IEnumerable, special case it - if (value is string) - { - return value; - } - - // if the value implements IEnumerable, build a comma separated string. - var enumerable = value as IEnumerable; - if (enumerable != null) - { - return string.Join(", ", enumerable.Cast().Select(o => o ?? NullValue)); - } - - return value; - } - - } -} \ No newline at end of file diff --git a/MeadowLogger/LogLevel.cs b/MeadowLogger/LogLevel.cs deleted file mode 100644 index 78cce186..00000000 --- a/MeadowLogger/LogLevel.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Defines logging severity levels. - /// - public enum LogLevel - { - /// - /// Logs that contain the most detailed messages. These messages may contain sensitive application data. - /// These messages are disabled by default and should never be enabled in a production environment. - /// - Trace = 0, - - /// - /// Logs that are used for interactive investigation during development. These logs should primarily contain - /// information useful for debugging and have no long-term value. - /// - Debug = 1, - - /// - /// Logs that track the general flow of the application. These logs should have long-term value. - /// - Information = 2, - - /// - /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the - /// application execution to stop. - /// - Warning = 3, - - /// - /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a - /// failure in the current activity, not an application-wide failure. - /// - Error = 4, - - /// - /// Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires - /// immediate attention. - /// - Critical = 5, - - /// - /// Not used for writing log messages. Specifies that a logging category should not write any messages. - /// - None = 6, - } -} \ No newline at end of file diff --git a/MeadowLogger/Logger.cs b/MeadowLogger/Logger.cs deleted file mode 100644 index 197d0bc0..00000000 --- a/MeadowLogger/Logger.cs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Meadow.CLI.Core.Logging -{ - internal class Logger : ILogger - { - public LoggerInformation[] Loggers { get; set; } - public MessageLogger[] MessageLoggers { get; set; } - public ScopeLogger[] ScopeLoggers { get; set; } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - var loggers = MessageLoggers; - if (loggers == null) - { - return; - } - - List exceptions = null; - foreach (var loggerInfo in loggers) - { - if (!loggerInfo.IsEnabled(logLevel)) - { - continue; - } - - try - { - loggerInfo.Logger.Log(logLevel, eventId, state, exception, formatter); - } - catch (Exception ex) - { - if (exceptions == null) - { - exceptions = new List(); - } - - exceptions.Add(ex); - } - } - - if (exceptions != null && exceptions.Count > 0) - { - throw new AggregateException( - message: "An error occurred while writing to logger(s).", innerExceptions: exceptions); - } - } - - public bool IsEnabled(LogLevel logLevel) - { - var loggers = MessageLoggers; - if (loggers == null) - { - return false; - } - - List exceptions = null; - foreach (var loggerInfo in loggers) - { - if (!loggerInfo.IsEnabled(logLevel)) - { - continue; - } - - try - { - if (loggerInfo.Logger.IsEnabled(logLevel)) - { - return true; - } - } - catch (Exception ex) - { - if (exceptions == null) - { - exceptions = new List(); - } - - exceptions.Add(ex); - } - } - - if (exceptions != null && exceptions.Count > 0) - { - throw new AggregateException( - message: "An error occurred while writing to logger(s).", - innerExceptions: exceptions); - } - - return false; - } - - public IDisposable BeginScope(TState state) - { - var loggers = ScopeLoggers; - - if (loggers == null) - { - return NullScope.Instance; - } - - if (loggers.Length == 1) - { - return loggers[0].CreateScope(state); - } - - var scope = new Scope(loggers.Length); - List exceptions = null; - for (var index = 0; index < loggers.Length; index++) - { - var scopeLogger = loggers[index]; - - try - { - scope.SetDisposable(index, scopeLogger.CreateScope(state)); - } - catch (Exception ex) - { - if (exceptions == null) - { - exceptions = new List(); - } - - exceptions.Add(ex); - } - } - - if (exceptions != null && exceptions.Count > 0) - { - throw new AggregateException( - message: "An error occurred while writing to logger(s).", innerExceptions: exceptions); - } - - return scope; - } - - private class Scope : IDisposable - { - private bool _isDisposed; - - private IDisposable _disposable0; - private IDisposable _disposable1; - private readonly IDisposable[] _disposable; - - public Scope(int count) - { - if (count > 2) - { - _disposable = new IDisposable[count - 2]; - } - } - - public void SetDisposable(int index, IDisposable disposable) - { - switch (index) - { - case 0: - _disposable0 = disposable; - break; - case 1: - _disposable1 = disposable; - break; - default: - _disposable[index - 2] = disposable; - break; - } - } - - public void Dispose() - { - if (!_isDisposed) - { - _disposable0?.Dispose(); - _disposable1?.Dispose(); - - if (_disposable != null) - { - var count = _disposable.Length; - for (var index = 0; index != count; ++index) - { - if (_disposable[index] != null) - { - _disposable[index].Dispose(); - } - } - } - - _isDisposed = true; - } - } - } - } -} \ No newline at end of file diff --git a/MeadowLogger/LoggerInformation.cs b/MeadowLogger/LoggerInformation.cs deleted file mode 100644 index 0b5f6dbc..00000000 --- a/MeadowLogger/LoggerInformation.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - internal readonly struct MessageLogger - { - public MessageLogger(ILogger logger, string category, Type providerType, LogLevel? minLevel, Func filter) - { - Logger = logger; - Category = category; - ProviderType = providerType; - MinLevel = minLevel; - Filter = filter; - } - - public ILogger Logger { get; } - - public string Category { get; } - - public Type ProviderType { get; } - - public LogLevel? MinLevel { get; } - - public Func Filter { get; } - - public bool IsEnabled(LogLevel level) - { - if (MinLevel != null && level < MinLevel) - { - return false; - } - - if (Filter != null) - { - return Filter(ProviderType.FullName, Category, level); - } - - return true; - } - } - - internal readonly struct ScopeLogger - { - public ScopeLogger(ILogger logger, IExternalScopeProvider externalScopeProvider) - { - Logger = logger; - ExternalScopeProvider = externalScopeProvider; - } - - public ILogger Logger { get; } - - public IExternalScopeProvider ExternalScopeProvider { get; } - - public IDisposable CreateScope(TState state) - { - if (ExternalScopeProvider != null) - { - return ExternalScopeProvider.Push(state); - } - return Logger.BeginScope(state); - } - } - - internal readonly struct LoggerInformation - { - public LoggerInformation(ILoggerProvider provider, string category) : this() - { - ProviderType = provider.GetType(); - Logger = provider.CreateLogger(category); - Category = category; - ExternalScope = provider is ISupportExternalScope; - } - - public ILogger Logger { get; } - - public string Category { get; } - - public Type ProviderType { get; } - - public bool ExternalScope { get; } - } -} \ No newline at end of file diff --git a/MeadowLogger/LoggerOfT.cs b/MeadowLogger/LoggerOfT.cs deleted file mode 100644 index cbd0e25d..00000000 --- a/MeadowLogger/LoggerOfT.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Delegates to a new instance using the full name of the given type, created by the - /// provided . - /// - /// The type. - public class Logger : ILogger - { - private readonly ILogger _logger; - - /// - /// Creates a new . - /// - /// The factory. - public Logger(ILoggerFactory factory) - { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - - _logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T))); - } - - IDisposable ILogger.BeginScope(TState state) - { - return _logger.BeginScope(state); - } - - bool ILogger.IsEnabled(LogLevel logLevel) - { - return _logger.IsEnabled(logLevel); - } - - void ILogger.Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - _logger.Log(logLevel, eventId, state, exception, formatter); - } - } -} \ No newline at end of file diff --git a/MeadowLogger/MeadowLogger.projitems b/MeadowLogger/MeadowLogger.projitems deleted file mode 100644 index 04835f2b..00000000 --- a/MeadowLogger/MeadowLogger.projitems +++ /dev/null @@ -1,30 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - a04f6a20-2b23-4b29-9905-1b79a39bbf25 - - - MeadowLogger - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MeadowLogger/MeadowLogger.shproj b/MeadowLogger/MeadowLogger.shproj deleted file mode 100644 index 1e348321..00000000 --- a/MeadowLogger/MeadowLogger.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - a04f6a20-2b23-4b29-9905-1b79a39bbf25 - 14.0 - - - - - - - - diff --git a/MeadowLogger/NullLogger.cs b/MeadowLogger/NullLogger.cs deleted file mode 100644 index f28a2340..00000000 --- a/MeadowLogger/NullLogger.cs +++ /dev/null @@ -1,79 +0,0 @@ - // Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// Minimalistic logger that does nothing. - /// - public class NullLogger : ILogger - { - public static NullLogger Instance { get; } = new NullLogger(); - - private NullLogger() - { - } - - /// - public IDisposable BeginScope(TState state) - { - return null;// ToDo NullScope.Instance; - } - - /// - public bool IsEnabled(LogLevel logLevel) - { - return false; - } - - /// - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - } - } - - /// - /// Minimalistic logger that does nothing. - /// - public class NullLogger : ILogger - { - public static readonly NullLogger Instance = new NullLogger(); - - /// - public IDisposable BeginScope(TState state) - { - return NullDisposable.Instance; - } - - /// - /// - /// This method ignores the parameters and does nothing. - /// - public void Log( - LogLevel logLevel, - EventId eventId, - TState state, - Exception exception, - Func formatter) - { - } - - /// - public bool IsEnabled(LogLevel logLevel) - { - return false; - } - - private class NullDisposable : IDisposable - { - public static readonly NullDisposable Instance = new NullDisposable(); - - public void Dispose() - { - // intentionally does nothing - } - } - } -} \ No newline at end of file diff --git a/MeadowLogger/NullScope.cs b/MeadowLogger/NullScope.cs deleted file mode 100644 index 7ea0fa65..00000000 --- a/MeadowLogger/NullScope.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Meadow.CLI.Core.Logging -{ - /// - /// An empty scope without any logic - /// - public class NullScope : IDisposable - { - public static NullScope Instance { get; } = new NullScope(); - - private NullScope() - { - } - - /// - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/MeadowLogger/TypeNameHelper.cs b/MeadowLogger/TypeNameHelper.cs deleted file mode 100644 index 112dfa77..00000000 --- a/MeadowLogger/TypeNameHelper.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Meadow.CLI.Core.Logging -{ - public class TypeNameHelper - { - private static readonly Dictionary _builtInTypeNames = new Dictionary - { - { typeof(bool), "bool" }, - { typeof(byte), "byte" }, - { typeof(char), "char" }, - { typeof(decimal), "decimal" }, - { typeof(double), "double" }, - { typeof(float), "float" }, - { typeof(int), "int" }, - { typeof(long), "long" }, - { typeof(object), "object" }, - { typeof(sbyte), "sbyte" }, - { typeof(short), "short" }, - { typeof(string), "string" }, - { typeof(uint), "uint" }, - { typeof(ulong), "ulong" }, - { typeof(ushort), "ushort" } - }; - - public static string GetTypeDisplayName(Type type) - { - if (type.GetTypeInfo().IsGenericType) - { - var fullName = type.GetGenericTypeDefinition().FullName; - - // Nested types (public or private) have a '+' in their full name - var parts = fullName.Split('+'); - - // Handle nested generic types - // Examples: - // ConsoleApp.Program+Foo`1+Bar - // ConsoleApp.Program+Foo`1+Bar`1 - for (var i = 0; i < parts.Length; i++) - { - var partName = parts[i]; - - var backTickIndex = partName.IndexOf('`'); - if (backTickIndex >= 0) - { - // Since '.' is typically used to filter log messages in a hierarchy kind of scenario, - // do not include any generic type information as part of the name. - // Example: - // Microsoft.AspNetCore.Mvc -> log level set as Warning - // Microsoft.AspNetCore.Mvc.ModelBinding -> log level set as Verbose - partName = partName.Substring(0, backTickIndex); - } - - parts[i] = partName; - } - - return string.Join(".", parts); - } - else if (_builtInTypeNames.ContainsKey(type)) - { - return _builtInTypeNames[type]; - } - else - { - var fullName = type.FullName; - - if (type.IsNested) - { - fullName = fullName.Replace('+', '.'); - } - - return fullName; - } - } - } -} \ No newline at end of file diff --git a/Source/v2/.editorconfig b/Source/.editorconfig similarity index 100% rename from Source/v2/.editorconfig rename to Source/.editorconfig diff --git a/Source/v2/Meadow.CLI.v2.sln b/Source/Meadow.CLI.sln similarity index 96% rename from Source/v2/Meadow.CLI.v2.sln rename to Source/Meadow.CLI.sln index 7c168378..60f9ce61 100644 --- a/Source/v2/Meadow.CLI.v2.sln +++ b/Source/Meadow.CLI.sln @@ -6,13 +6,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.HCom", "Meadow.HCom\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.CLI", "Meadow.CLI\Meadow.CLI.csproj", "{1BD32521-158C-478A-AEE7-0EE52BF3571F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Contracts", "..\..\..\Meadow.Contracts\Source\Meadow.Contracts\Meadow.Contracts.csproj", "{62D2092A-5A19-47AC-9B81-A8F5D9D7BD47}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Contracts", "..\..\Meadow.Contracts\Source\Meadow.Contracts\Meadow.Contracts.csproj", "{62D2092A-5A19-47AC-9B81-A8F5D9D7BD47}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_ref", "_ref", "{562945CE-DA15-4A2E-86A2-CA7E3FF22DCA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Logging", "..\..\..\Meadow.Logging\Source\Meadow.Logging\lib\Meadow.Logging.csproj", "{946B7200-8CC1-4A8D-9BCE-FCB06EDC705B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Logging", "..\..\Meadow.Logging\Source\Meadow.Logging\lib\Meadow.Logging.csproj", "{946B7200-8CC1-4A8D-9BCE-FCB06EDC705B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Units", "..\..\..\Meadow.Units\Source\Meadow.Units\Meadow.Units.csproj", "{5DC0D8EC-85D4-4E98-9403-2D5B9700D8AC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Units", "..\..\Meadow.Units\Source\Meadow.Units\Meadow.Units.csproj", "{5DC0D8EC-85D4-4E98-9403-2D5B9700D8AC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.SoftwareManager", "Meadow.SoftwareManager\Meadow.SoftwareManager.csproj", "{B842E44B-F57F-4728-980F-776DE6E2CDAA}" EndProject diff --git a/Source/v2/Meadow.Cli/CommandErrors.cs b/Source/Meadow.CLI/CommandErrors.cs similarity index 100% rename from Source/v2/Meadow.Cli/CommandErrors.cs rename to Source/Meadow.CLI/CommandErrors.cs diff --git a/Source/v2/Meadow.Cli/CommandException.cs b/Source/Meadow.CLI/CommandException.cs similarity index 100% rename from Source/v2/Meadow.Cli/CommandException.cs rename to Source/Meadow.CLI/CommandException.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/App/AppBuildCommand.cs b/Source/Meadow.CLI/Commands/Current/App/AppBuildCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/App/AppBuildCommand.cs rename to Source/Meadow.CLI/Commands/Current/App/AppBuildCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/App/AppDebugCommand.cs b/Source/Meadow.CLI/Commands/Current/App/AppDebugCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/App/AppDebugCommand.cs rename to Source/Meadow.CLI/Commands/Current/App/AppDebugCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/App/AppDeployCommand.cs b/Source/Meadow.CLI/Commands/Current/App/AppDeployCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/App/AppDeployCommand.cs rename to Source/Meadow.CLI/Commands/Current/App/AppDeployCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/App/AppRunCommand.cs b/Source/Meadow.CLI/Commands/Current/App/AppRunCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/App/AppRunCommand.cs rename to Source/Meadow.CLI/Commands/Current/App/AppRunCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs b/Source/Meadow.CLI/Commands/Current/App/AppTools.cs similarity index 99% rename from Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs rename to Source/Meadow.CLI/Commands/Current/App/AppTools.cs index d5385b27..cd5cec2f 100644 --- a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs +++ b/Source/Meadow.CLI/Commands/Current/App/AppTools.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using CliFx.Infrastructure; using Meadow.Hcom; using Meadow.Package; diff --git a/Source/v2/Meadow.Cli/Commands/Current/App/AppTrimCommand.cs b/Source/Meadow.CLI/Commands/Current/App/AppTrimCommand.cs similarity index 97% rename from Source/v2/Meadow.Cli/Commands/Current/App/AppTrimCommand.cs rename to Source/Meadow.CLI/Commands/Current/App/AppTrimCommand.cs index efdc5cb2..526f62b1 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/App/AppTrimCommand.cs +++ b/Source/Meadow.CLI/Commands/Current/App/AppTrimCommand.cs @@ -1,72 +1,72 @@ -using CliFx.Attributes; -using Meadow.Package; -using Meadow.Software; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement; - -[Command("app trim", Description = "Trim a pre-compiled Meadow application")] -public class AppTrimCommand : BaseDeviceCommand -{ - private readonly IPackageManager _packageManager; - - [CommandOption('c', Description = Strings.BuildConfiguration, IsRequired = false)] - public string? Configuration { get; private set; } - - [CommandParameter(0, Description = Strings.PathToMeadowProject, IsRequired = false)] - public string? Path { get; init; } - - [CommandOption("nolink", Description = Strings.NoLinkAssemblies, IsRequired = false)] - public string[]? NoLink { get; private set; } - - readonly FileManager _fileManager; - - public AppTrimCommand(FileManager fileManager, IPackageManager packageManager, MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory) - : base(connectionManager, loggerFactory) - { - _packageManager = packageManager; - _fileManager = fileManager; - } - - protected override async ValueTask ExecuteCommand() - { - await _fileManager.Refresh(); - - // for now we only support F7 - // TODO: add switch and support for other platforms - var collection = _fileManager.Firmware["Meadow F7"]; - - if (collection == null || collection.Count() == 0) - { - throw new CommandException(Strings.NoFirmwarePackagesFound, CommandExitCode.GeneralError); - } - - var path = AppTools.ValidateAndSanitizeAppPath(Path); - - if (!File.Exists(path)) - { - // is it a valid directory? - if (!Directory.Exists(path)) - { - throw new CommandException($"{Strings.InvalidApplicationPath} '{path}'", CommandExitCode.FileNotFound); - } - } - - var connection = await GetCurrentConnection(); - - await AppTools.DisableRuntimeIfEnabled(connection, Logger, CancellationToken); - - var deviceInfo = await connection.GetDeviceInfo(); - - if (deviceInfo == null || deviceInfo.OsVersion == null) - { - throw new CommandException(Strings.UnableToGetDeviceInfo, CommandExitCode.GeneralError); - } - - var package = collection.GetClosestLocalPackage(deviceInfo.OsVersion); - - Logger.LogInformation($"Preparing to trim using v{package?.Version ?? " unknown"} assemblies..."); - await AppTools.TrimApplication(path, _packageManager, deviceInfo.OsVersion, Configuration, NoLink, Logger, Console, CancellationToken); - Logger.LogInformation("Application trimmed successfully"); - } +using CliFx.Attributes; +using Meadow.Package; +using Meadow.Software; +using Microsoft.Extensions.Logging; + +namespace Meadow.CLI.Commands.DeviceManagement; + +[Command("app trim", Description = "Trim a pre-compiled Meadow application")] +public class AppTrimCommand : BaseDeviceCommand +{ + private readonly IPackageManager _packageManager; + + [CommandOption('c', Description = Strings.BuildConfiguration, IsRequired = false)] + public string? Configuration { get; private set; } + + [CommandParameter(0, Description = Strings.PathToMeadowProject, IsRequired = false)] + public string? Path { get; init; } + + [CommandOption("nolink", Description = Strings.NoLinkAssemblies, IsRequired = false)] + public string[]? NoLink { get; private set; } + + readonly FileManager _fileManager; + + public AppTrimCommand(FileManager fileManager, IPackageManager packageManager, MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory) + : base(connectionManager, loggerFactory) + { + _packageManager = packageManager; + _fileManager = fileManager; + } + + protected override async ValueTask ExecuteCommand() + { + await _fileManager.Refresh(); + + // for now we only support F7 + // TODO: add switch and support for other platforms + var collection = _fileManager.Firmware["Meadow F7"]; + + if (collection == null || collection.Count() == 0) + { + throw new CommandException(Strings.NoFirmwarePackagesFound, CommandExitCode.GeneralError); + } + + var path = AppTools.ValidateAndSanitizeAppPath(Path); + + if (!File.Exists(path)) + { + // is it a valid directory? + if (!Directory.Exists(path)) + { + throw new CommandException($"{Strings.InvalidApplicationPath} '{path}'", CommandExitCode.FileNotFound); + } + } + + var connection = await GetCurrentConnection(); + + await AppTools.DisableRuntimeIfEnabled(connection, Logger, CancellationToken); + + var deviceInfo = await connection.GetDeviceInfo(); + + if (deviceInfo == null || deviceInfo.OsVersion == null) + { + throw new CommandException(Strings.UnableToGetDeviceInfo, CommandExitCode.GeneralError); + } + + var package = collection.GetClosestLocalPackage(deviceInfo.OsVersion); + + Logger.LogInformation($"Preparing to trim using v{package?.Version ?? " unknown"} assemblies..."); + await AppTools.TrimApplication(path, _packageManager, deviceInfo.OsVersion, Configuration, NoLink, Logger, Console, CancellationToken); + Logger.LogInformation("Application trimmed successfully"); + } } \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Commands/Current/BaseCloudCommand.cs b/Source/Meadow.CLI/Commands/Current/BaseCloudCommand.cs similarity index 97% rename from Source/v2/Meadow.Cli/Commands/Current/BaseCloudCommand.cs rename to Source/Meadow.CLI/Commands/Current/BaseCloudCommand.cs index dea7f220..2b1a4bcd 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/BaseCloudCommand.cs +++ b/Source/Meadow.CLI/Commands/Current/BaseCloudCommand.cs @@ -1,129 +1,129 @@ -using CliFx.Attributes; -using Meadow.Cloud.Client; -using Meadow.Cloud.Client.Users; -using Microsoft.Extensions.Logging; -using System.Net.Http.Headers; -using System.Text; - -namespace Meadow.CLI.Commands.DeviceManagement; - -public abstract class BaseCloudCommand : BaseCommand -{ - [CommandOption("host", Description = $"The Meadow.Cloud endpoint.", IsRequired = false)] - public string Host { get; set; } = DefaultHost; - - [CommandOption("apikey", Description = "The API key to use with Meadow.Cloud. Otherwise, use the logged in Wilderness Labs account.", EnvironmentVariable = "MC_APIKEY", IsRequired = false)] - public string? ApiKey { get; set; } - - protected const string DefaultHost = Meadow.Cloud.Client.MeadowCloudClient.DefaultHost; - - protected bool RequiresAuthentication { get; set; } = true; - - protected IMeadowCloudClient MeadowCloudClient { get; } - - public BaseCloudCommand( - IMeadowCloudClient meadowCloudClient, - ILoggerFactory loggerFactory) - : base(loggerFactory) - { - MeadowCloudClient = meadowCloudClient; - } - - protected virtual ValueTask PreAuthenticatedValidation() - { - return ValueTask.CompletedTask; - } - - protected abstract ValueTask ExecuteCloudCommand(); - - protected sealed override async ValueTask ExecuteCommand() - { - if (!Host.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && !Host.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) - { - throw new CommandException("Host (--host) must be a valid URL that starts with http:// or https://."); - } - - if (!Uri.TryCreate(Host, UriKind.Absolute, out Uri? baseAddress) || baseAddress == null) - { - throw new CommandException("Host (--host) must be a valid URL."); - } - - MeadowCloudClient.BaseAddress = baseAddress; - - await PreAuthenticatedValidation(); - - if (RequiresAuthentication) - { - if (!string.IsNullOrEmpty(ApiKey)) - { - MeadowCloudClient.Authorization = new AuthenticationHeaderValue("APIKEY", ApiKey); - } - else - { - var result = await MeadowCloudClient.Authenticate(CancellationToken); - if (!result) - { - throw new CommandException("You must be signed into your Wilderness Labs account to execute this command. Run 'meadow login' to do so."); - } - - // If the user does not yet exist in Meadow.Cloud, this creates them and sets up their initial org - var _ = await MeadowCloudClient.User.GetUser(CancellationToken) - ?? throw new CommandException("There was a problem retrieving your account information."); - } - } - - try - { - await ExecuteCloudCommand(); - } - catch (MeadowCloudAuthException ex) - { - throw new CommandException("You must be signed into your Wilderness Labs account to execute this command. Run 'meadow login' to do so.", ex); - } - catch (MeadowCloudException ex) - { - if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) - { - var sb = new StringBuilder("You are not authorized to perform this action. Please check that you have sufficient access"); - if (!string.IsNullOrWhiteSpace(ApiKey)) - { - sb.Append(", that your API keys is valid with the correct scopes,"); - } - sb.Append(" and try again."); - - throw new CommandException(sb.ToString(), ex); - } - - throw new CommandException($@"There was a problem executing the command. Meadow.Cloud returned a non-successful response. - -{(int)ex.StatusCode} {ex.StatusCode} -Response: {(string.IsNullOrWhiteSpace(ex.Response) ? "None" : Environment.NewLine + ex.Response)} - -{ex.StackTrace}", ex); - } - } - - protected async Task GetOrganization(string? orgNameOrId = null, CancellationToken cancellationToken = default) - { - Logger.LogInformation("Retrieving your user and organization information..."); - - var orgs = await MeadowCloudClient.User.GetOrganizations(cancellationToken).ConfigureAwait(false); - if (orgs.Count() > 1 && string.IsNullOrEmpty(orgNameOrId)) - { - Logger.LogInformation($"You are a member of more than 1 organization. Please specify the desired orgId for this device provisioning."); - return null; - } - else if (orgs.Count() == 1 && string.IsNullOrEmpty(orgNameOrId)) - { - orgNameOrId = orgs.Single().Id; - } - - var org = orgs.FirstOrDefault(o => o.Id == orgNameOrId || string.Equals(o.Name, orgNameOrId, StringComparison.OrdinalIgnoreCase)); - if (org == null) - { - Logger.LogInformation($"Unable to find an organization with a Name or ID matching '{orgNameOrId}'"); - } - - return org; - } +using CliFx.Attributes; +using Meadow.Cloud.Client; +using Meadow.Cloud.Client.Users; +using Microsoft.Extensions.Logging; +using System.Net.Http.Headers; +using System.Text; + +namespace Meadow.CLI.Commands.DeviceManagement; + +public abstract class BaseCloudCommand : BaseCommand +{ + [CommandOption("host", Description = $"The Meadow.Cloud endpoint.", IsRequired = false)] + public string Host { get; set; } = DefaultHost; + + [CommandOption("apikey", Description = "The API key to use with Meadow.Cloud. Otherwise, use the logged in Wilderness Labs account.", EnvironmentVariable = "MC_APIKEY", IsRequired = false)] + public string? ApiKey { get; set; } + + protected const string DefaultHost = Meadow.Cloud.Client.MeadowCloudClient.DefaultHost; + + protected bool RequiresAuthentication { get; set; } = true; + + protected IMeadowCloudClient MeadowCloudClient { get; } + + public BaseCloudCommand( + IMeadowCloudClient meadowCloudClient, + ILoggerFactory loggerFactory) + : base(loggerFactory) + { + MeadowCloudClient = meadowCloudClient; + } + + protected virtual ValueTask PreAuthenticatedValidation() + { + return ValueTask.CompletedTask; + } + + protected abstract ValueTask ExecuteCloudCommand(); + + protected sealed override async ValueTask ExecuteCommand() + { + if (!Host.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && !Host.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + throw new CommandException("Host (--host) must be a valid URL that starts with http:// or https://."); + } + + if (!Uri.TryCreate(Host, UriKind.Absolute, out Uri? baseAddress) || baseAddress == null) + { + throw new CommandException("Host (--host) must be a valid URL."); + } + + MeadowCloudClient.BaseAddress = baseAddress; + + await PreAuthenticatedValidation(); + + if (RequiresAuthentication) + { + if (!string.IsNullOrEmpty(ApiKey)) + { + MeadowCloudClient.Authorization = new AuthenticationHeaderValue("APIKEY", ApiKey); + } + else + { + var result = await MeadowCloudClient.Authenticate(CancellationToken); + if (!result) + { + throw new CommandException("You must be signed into your Wilderness Labs account to execute this command. Run 'meadow login' to do so."); + } + + // If the user does not yet exist in Meadow.Cloud, this creates them and sets up their initial org + var _ = await MeadowCloudClient.User.GetUser(CancellationToken) + ?? throw new CommandException("There was a problem retrieving your account information."); + } + } + + try + { + await ExecuteCloudCommand(); + } + catch (MeadowCloudAuthException ex) + { + throw new CommandException("You must be signed into your Wilderness Labs account to execute this command. Run 'meadow login' to do so.", ex); + } + catch (MeadowCloudException ex) + { + if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) + { + var sb = new StringBuilder("You are not authorized to perform this action. Please check that you have sufficient access"); + if (!string.IsNullOrWhiteSpace(ApiKey)) + { + sb.Append(", that your API keys is valid with the correct scopes,"); + } + sb.Append(" and try again."); + + throw new CommandException(sb.ToString(), ex); + } + + throw new CommandException($@"There was a problem executing the command. Meadow.Cloud returned a non-successful response. + +{(int)ex.StatusCode} {ex.StatusCode} +Response: {(string.IsNullOrWhiteSpace(ex.Response) ? "None" : Environment.NewLine + ex.Response)} + +{ex.StackTrace}", ex); + } + } + + protected async Task GetOrganization(string? orgNameOrId = null, CancellationToken cancellationToken = default) + { + Logger.LogInformation("Retrieving your user and organization information..."); + + var orgs = await MeadowCloudClient.User.GetOrganizations(cancellationToken).ConfigureAwait(false); + if (orgs.Count() > 1 && string.IsNullOrEmpty(orgNameOrId)) + { + Logger.LogInformation($"You are a member of more than 1 organization. Please specify the desired orgId for this device provisioning."); + return null; + } + else if (orgs.Count() == 1 && string.IsNullOrEmpty(orgNameOrId)) + { + orgNameOrId = orgs.Single().Id; + } + + var org = orgs.FirstOrDefault(o => o.Id == orgNameOrId || string.Equals(o.Name, orgNameOrId, StringComparison.OrdinalIgnoreCase)); + if (org == null) + { + Logger.LogInformation($"Unable to find an organization with a Name or ID matching '{orgNameOrId}'"); + } + + return org; + } } \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Commands/Current/BaseCommand.cs b/Source/Meadow.CLI/Commands/Current/BaseCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/BaseCommand.cs rename to Source/Meadow.CLI/Commands/Current/BaseCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/BaseDeviceCommand.cs b/Source/Meadow.CLI/Commands/Current/BaseDeviceCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/BaseDeviceCommand.cs rename to Source/Meadow.CLI/Commands/Current/BaseDeviceCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/BaseFileCommand.cs b/Source/Meadow.CLI/Commands/Current/BaseFileCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/BaseFileCommand.cs rename to Source/Meadow.CLI/Commands/Current/BaseFileCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/BaseSettingsCommand.cs b/Source/Meadow.CLI/Commands/Current/BaseSettingsCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/BaseSettingsCommand.cs rename to Source/Meadow.CLI/Commands/Current/BaseSettingsCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyCreateCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyCreateCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyCreateCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyCreateCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyDeleteCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyDeleteCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyDeleteCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyDeleteCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyListCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyListCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyListCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyListCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyUpdateCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyUpdateCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/ApiKey/CloudApiKeyUpdateCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/ApiKey/CloudApiKeyUpdateCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Collection/CloudCollectionListCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Collection/CloudCollectionListCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Collection/CloudCollectionListCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Collection/CloudCollectionListCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Collection/JsonDocumentBindingConverter.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Collection/JsonDocumentBindingConverter.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Collection/JsonDocumentBindingConverter.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Collection/JsonDocumentBindingConverter.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Collection/QualityOfService.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Collection/QualityOfService.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Collection/QualityOfService.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Collection/QualityOfService.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Command/CloudCommandPublishCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Command/CloudCommandPublishCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Command/CloudCommandPublishCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Command/CloudCommandPublishCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/ConsoleTable.cs b/Source/Meadow.CLI/Commands/Current/Cloud/ConsoleTable.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/ConsoleTable.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/ConsoleTable.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageCreateCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageCreateCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageCreateCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageCreateCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageListCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageListCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageListCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageListCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackagePublishCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackagePublishCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackagePublishCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackagePublishCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageUploadCommand.cs b/Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageUploadCommand.cs similarity index 97% rename from Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageUploadCommand.cs rename to Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageUploadCommand.cs index 523da84d..d8de30a3 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/Cloud/Package/CloudPackageUploadCommand.cs +++ b/Source/Meadow.CLI/Commands/Current/Cloud/Package/CloudPackageUploadCommand.cs @@ -1,50 +1,50 @@ -using CliFx.Attributes; -using Meadow.Cloud.Client; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement; - -[Command("cloud package upload", Description = "Upload a Meadow Package (MPAK) to Meadow.Cloud")] -public class CloudPackageUploadCommand : BaseCloudCommand -{ - [CommandParameter(0, Name = "MpakPath", Description = "The full path of the mpak file", IsRequired = true)] - public string MpakPath { get; init; } = default!; - - [CommandOption("orgId", 'o', Description = "OrgId to upload to", IsRequired = false)] - public string? OrgId { get; init; } - - [CommandOption("description", 'd', Description = "Description of the package", IsRequired = false)] - public string? Description { get; init; } - - private readonly PackageService _packageService; - - public CloudPackageUploadCommand( - IMeadowCloudClient meadowCloudClient, - PackageService packageService, - ILoggerFactory loggerFactory) - : base(meadowCloudClient, loggerFactory) - { - _packageService = packageService; - } - protected override ValueTask PreAuthenticatedValidation() - { - if (!File.Exists(MpakPath)) - { - throw new CommandException($"Package {MpakPath} does not exist"); - } - - return ValueTask.CompletedTask; - } - - protected override async ValueTask ExecuteCloudCommand() - { - var org = await GetOrganization(OrgId, CancellationToken); - - if (org == null) { return; } - - Logger.LogInformation($"Uploading package {Path.GetFileName(MpakPath)}..."); - - var package = await _packageService.UploadPackage(MpakPath, org.Id, Description ?? string.Empty, Host, CancellationToken); - Logger.LogInformation($"Upload complete. Package Id: {package.Id}"); - } +using CliFx.Attributes; +using Meadow.Cloud.Client; +using Microsoft.Extensions.Logging; + +namespace Meadow.CLI.Commands.DeviceManagement; + +[Command("cloud package upload", Description = "Upload a Meadow Package (MPAK) to Meadow.Cloud")] +public class CloudPackageUploadCommand : BaseCloudCommand +{ + [CommandParameter(0, Name = "MpakPath", Description = "The full path of the mpak file", IsRequired = true)] + public string MpakPath { get; init; } = default!; + + [CommandOption("orgId", 'o', Description = "OrgId to upload to", IsRequired = false)] + public string? OrgId { get; init; } + + [CommandOption("description", 'd', Description = "Description of the package", IsRequired = false)] + public string? Description { get; init; } + + private readonly PackageService _packageService; + + public CloudPackageUploadCommand( + IMeadowCloudClient meadowCloudClient, + PackageService packageService, + ILoggerFactory loggerFactory) + : base(meadowCloudClient, loggerFactory) + { + _packageService = packageService; + } + protected override ValueTask PreAuthenticatedValidation() + { + if (!File.Exists(MpakPath)) + { + throw new CommandException($"Package {MpakPath} does not exist"); + } + + return ValueTask.CompletedTask; + } + + protected override async ValueTask ExecuteCloudCommand() + { + var org = await GetOrganization(OrgId, CancellationToken); + + if (org == null) { return; } + + Logger.LogInformation($"Uploading package {Path.GetFileName(MpakPath)}..."); + + var package = await _packageService.UploadPackage(MpakPath, org.Id, Description ?? string.Empty, Host, CancellationToken); + Logger.LogInformation($"Upload complete. Package Id: {package.Id}"); + } } \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Commands/Current/Config/ConfigCommand.cs b/Source/Meadow.CLI/Commands/Current/Config/ConfigCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Config/ConfigCommand.cs rename to Source/Meadow.CLI/Commands/Current/Config/ConfigCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Config/ConfigRouteCommand.cs b/Source/Meadow.CLI/Commands/Current/Config/ConfigRouteCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Config/ConfigRouteCommand.cs rename to Source/Meadow.CLI/Commands/Current/Config/ConfigRouteCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Config/ConfigSourceCommand.cs b/Source/Meadow.CLI/Commands/Current/Config/ConfigSourceCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Config/ConfigSourceCommand.cs rename to Source/Meadow.CLI/Commands/Current/Config/ConfigSourceCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/DeveloperCommand.cs b/Source/Meadow.CLI/Commands/Current/DeveloperCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/DeveloperCommand.cs rename to Source/Meadow.CLI/Commands/Current/DeveloperCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Device/DeviceClockCommand.cs b/Source/Meadow.CLI/Commands/Current/Device/DeviceClockCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Device/DeviceClockCommand.cs rename to Source/Meadow.CLI/Commands/Current/Device/DeviceClockCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Device/DeviceInfoCommand.cs b/Source/Meadow.CLI/Commands/Current/Device/DeviceInfoCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Device/DeviceInfoCommand.cs rename to Source/Meadow.CLI/Commands/Current/Device/DeviceInfoCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Device/DeviceProvisionCommand.cs b/Source/Meadow.CLI/Commands/Current/Device/DeviceProvisionCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Device/DeviceProvisionCommand.cs rename to Source/Meadow.CLI/Commands/Current/Device/DeviceProvisionCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Device/DeviceResetCommand.cs b/Source/Meadow.CLI/Commands/Current/Device/DeviceResetCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Device/DeviceResetCommand.cs rename to Source/Meadow.CLI/Commands/Current/Device/DeviceResetCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Dfu/DfuInstallCommand.cs b/Source/Meadow.CLI/Commands/Current/Dfu/DfuInstallCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Dfu/DfuInstallCommand.cs rename to Source/Meadow.CLI/Commands/Current/Dfu/DfuInstallCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs b/Source/Meadow.CLI/Commands/Current/File/FileDeleteCommand.cs similarity index 97% rename from Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs rename to Source/Meadow.CLI/Commands/Current/File/FileDeleteCommand.cs index bf3da405..82561793 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs +++ b/Source/Meadow.CLI/Commands/Current/File/FileDeleteCommand.cs @@ -1,106 +1,106 @@ -using CliFx.Attributes; -using Meadow.Hcom; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement; - -[Command("file delete", Description = "Deletes a file from the device")] -public class FileDeleteCommand : BaseDeviceCommand -{ - [CommandParameter(0, Name = "MeadowFile", IsRequired = true)] - public string MeadowFile { get; init; } = default!; - - public FileDeleteCommand(MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory) - : base(connectionManager, loggerFactory) - { } - - protected override async ValueTask ExecuteCommand() - { - var connection = await GetCurrentConnection(); - var device = await GetCurrentDevice(); - - var state = await device.IsRuntimeEnabled(CancellationToken); - - if (state == true) - { - Logger?.LogInformation($"{Strings.DisablingRuntime}..."); - await device.RuntimeDisable(CancellationToken); - } - - if (MeadowFile == "all") - { - Logger?.LogInformation($"Looking for files..."); - } - else - { - Logger?.LogInformation($"Looking for file {MeadowFile}..."); - } - - var folder = AppTools.SanitizeMeadowFolderName(Path.GetDirectoryName(MeadowFile)!); - - var fileList = await connection.GetFileList($"{folder}", false, CancellationToken); - - if (fileList == null || fileList.Length == 0) - { - Logger?.LogError($"File delete failed, no files found"); - return; - } - - if (MeadowFile == "all") - { - foreach (var file in fileList) - { - await DeleteFileRecursive(device, folder, file, CancellationToken); - } - } - else - { - var requested = Path.GetFileName(MeadowFile); - - var exists = fileList?.Any(f => Path.GetFileName(f.Name) == requested) ?? false; - - var file = AppTools.SanitizeMeadowFilename(MeadowFile); - - if (!exists) - { - Logger?.LogError($"File '{file}' not found on device"); - } - else - { - Logger?.LogInformation($"Deleting '{file}'"); - await device.DeleteFile(file, CancellationToken); - } - } - } - - private async Task DeleteFileRecursive(IMeadowDevice device, string directoryname, MeadowFileInfo fileInfo, CancellationToken cancellationToken) - { - var meadowFile = AppTools.SanitizeMeadowFilename(Path.Combine(directoryname, fileInfo.Name)); - - foreach (var folder in AppManager.PersistantFolders) - { - if (meadowFile.StartsWith($"/{AppManager.MeadowRootFolder}/{folder}")) - { - return; - } - } - - if (fileInfo.IsDirectory) - { - // Add a backslash as we're a directory and not a file - meadowFile += "/"; - var subfolderFiles = await device.GetFileList(meadowFile, false, cancellationToken); - - foreach (var subfolderFile in subfolderFiles) - { - await DeleteFileRecursive(device, meadowFile, subfolderFile, cancellationToken); - } - return; - } - - Logger?.LogInformation($"Deleting file '{meadowFile}' from device..."); - - await device.DeleteFile(meadowFile, cancellationToken); - await Task.Delay(100); - } +using CliFx.Attributes; +using Meadow.Hcom; +using Microsoft.Extensions.Logging; + +namespace Meadow.CLI.Commands.DeviceManagement; + +[Command("file delete", Description = "Deletes a file from the device")] +public class FileDeleteCommand : BaseDeviceCommand +{ + [CommandParameter(0, Name = "MeadowFile", IsRequired = true)] + public string MeadowFile { get; init; } = default!; + + public FileDeleteCommand(MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory) + : base(connectionManager, loggerFactory) + { } + + protected override async ValueTask ExecuteCommand() + { + var connection = await GetCurrentConnection(); + var device = await GetCurrentDevice(); + + var state = await device.IsRuntimeEnabled(CancellationToken); + + if (state == true) + { + Logger?.LogInformation($"{Strings.DisablingRuntime}..."); + await device.RuntimeDisable(CancellationToken); + } + + if (MeadowFile == "all") + { + Logger?.LogInformation($"Looking for files..."); + } + else + { + Logger?.LogInformation($"Looking for file {MeadowFile}..."); + } + + var folder = AppTools.SanitizeMeadowFolderName(Path.GetDirectoryName(MeadowFile)!); + + var fileList = await connection.GetFileList($"{folder}", false, CancellationToken); + + if (fileList == null || fileList.Length == 0) + { + Logger?.LogError($"File delete failed, no files found"); + return; + } + + if (MeadowFile == "all") + { + foreach (var file in fileList) + { + await DeleteFileRecursive(device, folder, file, CancellationToken); + } + } + else + { + var requested = Path.GetFileName(MeadowFile); + + var exists = fileList?.Any(f => Path.GetFileName(f.Name) == requested) ?? false; + + var file = AppTools.SanitizeMeadowFilename(MeadowFile); + + if (!exists) + { + Logger?.LogError($"File '{file}' not found on device"); + } + else + { + Logger?.LogInformation($"Deleting '{file}'"); + await device.DeleteFile(file, CancellationToken); + } + } + } + + private async Task DeleteFileRecursive(IMeadowDevice device, string directoryname, MeadowFileInfo fileInfo, CancellationToken cancellationToken) + { + var meadowFile = AppTools.SanitizeMeadowFilename(Path.Combine(directoryname, fileInfo.Name)); + + foreach (var folder in AppManager.PersistantFolders) + { + if (meadowFile.StartsWith($"/{AppManager.MeadowRootFolder}/{folder}")) + { + return; + } + } + + if (fileInfo.IsDirectory) + { + // Add a backslash as we're a directory and not a file + meadowFile += "/"; + var subfolderFiles = await device.GetFileList(meadowFile, false, cancellationToken); + + foreach (var subfolderFile in subfolderFiles) + { + await DeleteFileRecursive(device, meadowFile, subfolderFile, cancellationToken); + } + return; + } + + Logger?.LogInformation($"Deleting file '{meadowFile}' from device..."); + + await device.DeleteFile(meadowFile, cancellationToken); + await Task.Delay(100); + } } \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileInitialCommand.cs b/Source/Meadow.CLI/Commands/Current/File/FileInitialCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/File/FileInitialCommand.cs rename to Source/Meadow.CLI/Commands/Current/File/FileInitialCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs b/Source/Meadow.CLI/Commands/Current/File/FileListCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs rename to Source/Meadow.CLI/Commands/Current/File/FileListCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileReadCommand.cs b/Source/Meadow.CLI/Commands/Current/File/FileReadCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/File/FileReadCommand.cs rename to Source/Meadow.CLI/Commands/Current/File/FileReadCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileWriteCommand.cs b/Source/Meadow.CLI/Commands/Current/File/FileWriteCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/File/FileWriteCommand.cs rename to Source/Meadow.CLI/Commands/Current/File/FileWriteCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareDefaultCommand.cs b/Source/Meadow.CLI/Commands/Current/Firmware/FirmwareDefaultCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareDefaultCommand.cs rename to Source/Meadow.CLI/Commands/Current/Firmware/FirmwareDefaultCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareDeleteCommand.cs b/Source/Meadow.CLI/Commands/Current/Firmware/FirmwareDeleteCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareDeleteCommand.cs rename to Source/Meadow.CLI/Commands/Current/Firmware/FirmwareDeleteCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareDownloadCommand.cs b/Source/Meadow.CLI/Commands/Current/Firmware/FirmwareDownloadCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareDownloadCommand.cs rename to Source/Meadow.CLI/Commands/Current/Firmware/FirmwareDownloadCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareListCommand.cs b/Source/Meadow.CLI/Commands/Current/Firmware/FirmwareListCommand.cs similarity index 97% rename from Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareListCommand.cs rename to Source/Meadow.CLI/Commands/Current/Firmware/FirmwareListCommand.cs index 00807654..cebca8ac 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareListCommand.cs +++ b/Source/Meadow.CLI/Commands/Current/Firmware/FirmwareListCommand.cs @@ -1,110 +1,110 @@ -using CliFx.Attributes; -using Meadow.Software; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement; - -[Command("firmware list", Description = "List locally available firmware")] -public class FirmwareListCommand : BaseCommand -{ - [CommandOption("verbose", 'v', IsRequired = false)] - public bool Verbose { get; init; } - - private FileManager FileManager { get; } - - public FirmwareListCommand(FileManager fileManager, ILoggerFactory loggerFactory) - : base(loggerFactory) - { - FileManager = fileManager; - } - - protected override async ValueTask ExecuteCommand() - { - await FileManager.Refresh(); - - //show the firmware path - Logger?.LogInformation($"Firmware location: {F7FirmwarePackageCollection.DefaultF7FirmwareStoreRoot}"); - - if (Verbose) - { - await DisplayVerboseResults(FileManager); - } - else - { - await DisplayTerseResults(FileManager); - } - } - - private async Task DisplayVerboseResults(FileManager manager) - { - Logger?.LogInformation($" (D== Default, OSB==OS without bootloader, RT==Runtime, CP==Coprocessor){Environment.NewLine}"); - Logger?.LogInformation($" D VERSION OS OSB RT CP BCL"); - - Logger?.LogInformation($"------------------------------------------"); - - foreach (var name in manager.Firmware.CollectionNames) - { - Logger?.LogInformation($" {name}"); - var collection = manager.Firmware[name]; - - foreach (var package in collection.OrderBy(p => new Version(p.Version))) - { - if (package == collection.DefaultPackage) - { - Logger?.LogInformation( - $" * {package.Version.PadRight(18)} " + - $"{(package.OSWithBootloader != null ? "X " : " ")}" + - $"{(package.OsWithoutBootloader != null ? " X " : " ")}" + - $"{(package.Runtime != null ? "X " : " ")}" + - $"{(package.CoprocApplication != null ? "X " : " ")}" + - $"{(package.BclFolder != null ? "X " : " ")}" - ); - } - else - { - Logger?.LogInformation( - $" {package.Version.PadRight(18)} " + - $"{(package.OSWithBootloader != null ? "X " : " ")}" + - $"{(package.OsWithoutBootloader != null ? " X " : " ")}" + - $"{(package.Runtime != null ? "X " : " ")}" + - $"{(package.CoprocApplication != null ? "X " : " ")}" + - $"{(package.BclFolder != null ? "X " : " ")}" - ); - } - } - - var update = await collection.UpdateAvailable(); - if (update != null) - { - Logger?.LogInformation($"{Environment.NewLine} ! {update} IS AVAILABLE FOR DOWNLOAD"); - } - } - } - - private async Task DisplayTerseResults(FileManager manager) - { - foreach (var name in manager.Firmware.CollectionNames) - { - Logger?.LogInformation($" {name}"); - var collection = manager.Firmware[name]; - - foreach (var package in collection.OrderBy(p => new Version(p.Version))) - { - if (package == collection.DefaultPackage) - { - Logger?.LogInformation($" * {package.Version} (default)"); - } - else - { - Logger?.LogInformation($" {package.Version}"); - } - } - - var update = await collection.UpdateAvailable(); - if (update != null) - { - Logger?.LogInformation($"{Environment.NewLine} ! {update} IS AVAILABLE FOR DOWNLOAD"); - } - } - } +using CliFx.Attributes; +using Meadow.Software; +using Microsoft.Extensions.Logging; + +namespace Meadow.CLI.Commands.DeviceManagement; + +[Command("firmware list", Description = "List locally available firmware")] +public class FirmwareListCommand : BaseCommand +{ + [CommandOption("verbose", 'v', IsRequired = false)] + public bool Verbose { get; init; } + + private FileManager FileManager { get; } + + public FirmwareListCommand(FileManager fileManager, ILoggerFactory loggerFactory) + : base(loggerFactory) + { + FileManager = fileManager; + } + + protected override async ValueTask ExecuteCommand() + { + await FileManager.Refresh(); + + //show the firmware path + Logger?.LogInformation($"Firmware location: {F7FirmwarePackageCollection.DefaultF7FirmwareStoreRoot}"); + + if (Verbose) + { + await DisplayVerboseResults(FileManager); + } + else + { + await DisplayTerseResults(FileManager); + } + } + + private async Task DisplayVerboseResults(FileManager manager) + { + Logger?.LogInformation($" (D== Default, OSB==OS without bootloader, RT==Runtime, CP==Coprocessor){Environment.NewLine}"); + Logger?.LogInformation($" D VERSION OS OSB RT CP BCL"); + + Logger?.LogInformation($"------------------------------------------"); + + foreach (var name in manager.Firmware.CollectionNames) + { + Logger?.LogInformation($" {name}"); + var collection = manager.Firmware[name]; + + foreach (var package in collection.OrderBy(p => new Version(p.Version))) + { + if (package == collection.DefaultPackage) + { + Logger?.LogInformation( + $" * {package.Version.PadRight(18)} " + + $"{(package.OSWithBootloader != null ? "X " : " ")}" + + $"{(package.OsWithoutBootloader != null ? " X " : " ")}" + + $"{(package.Runtime != null ? "X " : " ")}" + + $"{(package.CoprocApplication != null ? "X " : " ")}" + + $"{(package.BclFolder != null ? "X " : " ")}" + ); + } + else + { + Logger?.LogInformation( + $" {package.Version.PadRight(18)} " + + $"{(package.OSWithBootloader != null ? "X " : " ")}" + + $"{(package.OsWithoutBootloader != null ? " X " : " ")}" + + $"{(package.Runtime != null ? "X " : " ")}" + + $"{(package.CoprocApplication != null ? "X " : " ")}" + + $"{(package.BclFolder != null ? "X " : " ")}" + ); + } + } + + var update = await collection.UpdateAvailable(); + if (update != null) + { + Logger?.LogInformation($"{Environment.NewLine} ! {update} IS AVAILABLE FOR DOWNLOAD"); + } + } + } + + private async Task DisplayTerseResults(FileManager manager) + { + foreach (var name in manager.Firmware.CollectionNames) + { + Logger?.LogInformation($" {name}"); + var collection = manager.Firmware[name]; + + foreach (var package in collection.OrderBy(p => new Version(p.Version))) + { + if (package == collection.DefaultPackage) + { + Logger?.LogInformation($" * {package.Version} (default)"); + } + else + { + Logger?.LogInformation($" {package.Version}"); + } + } + + var update = await collection.UpdateAvailable(); + if (update != null) + { + Logger?.LogInformation($"{Environment.NewLine} ! {update} IS AVAILABLE FOR DOWNLOAD"); + } + } + } } \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs b/Source/Meadow.CLI/Commands/Current/Firmware/FirmwareWriteCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs rename to Source/Meadow.CLI/Commands/Current/Firmware/FirmwareWriteCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Flash/FlashEraseCommand.cs b/Source/Meadow.CLI/Commands/Current/Flash/FlashEraseCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Flash/FlashEraseCommand.cs rename to Source/Meadow.CLI/Commands/Current/Flash/FlashEraseCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/ListenCommand.cs b/Source/Meadow.CLI/Commands/Current/ListenCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/ListenCommand.cs rename to Source/Meadow.CLI/Commands/Current/ListenCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/LoginCommand.cs b/Source/Meadow.CLI/Commands/Current/LoginCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/LoginCommand.cs rename to Source/Meadow.CLI/Commands/Current/LoginCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/LogoutCommand.cs b/Source/Meadow.CLI/Commands/Current/LogoutCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/LogoutCommand.cs rename to Source/Meadow.CLI/Commands/Current/LogoutCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Nsh/NshDisableCommand.cs b/Source/Meadow.CLI/Commands/Current/Nsh/NshDisableCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Nsh/NshDisableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Nsh/NshDisableCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Nsh/NshEnableCommand.cs b/Source/Meadow.CLI/Commands/Current/Nsh/NshEnableCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Nsh/NshEnableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Nsh/NshEnableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Port/PortListCommand.cs b/Source/Meadow.CLI/Commands/Current/Port/PortListCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Port/PortListCommand.cs rename to Source/Meadow.CLI/Commands/Current/Port/PortListCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Port/PortSelectCommand.cs b/Source/Meadow.CLI/Commands/Current/Port/PortSelectCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Port/PortSelectCommand.cs rename to Source/Meadow.CLI/Commands/Current/Port/PortSelectCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Project/MeadowTemplate.cs b/Source/Meadow.CLI/Commands/Current/Project/MeadowTemplate.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Project/MeadowTemplate.cs rename to Source/Meadow.CLI/Commands/Current/Project/MeadowTemplate.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Project/ProjectInstallCommand.cs b/Source/Meadow.CLI/Commands/Current/Project/ProjectInstallCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Project/ProjectInstallCommand.cs rename to Source/Meadow.CLI/Commands/Current/Project/ProjectInstallCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Project/ProjectNewCommand.cs b/Source/Meadow.CLI/Commands/Current/Project/ProjectNewCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Project/ProjectNewCommand.cs rename to Source/Meadow.CLI/Commands/Current/Project/ProjectNewCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Runtime/RuntimeDisableCommand.cs b/Source/Meadow.CLI/Commands/Current/Runtime/RuntimeDisableCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Runtime/RuntimeDisableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Runtime/RuntimeDisableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Runtime/RuntimeEnableCommand.cs b/Source/Meadow.CLI/Commands/Current/Runtime/RuntimeEnableCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Runtime/RuntimeEnableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Runtime/RuntimeEnableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Runtime/RuntimeStateCommand.cs b/Source/Meadow.CLI/Commands/Current/Runtime/RuntimeStateCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Runtime/RuntimeStateCommand.cs rename to Source/Meadow.CLI/Commands/Current/Runtime/RuntimeStateCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Source/SourceCheckoutCommand.cs b/Source/Meadow.CLI/Commands/Current/Source/SourceCheckoutCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Source/SourceCheckoutCommand.cs rename to Source/Meadow.CLI/Commands/Current/Source/SourceCheckoutCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Source/SourceFetchCommand.cs b/Source/Meadow.CLI/Commands/Current/Source/SourceFetchCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Source/SourceFetchCommand.cs rename to Source/Meadow.CLI/Commands/Current/Source/SourceFetchCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Source/SourcePullCommand.cs b/Source/Meadow.CLI/Commands/Current/Source/SourcePullCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Source/SourcePullCommand.cs rename to Source/Meadow.CLI/Commands/Current/Source/SourcePullCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Source/SourceStatusCommand.cs b/Source/Meadow.CLI/Commands/Current/Source/SourceStatusCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Source/SourceStatusCommand.cs rename to Source/Meadow.CLI/Commands/Current/Source/SourceStatusCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/TelemetryCommand.cs b/Source/Meadow.CLI/Commands/Current/TelemetryCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/TelemetryCommand.cs rename to Source/Meadow.CLI/Commands/Current/TelemetryCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Trace/TraceDisableCommand.cs b/Source/Meadow.CLI/Commands/Current/Trace/TraceDisableCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Trace/TraceDisableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Trace/TraceDisableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Trace/TraceEnableCommand.cs b/Source/Meadow.CLI/Commands/Current/Trace/TraceEnableCommand.cs similarity index 97% rename from Source/v2/Meadow.Cli/Commands/Current/Trace/TraceEnableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Trace/TraceEnableCommand.cs index 1817ca8f..58fad0f4 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/Trace/TraceEnableCommand.cs +++ b/Source/Meadow.CLI/Commands/Current/Trace/TraceEnableCommand.cs @@ -1,36 +1,36 @@ -using CliFx.Attributes; -using Microsoft.Extensions.Logging; - -namespace Meadow.CLI.Commands.DeviceManagement; - -[Command("trace enable", Description = "Enable trace logging on the Meadow")] -public class TraceEnableCommand : BaseDeviceCommand -{ - [CommandOption("level", 'l', Description = "The desired trace level", IsRequired = false)] - public int? Level { get; init; } - - public TraceEnableCommand(MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory) - : base(connectionManager, loggerFactory) - { } - - protected override async ValueTask ExecuteCommand() - { - var connection = await GetCurrentConnection(); - var device = await GetCurrentDevice(); - - connection.DeviceMessageReceived += (s, e) => - { - Logger?.LogInformation(e.message); - }; - - if (Level != null) - { - Logger?.LogInformation($"Setting trace level to {Level}..."); - await device.SetTraceLevel(Level.Value, CancellationToken); - } - - Logger?.LogInformation($"{Strings.EnablingTracing}..."); - - await device.TraceEnable(CancellationToken); - } +using CliFx.Attributes; +using Microsoft.Extensions.Logging; + +namespace Meadow.CLI.Commands.DeviceManagement; + +[Command("trace enable", Description = "Enable trace logging on the Meadow")] +public class TraceEnableCommand : BaseDeviceCommand +{ + [CommandOption("level", 'l', Description = "The desired trace level", IsRequired = false)] + public int? Level { get; init; } + + public TraceEnableCommand(MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory) + : base(connectionManager, loggerFactory) + { } + + protected override async ValueTask ExecuteCommand() + { + var connection = await GetCurrentConnection(); + var device = await GetCurrentDevice(); + + connection.DeviceMessageReceived += (s, e) => + { + Logger?.LogInformation(e.message); + }; + + if (Level != null) + { + Logger?.LogInformation($"Setting trace level to {Level}..."); + await device.SetTraceLevel(Level.Value, CancellationToken); + } + + Logger?.LogInformation($"{Strings.EnablingTracing}..."); + + await device.TraceEnable(CancellationToken); + } } \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Commands/Current/Trace/TraceLevelCommand.cs b/Source/Meadow.CLI/Commands/Current/Trace/TraceLevelCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Trace/TraceLevelCommand.cs rename to Source/Meadow.CLI/Commands/Current/Trace/TraceLevelCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Uart/UartProfilerDisableCommand.cs b/Source/Meadow.CLI/Commands/Current/Uart/UartProfilerDisableCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Uart/UartProfilerDisableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Uart/UartProfilerDisableCommand.cs diff --git a/Source/v2/Meadow.CLI/Commands/Current/Uart/UartProfilerEnableCommand.cs b/Source/Meadow.CLI/Commands/Current/Uart/UartProfilerEnableCommand.cs similarity index 100% rename from Source/v2/Meadow.CLI/Commands/Current/Uart/UartProfilerEnableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Uart/UartProfilerEnableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Uart/UartTraceDisableCommand.cs b/Source/Meadow.CLI/Commands/Current/Uart/UartTraceDisableCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Uart/UartTraceDisableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Uart/UartTraceDisableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/Current/Uart/UartTraceEnableCommand.cs b/Source/Meadow.CLI/Commands/Current/Uart/UartTraceEnableCommand.cs similarity index 100% rename from Source/v2/Meadow.Cli/Commands/Current/Uart/UartTraceEnableCommand.cs rename to Source/Meadow.CLI/Commands/Current/Uart/UartTraceEnableCommand.cs diff --git a/Source/v2/Meadow.Cli/Commands/commands.md b/Source/Meadow.CLI/Commands/commands.md similarity index 100% rename from Source/v2/Meadow.Cli/Commands/commands.md rename to Source/Meadow.CLI/Commands/commands.md diff --git a/Source/v2/Meadow.Cli/ConsoleSpinner.cs b/Source/Meadow.CLI/ConsoleSpinner.cs similarity index 100% rename from Source/v2/Meadow.Cli/ConsoleSpinner.cs rename to Source/Meadow.CLI/ConsoleSpinner.cs diff --git a/Source/v2/Meadow.Cli/Meadow.CLI.csproj b/Source/Meadow.CLI/Meadow.CLI.csproj similarity index 97% rename from Source/v2/Meadow.Cli/Meadow.CLI.csproj rename to Source/Meadow.CLI/Meadow.CLI.csproj index 45677ed3..f611ddc2 100644 --- a/Source/v2/Meadow.Cli/Meadow.CLI.csproj +++ b/Source/Meadow.CLI/Meadow.CLI.csproj @@ -61,6 +61,6 @@ - + diff --git a/Source/v2/Meadow.Cli/Program.cs b/Source/Meadow.CLI/Program.cs similarity index 100% rename from Source/v2/Meadow.Cli/Program.cs rename to Source/Meadow.CLI/Program.cs diff --git a/Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs b/Source/Meadow.CLI/Properties/AssemblyInfo.cs similarity index 100% rename from Source/v2/Meadow.Cli/Properties/AssemblyInfo.cs rename to Source/Meadow.CLI/Properties/AssemblyInfo.cs diff --git a/Source/v2/Meadow.Cli/Properties/launchSettings.json b/Source/Meadow.CLI/Properties/launchSettings.json similarity index 100% rename from Source/v2/Meadow.Cli/Properties/launchSettings.json rename to Source/Meadow.CLI/Properties/launchSettings.json diff --git a/Source/v2/Meadow.Cli/Strings.cs b/Source/Meadow.CLI/Strings.cs similarity index 100% rename from Source/v2/Meadow.Cli/Strings.cs rename to Source/Meadow.CLI/Strings.cs diff --git a/Source/v2/Meadow.CLI/VersionChecker.cs b/Source/Meadow.CLI/VersionChecker.cs similarity index 100% rename from Source/v2/Meadow.CLI/VersionChecker.cs rename to Source/Meadow.CLI/VersionChecker.cs diff --git a/Meadow.CLI/appsettings.json b/Source/Meadow.CLI/appsettings.json similarity index 100% rename from Meadow.CLI/appsettings.json rename to Source/Meadow.CLI/appsettings.json diff --git a/Source/v2/Meadow.Cloud.Client/ApiTokens/ApiTokenClient.cs b/Source/Meadow.Cloud.Client/ApiTokens/ApiTokenClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/ApiTokens/ApiTokenClient.cs rename to Source/Meadow.Cloud.Client/ApiTokens/ApiTokenClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Collections/CollectionClient.cs b/Source/Meadow.Cloud.Client/Collections/CollectionClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Collections/CollectionClient.cs rename to Source/Meadow.Cloud.Client/Collections/CollectionClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Commands/CommandClient.cs b/Source/Meadow.Cloud.Client/Commands/CommandClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Commands/CommandClient.cs rename to Source/Meadow.Cloud.Client/Commands/CommandClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Constants.cs b/Source/Meadow.Cloud.Client/Constants.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Constants.cs rename to Source/Meadow.Cloud.Client/Constants.cs diff --git a/Source/v2/Meadow.Cloud.Client/Devices/AddDeviceRequest.cs b/Source/Meadow.Cloud.Client/Devices/AddDeviceRequest.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Devices/AddDeviceRequest.cs rename to Source/Meadow.Cloud.Client/Devices/AddDeviceRequest.cs diff --git a/Source/v2/Meadow.Cloud.Client/Devices/AddDeviceResponse.cs b/Source/Meadow.Cloud.Client/Devices/AddDeviceResponse.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Devices/AddDeviceResponse.cs rename to Source/Meadow.Cloud.Client/Devices/AddDeviceResponse.cs diff --git a/Source/v2/Meadow.Cloud.Client/Devices/DeviceClient.cs b/Source/Meadow.Cloud.Client/Devices/DeviceClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Devices/DeviceClient.cs rename to Source/Meadow.Cloud.Client/Devices/DeviceClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Devices/IDeviceClient.cs b/Source/Meadow.Cloud.Client/Devices/IDeviceClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Devices/IDeviceClient.cs rename to Source/Meadow.Cloud.Client/Devices/IDeviceClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Firmware/FirmwareClient.cs b/Source/Meadow.Cloud.Client/Firmware/FirmwareClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Firmware/FirmwareClient.cs rename to Source/Meadow.Cloud.Client/Firmware/FirmwareClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Firmware/GetFirmwareVersionResponse.cs b/Source/Meadow.Cloud.Client/Firmware/GetFirmwareVersionResponse.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Firmware/GetFirmwareVersionResponse.cs rename to Source/Meadow.Cloud.Client/Firmware/GetFirmwareVersionResponse.cs diff --git a/Source/v2/Meadow.Cloud.Client/Firmware/GetFirmwareVersionsResponse.cs b/Source/Meadow.Cloud.Client/Firmware/GetFirmwareVersionsResponse.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Firmware/GetFirmwareVersionsResponse.cs rename to Source/Meadow.Cloud.Client/Firmware/GetFirmwareVersionsResponse.cs diff --git a/Source/v2/Meadow.Cloud.Client/Firmware/IFirmwareClient.cs b/Source/Meadow.Cloud.Client/Firmware/IFirmwareClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Firmware/IFirmwareClient.cs rename to Source/Meadow.Cloud.Client/Firmware/IFirmwareClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/IMeadowCloudClient.cs b/Source/Meadow.Cloud.Client/IMeadowCloudClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/IMeadowCloudClient.cs rename to Source/Meadow.Cloud.Client/IMeadowCloudClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Identity/IdentityManager.cs b/Source/Meadow.Cloud.Client/Identity/IdentityManager.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Identity/IdentityManager.cs rename to Source/Meadow.Cloud.Client/Identity/IdentityManager.cs diff --git a/Source/v2/Meadow.Cloud.Client/Identity/Keychain.cs b/Source/Meadow.Cloud.Client/Identity/Keychain.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Identity/Keychain.cs rename to Source/Meadow.Cloud.Client/Identity/Keychain.cs diff --git a/Source/v2/Meadow.Cloud.Client/Identity/LibSecret.cs b/Source/Meadow.Cloud.Client/Identity/LibSecret.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Identity/LibSecret.cs rename to Source/Meadow.Cloud.Client/Identity/LibSecret.cs diff --git a/Source/v2/Meadow.Cloud.Client/Meadow.Cloud.Client.Rider.csproj b/Source/Meadow.Cloud.Client/Meadow.Cloud.Client.Rider.csproj similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Meadow.Cloud.Client.Rider.csproj rename to Source/Meadow.Cloud.Client/Meadow.Cloud.Client.Rider.csproj diff --git a/Source/v2/Meadow.Cloud.Client/Meadow.Cloud.Client.csproj b/Source/Meadow.Cloud.Client/Meadow.Cloud.Client.csproj similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Meadow.Cloud.Client.csproj rename to Source/Meadow.Cloud.Client/Meadow.Cloud.Client.csproj diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudAuthException.cs b/Source/Meadow.Cloud.Client/MeadowCloudAuthException.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudAuthException.cs rename to Source/Meadow.Cloud.Client/MeadowCloudAuthException.cs diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudClient.cs b/Source/Meadow.Cloud.Client/MeadowCloudClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudClient.cs rename to Source/Meadow.Cloud.Client/MeadowCloudClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudClientBase.cs b/Source/Meadow.Cloud.Client/MeadowCloudClientBase.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudClientBase.cs rename to Source/Meadow.Cloud.Client/MeadowCloudClientBase.cs diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudContext.cs b/Source/Meadow.Cloud.Client/MeadowCloudContext.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudContext.cs rename to Source/Meadow.Cloud.Client/MeadowCloudContext.cs diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudException.cs b/Source/Meadow.Cloud.Client/MeadowCloudException.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudException.cs rename to Source/Meadow.Cloud.Client/MeadowCloudException.cs diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudResponse.cs b/Source/Meadow.Cloud.Client/MeadowCloudResponse.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudResponse.cs rename to Source/Meadow.Cloud.Client/MeadowCloudResponse.cs diff --git a/Source/v2/Meadow.Cloud.Client/MeadowCloudUserAgent.cs b/Source/Meadow.Cloud.Client/MeadowCloudUserAgent.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/MeadowCloudUserAgent.cs rename to Source/Meadow.Cloud.Client/MeadowCloudUserAgent.cs diff --git a/Source/v2/Meadow.Cloud.Client/Messages/Collection.cs b/Source/Meadow.Cloud.Client/Messages/Collection.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Messages/Collection.cs rename to Source/Meadow.Cloud.Client/Messages/Collection.cs diff --git a/Source/v2/Meadow.Cloud.Client/Messages/Package.cs b/Source/Meadow.Cloud.Client/Messages/Package.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Messages/Package.cs rename to Source/Meadow.Cloud.Client/Messages/Package.cs diff --git a/Source/v2/Meadow.Cloud.Client/Messages/PackageInfo.cs b/Source/Meadow.Cloud.Client/Messages/PackageInfo.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Messages/PackageInfo.cs rename to Source/Meadow.Cloud.Client/Messages/PackageInfo.cs diff --git a/Source/v2/Meadow.Cloud.Client/Messages/User.cs b/Source/Meadow.Cloud.Client/Messages/User.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Messages/User.cs rename to Source/Meadow.Cloud.Client/Messages/User.cs diff --git a/Source/v2/Meadow.Cloud.Client/Messages/UserOrg.cs b/Source/Meadow.Cloud.Client/Messages/UserOrg.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Messages/UserOrg.cs rename to Source/Meadow.Cloud.Client/Messages/UserOrg.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/ApiTokenService.cs b/Source/Meadow.Cloud.Client/Services/ApiTokenService.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/ApiTokenService.cs rename to Source/Meadow.Cloud.Client/Services/ApiTokenService.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/CloudServiceBase.cs b/Source/Meadow.Cloud.Client/Services/CloudServiceBase.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/CloudServiceBase.cs rename to Source/Meadow.Cloud.Client/Services/CloudServiceBase.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/CollectionService.cs b/Source/Meadow.Cloud.Client/Services/CollectionService.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/CollectionService.cs rename to Source/Meadow.Cloud.Client/Services/CollectionService.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/CommandService.cs b/Source/Meadow.Cloud.Client/Services/CommandService.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/CommandService.cs rename to Source/Meadow.Cloud.Client/Services/CommandService.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/DeviceService.cs b/Source/Meadow.Cloud.Client/Services/DeviceService.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/DeviceService.cs rename to Source/Meadow.Cloud.Client/Services/DeviceService.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/PackageService.cs b/Source/Meadow.Cloud.Client/Services/PackageService.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/PackageService.cs rename to Source/Meadow.Cloud.Client/Services/PackageService.cs diff --git a/Source/v2/Meadow.Cloud.Client/Services/UserService.cs b/Source/Meadow.Cloud.Client/Services/UserService.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Services/UserService.cs rename to Source/Meadow.Cloud.Client/Services/UserService.cs diff --git a/Source/v2/Meadow.Cloud.Client/Users/GetOrganizationResponse.cs b/Source/Meadow.Cloud.Client/Users/GetOrganizationResponse.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Users/GetOrganizationResponse.cs rename to Source/Meadow.Cloud.Client/Users/GetOrganizationResponse.cs diff --git a/Source/v2/Meadow.Cloud.Client/Users/GetUserResponse.cs b/Source/Meadow.Cloud.Client/Users/GetUserResponse.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Users/GetUserResponse.cs rename to Source/Meadow.Cloud.Client/Users/GetUserResponse.cs diff --git a/Source/v2/Meadow.Cloud.Client/Users/IUserClient.cs b/Source/Meadow.Cloud.Client/Users/IUserClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Users/IUserClient.cs rename to Source/Meadow.Cloud.Client/Users/IUserClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Users/UserClient.cs b/Source/Meadow.Cloud.Client/Users/UserClient.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Users/UserClient.cs rename to Source/Meadow.Cloud.Client/Users/UserClient.cs diff --git a/Source/v2/Meadow.Cloud.Client/Usings.cs b/Source/Meadow.Cloud.Client/Usings.cs similarity index 100% rename from Source/v2/Meadow.Cloud.Client/Usings.cs rename to Source/Meadow.Cloud.Client/Usings.cs diff --git a/Source/v2/Meadow.Dfu/DfuSharp.cs b/Source/Meadow.Dfu/DfuSharp.cs similarity index 100% rename from Source/v2/Meadow.Dfu/DfuSharp.cs rename to Source/Meadow.Dfu/DfuSharp.cs diff --git a/Source/v2/Meadow.Dfu/DfuUtils.cs b/Source/Meadow.Dfu/DfuUtils.cs similarity index 100% rename from Source/v2/Meadow.Dfu/DfuUtils.cs rename to Source/Meadow.Dfu/DfuUtils.cs diff --git a/Source/v2/Meadow.Dfu/Meadow.Dfu.csproj b/Source/Meadow.Dfu/Meadow.Dfu.csproj similarity index 100% rename from Source/v2/Meadow.Dfu/Meadow.Dfu.csproj rename to Source/Meadow.Dfu/Meadow.Dfu.csproj diff --git a/Source/v2/Meadow.Firmware/FirmwareWriter.cs b/Source/Meadow.Firmware/FirmwareWriter.cs similarity index 100% rename from Source/v2/Meadow.Firmware/FirmwareWriter.cs rename to Source/Meadow.Firmware/FirmwareWriter.cs diff --git a/Source/v2/Meadow.Firmware/Meadow.Firmware.csproj b/Source/Meadow.Firmware/Meadow.Firmware.csproj similarity index 100% rename from Source/v2/Meadow.Firmware/Meadow.Firmware.csproj rename to Source/Meadow.Firmware/Meadow.Firmware.csproj diff --git a/Source/v2/Meadow.HCom/AssemblyAttributes.cs b/Source/Meadow.Hcom/AssemblyAttributes.cs similarity index 100% rename from Source/v2/Meadow.HCom/AssemblyAttributes.cs rename to Source/Meadow.Hcom/AssemblyAttributes.cs diff --git a/Source/v2/Meadow.HCom/CobsTools.cs b/Source/Meadow.Hcom/CobsTools.cs similarity index 100% rename from Source/v2/Meadow.HCom/CobsTools.cs rename to Source/Meadow.Hcom/CobsTools.cs diff --git a/Source/v2/Meadow.HCom/ConnectionManager.cs b/Source/Meadow.Hcom/ConnectionManager.cs similarity index 100% rename from Source/v2/Meadow.HCom/ConnectionManager.cs rename to Source/Meadow.Hcom/ConnectionManager.cs diff --git a/Source/v2/Meadow.HCom/ConnectionState.cs b/Source/Meadow.Hcom/ConnectionState.cs similarity index 100% rename from Source/v2/Meadow.HCom/ConnectionState.cs rename to Source/Meadow.Hcom/ConnectionState.cs diff --git a/Source/v2/Meadow.HCom/Connections/ConnectionBase.cs b/Source/Meadow.Hcom/Connections/ConnectionBase.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/Connections/ConnectionBase.cs rename to Source/Meadow.Hcom/Connections/ConnectionBase.cs diff --git a/Source/v2/Meadow.HCom/Connections/LocalConnection.cs b/Source/Meadow.Hcom/Connections/LocalConnection.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/Connections/LocalConnection.cs rename to Source/Meadow.Hcom/Connections/LocalConnection.cs diff --git a/Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs b/Source/Meadow.Hcom/Connections/SerialConnection.ListenerProc.cs similarity index 100% rename from Source/v2/Meadow.HCom/Connections/SerialConnection.ListenerProc.cs rename to Source/Meadow.Hcom/Connections/SerialConnection.ListenerProc.cs diff --git a/Source/v2/Meadow.HCom/Connections/SerialConnection.cs b/Source/Meadow.Hcom/Connections/SerialConnection.cs old mode 100755 new mode 100644 similarity index 96% rename from Source/v2/Meadow.HCom/Connections/SerialConnection.cs rename to Source/Meadow.Hcom/Connections/SerialConnection.cs index ba69186a..59641049 --- a/Source/v2/Meadow.HCom/Connections/SerialConnection.cs +++ b/Source/Meadow.Hcom/Connections/SerialConnection.cs @@ -1,1294 +1,1294 @@ -using System.Buffers; -using System.Collections.Concurrent; -using System.IO.Ports; -using System.Security.Cryptography; - -namespace Meadow.Hcom; - -public delegate void ConnectionStateChangedHandler(SerialConnection connection, ConnectionState oldState, ConnectionState newState); - -public partial class SerialConnection : ConnectionBase, IDisposable -{ - public const int DefaultBaudRate = 115200; - public const int ReadBufferSizeBytes = 0x2000; - private const int DefaultTimeout = 5000; - - private event EventHandler FileWriteAccepted = default!; - private event EventHandler FileTextReceived = default!; - public event ConnectionStateChangedHandler ConnectionStateChanged = default!; - - private readonly SerialPort _port; - private readonly ILogger? _logger; - private bool _isDisposed; - private ConnectionState _state; - private readonly List _listeners = new List(); - private readonly ConcurrentQueue _commandQueue = new ConcurrentQueue(); - private readonly AutoResetEvent _commandEvent = new AutoResetEvent(false); - private bool _maintainConnection; - private Thread? _connectionManager = null; - private readonly List _textList = new List(); - private int _messageCount = 0; - private ReadFileInfo? _readFileInfo = null; - private string? _lastError = null; - - public override string Name { get; } - - public SerialConnection(string port, ILogger? logger = default) - { - if (!SerialPort.GetPortNames().Contains(port, StringComparer.InvariantCultureIgnoreCase)) - { - throw new ArgumentException($"Serial Port '{port}' not found."); - } - - Name = port; - State = ConnectionState.Disconnected; - _logger = logger; - _port = new SerialPort(port); - _port.ReadTimeout = _port.WriteTimeout = DefaultTimeout; - - new Task( - () => _ = ListenerProc(), - TaskCreationOptions.LongRunning) - .Start(); - - new Thread(CommandManager) - { - IsBackground = true, - Name = "HCOM Sender" - } - .Start(); - } - - private bool MaintainConnection - { - get => _maintainConnection; - set - { - if (value == MaintainConnection) return; - - _maintainConnection = value; - - if (value) - { - if (_connectionManager == null || _connectionManager.ThreadState != System.Threading.ThreadState.Running) - { - _connectionManager = new Thread(ConnectionManagerProc) - { - IsBackground = true, - Name = "HCOM Connection Manager" - }; - _connectionManager.Start(); - } - } - } - } - - private void ConnectionManagerProc() - { - while (_maintainConnection) - { - if (!_port.IsOpen) - { - try - { - Debug.WriteLine("Opening COM port..."); - Open(); - Debug.WriteLine("Opened COM port"); - } - catch (Exception ex) - { - Debug.WriteLine($"{ex.Message}"); - Thread.Sleep(1000); - } - } - else - { - Thread.Sleep(1000); - } - } - } - - public void AddListener(IConnectionListener listener) - { - lock (_listeners) - { - _listeners.Add(listener); - } - - Open(); - - MaintainConnection = true; - } - - public void RemoveListener(IConnectionListener listener) - { - lock (_listeners) - { - _listeners.Remove(listener); - } - - // TODO: stop maintaining connection? - } - - public override ConnectionState State - { - get => _state; - protected set - { - if (value == State) { return; } - - var old = _state; - _state = value; - ConnectionStateChanged?.Invoke(this, old, State); - } - } - - private void Open() - { - if (!_port.IsOpen) - { - try - { - _port.Open(); - } - catch (FileNotFoundException) - { - throw new Exception($"Serial port '{_port.PortName}' not found"); - } - catch (UnauthorizedAccessException uae) - { - throw new Exception($"{uae.Message}"); - } - catch (Exception ex) - { - throw new Exception($"Unable to open port '{_port.PortName}' - {ex.Message}"); - } - - State = ConnectionState.Connected; - } - } - - private void Close() - { - if (_port.IsOpen) - { - _port.Close(); - } - - State = ConnectionState.Disconnected; - } - - public override void Detach() - { - if (MaintainConnection) - { - // TODO: close this up - } - - Close(); - } - - public override async Task Attach(CancellationToken? cancellationToken = null, int timeoutSeconds = 10) - { - try - { - // ensure the port is open - Open(); - - // search for the device via HCOM - we'll use a simple command since we don't have a "ping" - var command = RequestBuilder.Build(); - - // sequence numbers are only for file retrieval - Setting it to non-zero will cause it to hang - - _port.DiscardInBuffer(); - - // wait for a response - var timeout = timeoutSeconds * 50; - var dataReceived = false; - - // local function so we can unsubscribe - var count = _messageCount; - - EnqueueRequest(command); - - while (timeout-- > 0) - { - if (cancellationToken?.IsCancellationRequested ?? false) return null; - if (timeout <= 0) throw new TimeoutException(); - - if (count != _messageCount) - { - dataReceived = true; - break; - } - - await Task.Delay(20); - } - - // if HCOM fails, check for DFU/bootloader mode? only if we're doing an OS thing, so maybe no - - // create the device instance - if (dataReceived) - { - Device = new MeadowDevice(this); - } - - return Device; - } - catch (Exception e) - { - _logger?.LogError(e, "Failed to connect"); - throw; - } - } - - private void CommandManager() - { - while (!_isDisposed) - { - _commandEvent.WaitOne(1000); - - while (_commandQueue.Count > 0) - { - Debug.WriteLine($"There are {_commandQueue.Count} pending commands"); - - _commandQueue.TryDequeue(out var pendingCommand); - - if (pendingCommand is Request command) - { - // if this is a file write, we need to packetize for progress - var payload = command.Serialize(); - EncodeAndSendPacket(payload); - } - } - } - } - - private class ReadFileInfo - { - private string? _localFileName; - - public string MeadowFileName { get; set; } = default!; - public string? LocalFileName - { - get - { - if (_localFileName != null) return _localFileName; - - return Path.Combine(Environment.CurrentDirectory, Path.GetFileName(MeadowFileName)); - } - set => _localFileName = value; - } - public FileStream FileStream { get; set; } = default!; - } - - public void EnqueueRequest(IRequest command) - { - // TODO: verify we're connected - - if (command is InitFileReadRequest sfr) - { - _readFileInfo = new ReadFileInfo - { - MeadowFileName = sfr.MeadowFileName, - LocalFileName = sfr.LocalFileName, - }; - } - - _commandQueue.Enqueue(command); - _commandEvent.Set(); - } - - private void EncodeAndSendPacket(byte[] messageBytes, CancellationToken? cancellationToken = null) - { - EncodeAndSendPacket(messageBytes, messageBytes.Length, cancellationToken); - } - - private void EncodeAndSendPacket(byte[] messageBytes, int length, CancellationToken? cancellationToken = null) - { - //Debug.WriteLine($"+EncodeAndSendPacket({length} bytes)"); - - while (!_port.IsOpen) - { - _state = ConnectionState.Disconnected; - Thread.Sleep(100); - // wait for the port to open - } - - _state = ConnectionState.Connected; - - try - { - int encodedToSend; - byte[] encodedBytes; - - // For file download this is a LOT of messages - // _uiSupport.WriteDebugLine($"Sending packet with {messageSize} bytes"); - - // For testing calculate the crc including the sequence number - //_packetCrc32 = NuttxCrc.Crc32part(messageBytes, messageSize, 0, _packetCrc32); - try - { - // The encoded size using COBS is just a bit more than the original size adding 1 byte - // every 254 bytes plus 1 and need room for beginning and ending delimiters. - var l = Protocol.HCOM_PROTOCOL_ENCODED_MAX_SIZE + (Protocol.HCOM_PROTOCOL_ENCODED_MAX_SIZE / 254) + 8; - encodedBytes = new byte[l + 2]; - - // Skip over first byte so it can be a start delimiter - encodedToSend = CobsTools.CobsEncoding(messageBytes, 0, length, ref encodedBytes, 1); - - // DEBUG TESTING - if (encodedToSend == -1) - { - _logger?.LogError($"Error - encodedToSend == -1"); - return; - } - - if (_port == null) - { - _logger?.LogError($"Error - SerialPort == null"); - throw new Exception("Port is null"); - } - } - catch (Exception except) - { - string msg = string.Format("Send setup Exception: {0}", except); - _logger?.LogError(msg); - throw; - } - - // Add delimiters to packet boundaries - try - { - encodedBytes[0] = 0; // Start delimiter - encodedToSend++; - encodedBytes[encodedToSend] = 0; // End delimiter - encodedToSend++; - } - catch (Exception encodedBytesEx) - { - // This should drop the connection and retry - Debug.WriteLine($"Adding encodeBytes delimiter threw: {encodedBytesEx}"); - Thread.Sleep(500); // Place for break point - throw; - } - - try - { - // Send the data to Meadow - // DO NOT USE _port.BaseStream. It disables port timeouts! - _port.Write(encodedBytes, 0, encodedToSend); - } - catch (InvalidOperationException ioe) // Port not opened - { - string msg = string.Format("Write but port not opened. Exception: {0}", ioe); - _logger?.LogError(msg); - throw; - } - catch (ArgumentOutOfRangeException aore) // offset or count don't match buffer - { - string msg = string.Format("Write buffer, offset and count don't line up. Exception: {0}", aore); - _logger?.LogError(msg); - throw; - } - catch (ArgumentException ae) // offset plus count > buffer length - { - string msg = string.Format($"Write offset plus count > buffer length. Exception: {0}", ae); - _logger?.LogError(msg); - throw; - } - catch (TimeoutException te) // Took too long to send - { - string msg = string.Format("Write took too long to send. Exception: {0}", te); - _logger?.LogError(msg); - throw; - } - } - catch (Exception except) - { - // DID YOU RESTART MEADOW? - // This should drop the connection and retry - _logger?.LogError($"EncodeAndSendPacket threw: {except}"); - throw; - } - } - - private class SerialMessage - { - private readonly IList> _segments; - - public SerialMessage(Memory segment) - { - _segments = new List> - { - segment - }; - } - - public void AddSegment(Memory segment) - { - _segments.Add(segment); - } - - public byte[] ToArray() - { - using var ms = new MemoryStream(); - foreach (var segment in _segments) - { - // We could just call ToArray on the `Memory` but that will result in an uncontrolled allocation. - var tmp = ArrayPool.Shared.Rent(segment.Length); - segment.CopyTo(tmp); - ms.Write(tmp, 0, segment.Length); - ArrayPool.Shared.Return(tmp); - } - return ms.ToArray(); - } - } - - private bool DecodeAndProcessPacket(Memory packetBuffer, CancellationToken cancellationToken) - { - var decodedBuffer = ArrayPool.Shared.Rent(8192); - var packetLength = packetBuffer.Length; - // It's possible that we may find a series of 0x00 values in the buffer. - // This is because when the sender is blocked (because this code isn't - // running) it will attempt to send a single 0x00 before the full message. - // This allows it to test for a connection. When the connection is - // unblocked this 0x00 is sent and gets put into the buffer along with - // any others that were queued along the usb serial pipe line. - if (packetLength == 1) - { - //_logger.LogTrace("Throwing out 0x00 from buffer"); - return false; - } - - var decodedSize = CobsTools.CobsDecoding(packetBuffer.ToArray(), packetLength, ref decodedBuffer); - - ArrayPool.Shared.Return(decodedBuffer); - return true; - } - - protected override void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - Close(); - _port.Dispose(); - } - - _isDisposed = true; - } - } - - // ---------------------------------------------- - // ---------------------------------------------- - // ---------------------------------------------- - - private Exception? _lastException; - private bool? _textListComplete; - private DeviceInfo? _deviceInfo; - private RequestType? _lastRequestConcluded = null; - private List StdOut { get; } = new List(); - private List StdErr { get; } = new List(); - private List InfoMessages { get; } = new List(); - - private const string MonoStateToken = "Mono is"; - private const string RuntimeStateToken = "Runtime is"; - private const string MonoIsEnabledToken = "Mono is enabled"; - private const string RuntimeIsEnabledToken = "Runtime is enabled"; - private const string RtcRetrievalToken = "UTC time:"; - - public int CommandTimeoutSeconds { get; set; } = 30; - - private async Task WaitForFileReadCompleted(CancellationToken? cancellationToken) - { - var timeout = CommandTimeoutSeconds * 2; - - var completed = false; - - void LocalFRCHandler(object s, string e) - { - completed = true; - } - void LocalFBRHandler(object s, int e) - { - timeout = CommandTimeoutSeconds * 2; - } - - FileBytesReceived += LocalFBRHandler; - FileReadCompleted += LocalFRCHandler; - - try - { - while (timeout-- > 0) - { - if (cancellationToken?.IsCancellationRequested ?? false) return false; - if (_lastException != null) return false; - - if (timeout <= 0) throw new TimeoutException(); - - if (completed) return true; - - await Task.Delay(500); - } - } - finally - { - // clean up local events - FileBytesReceived -= LocalFBRHandler; - FileReadCompleted -= LocalFRCHandler; - } - - return true; - } - - private async Task WaitForResult(Func checkAction, CancellationToken? cancellationToken) - { - var timeout = CommandTimeoutSeconds * 2; - - while (timeout-- > 0) - { - if (cancellationToken?.IsCancellationRequested ?? false) return false; - if (_lastException != null) return false; - - if (timeout <= 0) throw new TimeoutException(); - - if (checkAction()) - { - break; - } - - await Task.Delay(500); - } - - return true; - } - - private async Task WaitForResponseText(string textToAwait, CancellationToken? cancellationToken = null) - { - return await WaitForResult(() => - { - if (InfoMessages.Count > 0) - { - var m = InfoMessages.FirstOrDefault(i => i.Contains(textToAwait)); - if (m != null) - { - return true; - } - } - - return false; - }, cancellationToken); - } - - private async Task WaitForConcluded(RequestType? requestType = null, CancellationToken? cancellationToken = null) - { - return await WaitForResult(() => - { - if (_lastRequestConcluded != null) - { - if (requestType == null || requestType == _lastRequestConcluded) - { - return true; - } - } - - return false; - }, cancellationToken); - } - - public override async Task SetRtcTime(DateTimeOffset dateTime, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.Time = dateTime; - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - var success = await WaitForResult(() => - { - if (_lastRequestConcluded != null && _lastRequestConcluded == RequestType.HCOM_MDOW_REQUEST_RTC_SET_TIME_CMD) - { - return true; - } - - return false; - }, cancellationToken); - } - - public override async Task GetRtcTime(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - InfoMessages.Clear(); - - EnqueueRequest(command); - - DateTimeOffset? now = null; - - var success = await WaitForResult(() => - { - if (InfoMessages.Count > 0) - { - var m = InfoMessages.FirstOrDefault(i => i.Contains(RtcRetrievalToken)); - if (m != null) - { - var timeString = m.Substring(m.IndexOf(RtcRetrievalToken) + RtcRetrievalToken.Length); - now = DateTimeOffset.Parse(timeString); - return true; - } - } - - return false; - }, cancellationToken); - - return now; - } - - public override async Task IsRuntimeEnabled(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - InfoMessages.Clear(); - - EnqueueRequest(command); - - // wait for an information response - var timeout = CommandTimeoutSeconds * 2; - while (timeout-- > 0) - { - if (cancellationToken?.IsCancellationRequested ?? false) - { - return false; - } - if (timeout <= 0) - { - throw new TimeoutException(); - } - - if (InfoMessages.Count > 0) - { - var m = InfoMessages.FirstOrDefault(i => - i.Contains(RuntimeStateToken) || - i.Contains(MonoStateToken)); - if (m != null) - { - return (m == RuntimeIsEnabledToken) || (m == MonoIsEnabledToken); - } - } - - await Task.Delay(500); - } - return false; - } - - public override async Task RuntimeEnable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - InfoMessages.Clear(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task RuntimeDisable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - InfoMessages.Clear(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task NshEnable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(1); - - InfoMessages.Clear(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task NshDisable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(0); - - InfoMessages.Clear(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task TraceEnable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task TraceDisable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task UartTraceEnable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task UartProfilerEnable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task UartProfilerDisable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task UartTraceDisable(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task SetTraceLevel(int level, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.UserData = (uint)level; - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task SetDeveloperParameter(ushort parameter, uint value, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.ExtraData = parameter; - command.UserData = value; - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - } - - public override async Task ResetDevice(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - EnqueueRequest(command); - - // we have to give time for the device to actually reset - await Task.Delay(1500); - - await WaitForMeadowAttach(cancellationToken); - } - - public override async Task GetDeviceInfo(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _deviceInfo = null; - - _lastException = null; - EnqueueRequest(command); - - if (!await WaitForResult( - () => _deviceInfo != null, - cancellationToken)) - { - return null; - } - - return _deviceInfo; - } - - public override async Task GetFileList(string folder, bool includeCrcs, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.IncludeCrcs = includeCrcs; - - command.Path = folder; - - EnqueueRequest(command); - - if (!await WaitForResult( - () => _textListComplete ?? false, - cancellationToken)) - { - _textListComplete = null; - return null; - } - - var list = new List(); - - foreach (var candidate in _textList) - { - var fi = MeadowFileInfo.Parse(candidate, folder); - if (fi != null) - { - list.Add(fi); - } - } - - _textListComplete = null; - return list.ToArray(); - } - - public override async Task WriteFile( - string localFileName, - string? meadowFileName = null, - CancellationToken? cancellationToken = null) - { - return await WriteFile(localFileName, meadowFileName, - RequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER, - RequestType.HCOM_MDOW_REQUEST_END_FILE_TRANSFER, - 0, - cancellationToken); - } - - public override async Task WriteRuntime( - string localFileName, - CancellationToken? cancellationToken = null) - { - var commandTimeout = CommandTimeoutSeconds; - - - CommandTimeoutSeconds = 120; - _lastRequestConcluded = null; - - try - { - InfoMessages.Clear(); - - _lastRequestConcluded = null; - - var status = await WriteFile(localFileName, "Meadow.OS.Runtime.bin", - RequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME, - RequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_FILE_END, - 0, - cancellationToken); - - - if (status) - { - await WaitForConcluded(null, cancellationToken); - } - - return status; - } - finally - { - CommandTimeoutSeconds = commandTimeout; - } - } - - public override async Task WriteCoprocessorFile( - string localFileName, - int destinationAddress, - CancellationToken? cancellationToken = null) - { - // make the timeouts much bigger, as the ESP flash takes a lot of time - var readTimeout = _port.ReadTimeout; - var commandTimeout = CommandTimeoutSeconds; - _lastRequestConcluded = null; - - _port.ReadTimeout = 60000; - CommandTimeoutSeconds = 180; - InfoMessages.Clear(); - - try - { - RaiseConnectionMessage($"Transferring {Path.GetFileName(localFileName)} to coprocessor..."); - - // push the file to the device - if (!await WriteFile(localFileName, null, - RequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER, - RequestType.HCOM_MDOW_REQUEST_END_ESP_FILE_TRANSFER, - destinationAddress, - cancellationToken)) - { - return false; - } - - - _lastRequestConcluded = null; - - // now wait for the STM32 to finish writing to the ESP32 - await WaitForConcluded(null, cancellationToken); - return true; - } - finally - { - _port.ReadTimeout = readTimeout; - CommandTimeoutSeconds = commandTimeout; - } - } - - private async Task WriteFile( - string localFileName, - string? meadowFileName, - RequestType initialRequestType, - RequestType endRequestType, - int writeAddress = 0, - CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - var fileBytes = File.ReadAllBytes(localFileName); - - var fileHash = Encoding.ASCII.GetBytes("12345678901234567890123456789012"); // must be 32 bytes - if (writeAddress != 0) - { - // calculate the MD5 hash of the file - we have to send it as a UTF8 string, not as bytes. - using var md5 = MD5.Create(); - var hashBytes = md5.ComputeHash(fileBytes); - var hashString = BitConverter.ToString(hashBytes) - .Replace("-", "") - .ToLowerInvariant(); - fileHash = Encoding.UTF8.GetBytes(hashString); - } - var fileCrc = NuttxCrc.Crc32part(fileBytes, (uint)fileBytes.Length, 0); - - command.SetParameters( - localFileName, - meadowFileName ?? Path.GetFileName(localFileName), - fileCrc, - writeAddress, - fileHash, - initialRequestType); - - var accepted = false; - Exception? ex = null; - var needsRetry = false; - - void OnFileWriteAccepted(object? sender, EventArgs a) - { - accepted = true; - } - void OnFileError(object? sender, Exception exception) - { - ex = exception; - } - void OnFileRetry(object? sender, EventArgs e) - { - needsRetry = true; - } - - FileWriteAccepted += OnFileWriteAccepted; - FileException += OnFileError; - FileWriteFailed += OnFileRetry; - - EnqueueRequest(command); - - // this will wait for a "file write accepted" from the target - if (!await WaitForResult( - () => - { - if (ex != null) throw ex; - return accepted; - }, - cancellationToken)) - { - return false; - } - - // now send the file data - // The maximum data bytes is max packet size - 2 bytes for the sequence number - byte[] packet = new byte[Protocol.HCOM_PROTOCOL_PACKET_MAX_SIZE - 2]; - ushort sequenceNumber = 0; - - var progress = 0; - var expected = fileBytes.Length; - - var fileName = Path.GetFileName(localFileName); - - base.RaiseFileWriteProgress(fileName, progress, expected); - - var oldTimeout = _port.ReadTimeout; - _port.ReadTimeout = 60000; - - while (true && !needsRetry) - { - if (cancellationToken.HasValue && cancellationToken.Value.IsCancellationRequested) - { - return false; - } - - sequenceNumber++; - - Array.Copy(BitConverter.GetBytes(sequenceNumber), packet, 2); - - var toRead = fileBytes.Length - progress; - if (toRead > packet.Length - 2) - { - toRead = packet.Length - 2; - } - Array.Copy(fileBytes, progress, packet, 2, toRead); - try - { - EncodeAndSendPacket(packet, toRead + 2, cancellationToken); - } - catch (Exception) - { - break; - } - - progress += toRead; - base.RaiseFileWriteProgress(fileName, progress, expected); - if (progress >= fileBytes.Length) break; - } - - if (!needsRetry) - { - _port.ReadTimeout = oldTimeout; - - base.RaiseFileWriteProgress(fileName, expected, expected); - - // finish with an "end" message - not enqued because this is all a serial operation - var request = RequestBuilder.Build(); - request.SetRequestType(endRequestType); - var p = request.Serialize(); - EncodeAndSendPacket(p, cancellationToken); - } - - FileWriteAccepted -= OnFileWriteAccepted; - FileException -= OnFileError; - FileWriteFailed -= OnFileRetry; - - return !needsRetry; - } - - public override async Task ReadFile(string meadowFileName, string? localFileName = null, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.MeadowFileName = meadowFileName; - command.LocalFileName = localFileName; - - var completed = false; - Exception? ex = null; - - void OnFileReadCompleted(object? sender, string filename) - { - completed = true; - } - void OnFileError(object? sender, Exception exception) - { - ex = exception; - } - - try - { - FileReadCompleted += OnFileReadCompleted; - FileException += OnFileError; - ConnectionError += OnFileError; - - EnqueueRequest(command); - - if (!await WaitForFileReadCompleted(cancellationToken)) - { - return false; - } - - return ex == null; - } - finally - { - FileReadCompleted -= OnFileReadCompleted; - FileException -= OnFileError; - } - } - - public override async Task ReadFileString(string fileName, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.MeadowFileName = fileName; - - string? contents = null; - - void OnFileDataReceived(object? sender, string data) - { - contents = data; - } - - FileTextReceived += OnFileDataReceived; - - _lastRequestConcluded = null; - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - - return contents; - } - - public override async Task DeleteFile(string meadowFileName, CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - command.MeadowFileName = meadowFileName; - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - var result = await WaitForConcluded(null, cancellationToken); - return result; - } - - public override async Task EraseFlash(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - _lastRequestConcluded = null; - - var lastTimeout = CommandTimeoutSeconds; - - CommandTimeoutSeconds = 5 * 60; - - EnqueueRequest(command); - - await WaitForConcluded(null, cancellationToken); - - CommandTimeoutSeconds = lastTimeout; - } - - public override async Task GetPublicKey(CancellationToken? cancellationToken = null) - { - var command = RequestBuilder.Build(); - - string contents = string.Empty; - - void OnFileDataReceived(object? sender, string data) - { - contents = data; - } - - FileTextReceived += OnFileDataReceived; - - var lastTimeout = CommandTimeoutSeconds; - - CommandTimeoutSeconds = 5 * 60; - - _lastRequestConcluded = null; - EnqueueRequest(command); - - if (!await WaitForResult( - () => - { - return contents != string.Empty; - }, - cancellationToken)) - { - CommandTimeoutSeconds = lastTimeout; - return string.Empty; - } - - CommandTimeoutSeconds = lastTimeout; - - return contents; - } - - public override async Task StartDebuggingSession(int port, ILogger? logger, CancellationToken cancellationToken) - { - if (Device == null) - { - throw new DeviceNotFoundException(); - } - - var debuggingServer = new DebuggingServer(this, port, logger); - - logger?.LogDebug("Tell the Debugging Server to Start Listening"); - await debuggingServer.StartListening(cancellationToken); - - logger?.LogDebug($"Start Debugging on port: {port}"); - await Device.StartDebugging(port, logger, cancellationToken); - - return debuggingServer; - } - - public override async Task StartDebugging(int port, ILogger? logger, CancellationToken? cancellationToken) - { - var command = RequestBuilder.Build(); - - if (command != null) - { - InfoMessages.Clear(); - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - await WaitForMeadowAttach(cancellationToken); - } - else - { - new Exception($"{typeof(StartDebuggingRequest)} command failed to build"); - } - } - - public override Task SendDebuggerData(byte[] debuggerData, uint userData, CancellationToken? cancellationToken) - { - var command = RequestBuilder.Build(userData); - command.DebuggerData = debuggerData; - - _lastRequestConcluded = null; - - EnqueueRequest(command); - - return Task.CompletedTask; - } +using System.Buffers; +using System.Collections.Concurrent; +using System.IO.Ports; +using System.Security.Cryptography; + +namespace Meadow.Hcom; + +public delegate void ConnectionStateChangedHandler(SerialConnection connection, ConnectionState oldState, ConnectionState newState); + +public partial class SerialConnection : ConnectionBase, IDisposable +{ + public const int DefaultBaudRate = 115200; + public const int ReadBufferSizeBytes = 0x2000; + private const int DefaultTimeout = 5000; + + private event EventHandler FileWriteAccepted = default!; + private event EventHandler FileTextReceived = default!; + public event ConnectionStateChangedHandler ConnectionStateChanged = default!; + + private readonly SerialPort _port; + private readonly ILogger? _logger; + private bool _isDisposed; + private ConnectionState _state; + private readonly List _listeners = new List(); + private readonly ConcurrentQueue _commandQueue = new ConcurrentQueue(); + private readonly AutoResetEvent _commandEvent = new AutoResetEvent(false); + private bool _maintainConnection; + private Thread? _connectionManager = null; + private readonly List _textList = new List(); + private int _messageCount = 0; + private ReadFileInfo? _readFileInfo = null; + private string? _lastError = null; + + public override string Name { get; } + + public SerialConnection(string port, ILogger? logger = default) + { + if (!SerialPort.GetPortNames().Contains(port, StringComparer.InvariantCultureIgnoreCase)) + { + throw new ArgumentException($"Serial Port '{port}' not found."); + } + + Name = port; + State = ConnectionState.Disconnected; + _logger = logger; + _port = new SerialPort(port); + _port.ReadTimeout = _port.WriteTimeout = DefaultTimeout; + + new Task( + () => _ = ListenerProc(), + TaskCreationOptions.LongRunning) + .Start(); + + new Thread(CommandManager) + { + IsBackground = true, + Name = "HCOM Sender" + } + .Start(); + } + + private bool MaintainConnection + { + get => _maintainConnection; + set + { + if (value == MaintainConnection) return; + + _maintainConnection = value; + + if (value) + { + if (_connectionManager == null || _connectionManager.ThreadState != System.Threading.ThreadState.Running) + { + _connectionManager = new Thread(ConnectionManagerProc) + { + IsBackground = true, + Name = "HCOM Connection Manager" + }; + _connectionManager.Start(); + } + } + } + } + + private void ConnectionManagerProc() + { + while (_maintainConnection) + { + if (!_port.IsOpen) + { + try + { + Debug.WriteLine("Opening COM port..."); + Open(); + Debug.WriteLine("Opened COM port"); + } + catch (Exception ex) + { + Debug.WriteLine($"{ex.Message}"); + Thread.Sleep(1000); + } + } + else + { + Thread.Sleep(1000); + } + } + } + + public void AddListener(IConnectionListener listener) + { + lock (_listeners) + { + _listeners.Add(listener); + } + + Open(); + + MaintainConnection = true; + } + + public void RemoveListener(IConnectionListener listener) + { + lock (_listeners) + { + _listeners.Remove(listener); + } + + // TODO: stop maintaining connection? + } + + public override ConnectionState State + { + get => _state; + protected set + { + if (value == State) { return; } + + var old = _state; + _state = value; + ConnectionStateChanged?.Invoke(this, old, State); + } + } + + private void Open() + { + if (!_port.IsOpen) + { + try + { + _port.Open(); + } + catch (FileNotFoundException) + { + throw new Exception($"Serial port '{_port.PortName}' not found"); + } + catch (UnauthorizedAccessException uae) + { + throw new Exception($"{uae.Message}"); + } + catch (Exception ex) + { + throw new Exception($"Unable to open port '{_port.PortName}' - {ex.Message}"); + } + + State = ConnectionState.Connected; + } + } + + private void Close() + { + if (_port.IsOpen) + { + _port.Close(); + } + + State = ConnectionState.Disconnected; + } + + public override void Detach() + { + if (MaintainConnection) + { + // TODO: close this up + } + + Close(); + } + + public override async Task Attach(CancellationToken? cancellationToken = null, int timeoutSeconds = 10) + { + try + { + // ensure the port is open + Open(); + + // search for the device via HCOM - we'll use a simple command since we don't have a "ping" + var command = RequestBuilder.Build(); + + // sequence numbers are only for file retrieval - Setting it to non-zero will cause it to hang + + _port.DiscardInBuffer(); + + // wait for a response + var timeout = timeoutSeconds * 50; + var dataReceived = false; + + // local function so we can unsubscribe + var count = _messageCount; + + EnqueueRequest(command); + + while (timeout-- > 0) + { + if (cancellationToken?.IsCancellationRequested ?? false) return null; + if (timeout <= 0) throw new TimeoutException(); + + if (count != _messageCount) + { + dataReceived = true; + break; + } + + await Task.Delay(20); + } + + // if HCOM fails, check for DFU/bootloader mode? only if we're doing an OS thing, so maybe no + + // create the device instance + if (dataReceived) + { + Device = new MeadowDevice(this); + } + + return Device; + } + catch (Exception e) + { + _logger?.LogError(e, "Failed to connect"); + throw; + } + } + + private void CommandManager() + { + while (!_isDisposed) + { + _commandEvent.WaitOne(1000); + + while (_commandQueue.Count > 0) + { + Debug.WriteLine($"There are {_commandQueue.Count} pending commands"); + + _commandQueue.TryDequeue(out var pendingCommand); + + if (pendingCommand is Request command) + { + // if this is a file write, we need to packetize for progress + var payload = command.Serialize(); + EncodeAndSendPacket(payload); + } + } + } + } + + private class ReadFileInfo + { + private string? _localFileName; + + public string MeadowFileName { get; set; } = default!; + public string? LocalFileName + { + get + { + if (_localFileName != null) return _localFileName; + + return Path.Combine(Environment.CurrentDirectory, Path.GetFileName(MeadowFileName)); + } + set => _localFileName = value; + } + public FileStream FileStream { get; set; } = default!; + } + + public void EnqueueRequest(IRequest command) + { + // TODO: verify we're connected + + if (command is InitFileReadRequest sfr) + { + _readFileInfo = new ReadFileInfo + { + MeadowFileName = sfr.MeadowFileName, + LocalFileName = sfr.LocalFileName, + }; + } + + _commandQueue.Enqueue(command); + _commandEvent.Set(); + } + + private void EncodeAndSendPacket(byte[] messageBytes, CancellationToken? cancellationToken = null) + { + EncodeAndSendPacket(messageBytes, messageBytes.Length, cancellationToken); + } + + private void EncodeAndSendPacket(byte[] messageBytes, int length, CancellationToken? cancellationToken = null) + { + //Debug.WriteLine($"+EncodeAndSendPacket({length} bytes)"); + + while (!_port.IsOpen) + { + _state = ConnectionState.Disconnected; + Thread.Sleep(100); + // wait for the port to open + } + + _state = ConnectionState.Connected; + + try + { + int encodedToSend; + byte[] encodedBytes; + + // For file download this is a LOT of messages + // _uiSupport.WriteDebugLine($"Sending packet with {messageSize} bytes"); + + // For testing calculate the crc including the sequence number + //_packetCrc32 = NuttxCrc.Crc32part(messageBytes, messageSize, 0, _packetCrc32); + try + { + // The encoded size using COBS is just a bit more than the original size adding 1 byte + // every 254 bytes plus 1 and need room for beginning and ending delimiters. + var l = Protocol.HCOM_PROTOCOL_ENCODED_MAX_SIZE + (Protocol.HCOM_PROTOCOL_ENCODED_MAX_SIZE / 254) + 8; + encodedBytes = new byte[l + 2]; + + // Skip over first byte so it can be a start delimiter + encodedToSend = CobsTools.CobsEncoding(messageBytes, 0, length, ref encodedBytes, 1); + + // DEBUG TESTING + if (encodedToSend == -1) + { + _logger?.LogError($"Error - encodedToSend == -1"); + return; + } + + if (_port == null) + { + _logger?.LogError($"Error - SerialPort == null"); + throw new Exception("Port is null"); + } + } + catch (Exception except) + { + string msg = string.Format("Send setup Exception: {0}", except); + _logger?.LogError(msg); + throw; + } + + // Add delimiters to packet boundaries + try + { + encodedBytes[0] = 0; // Start delimiter + encodedToSend++; + encodedBytes[encodedToSend] = 0; // End delimiter + encodedToSend++; + } + catch (Exception encodedBytesEx) + { + // This should drop the connection and retry + Debug.WriteLine($"Adding encodeBytes delimiter threw: {encodedBytesEx}"); + Thread.Sleep(500); // Place for break point + throw; + } + + try + { + // Send the data to Meadow + // DO NOT USE _port.BaseStream. It disables port timeouts! + _port.Write(encodedBytes, 0, encodedToSend); + } + catch (InvalidOperationException ioe) // Port not opened + { + string msg = string.Format("Write but port not opened. Exception: {0}", ioe); + _logger?.LogError(msg); + throw; + } + catch (ArgumentOutOfRangeException aore) // offset or count don't match buffer + { + string msg = string.Format("Write buffer, offset and count don't line up. Exception: {0}", aore); + _logger?.LogError(msg); + throw; + } + catch (ArgumentException ae) // offset plus count > buffer length + { + string msg = string.Format($"Write offset plus count > buffer length. Exception: {0}", ae); + _logger?.LogError(msg); + throw; + } + catch (TimeoutException te) // Took too long to send + { + string msg = string.Format("Write took too long to send. Exception: {0}", te); + _logger?.LogError(msg); + throw; + } + } + catch (Exception except) + { + // DID YOU RESTART MEADOW? + // This should drop the connection and retry + _logger?.LogError($"EncodeAndSendPacket threw: {except}"); + throw; + } + } + + private class SerialMessage + { + private readonly IList> _segments; + + public SerialMessage(Memory segment) + { + _segments = new List> + { + segment + }; + } + + public void AddSegment(Memory segment) + { + _segments.Add(segment); + } + + public byte[] ToArray() + { + using var ms = new MemoryStream(); + foreach (var segment in _segments) + { + // We could just call ToArray on the `Memory` but that will result in an uncontrolled allocation. + var tmp = ArrayPool.Shared.Rent(segment.Length); + segment.CopyTo(tmp); + ms.Write(tmp, 0, segment.Length); + ArrayPool.Shared.Return(tmp); + } + return ms.ToArray(); + } + } + + private bool DecodeAndProcessPacket(Memory packetBuffer, CancellationToken cancellationToken) + { + var decodedBuffer = ArrayPool.Shared.Rent(8192); + var packetLength = packetBuffer.Length; + // It's possible that we may find a series of 0x00 values in the buffer. + // This is because when the sender is blocked (because this code isn't + // running) it will attempt to send a single 0x00 before the full message. + // This allows it to test for a connection. When the connection is + // unblocked this 0x00 is sent and gets put into the buffer along with + // any others that were queued along the usb serial pipe line. + if (packetLength == 1) + { + //_logger.LogTrace("Throwing out 0x00 from buffer"); + return false; + } + + var decodedSize = CobsTools.CobsDecoding(packetBuffer.ToArray(), packetLength, ref decodedBuffer); + + ArrayPool.Shared.Return(decodedBuffer); + return true; + } + + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + _port.Dispose(); + } + + _isDisposed = true; + } + } + + // ---------------------------------------------- + // ---------------------------------------------- + // ---------------------------------------------- + + private Exception? _lastException; + private bool? _textListComplete; + private DeviceInfo? _deviceInfo; + private RequestType? _lastRequestConcluded = null; + private List StdOut { get; } = new List(); + private List StdErr { get; } = new List(); + private List InfoMessages { get; } = new List(); + + private const string MonoStateToken = "Mono is"; + private const string RuntimeStateToken = "Runtime is"; + private const string MonoIsEnabledToken = "Mono is enabled"; + private const string RuntimeIsEnabledToken = "Runtime is enabled"; + private const string RtcRetrievalToken = "UTC time:"; + + public int CommandTimeoutSeconds { get; set; } = 30; + + private async Task WaitForFileReadCompleted(CancellationToken? cancellationToken) + { + var timeout = CommandTimeoutSeconds * 2; + + var completed = false; + + void LocalFRCHandler(object s, string e) + { + completed = true; + } + void LocalFBRHandler(object s, int e) + { + timeout = CommandTimeoutSeconds * 2; + } + + FileBytesReceived += LocalFBRHandler; + FileReadCompleted += LocalFRCHandler; + + try + { + while (timeout-- > 0) + { + if (cancellationToken?.IsCancellationRequested ?? false) return false; + if (_lastException != null) return false; + + if (timeout <= 0) throw new TimeoutException(); + + if (completed) return true; + + await Task.Delay(500); + } + } + finally + { + // clean up local events + FileBytesReceived -= LocalFBRHandler; + FileReadCompleted -= LocalFRCHandler; + } + + return true; + } + + private async Task WaitForResult(Func checkAction, CancellationToken? cancellationToken) + { + var timeout = CommandTimeoutSeconds * 2; + + while (timeout-- > 0) + { + if (cancellationToken?.IsCancellationRequested ?? false) return false; + if (_lastException != null) return false; + + if (timeout <= 0) throw new TimeoutException(); + + if (checkAction()) + { + break; + } + + await Task.Delay(500); + } + + return true; + } + + private async Task WaitForResponseText(string textToAwait, CancellationToken? cancellationToken = null) + { + return await WaitForResult(() => + { + if (InfoMessages.Count > 0) + { + var m = InfoMessages.FirstOrDefault(i => i.Contains(textToAwait)); + if (m != null) + { + return true; + } + } + + return false; + }, cancellationToken); + } + + private async Task WaitForConcluded(RequestType? requestType = null, CancellationToken? cancellationToken = null) + { + return await WaitForResult(() => + { + if (_lastRequestConcluded != null) + { + if (requestType == null || requestType == _lastRequestConcluded) + { + return true; + } + } + + return false; + }, cancellationToken); + } + + public override async Task SetRtcTime(DateTimeOffset dateTime, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.Time = dateTime; + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + var success = await WaitForResult(() => + { + if (_lastRequestConcluded != null && _lastRequestConcluded == RequestType.HCOM_MDOW_REQUEST_RTC_SET_TIME_CMD) + { + return true; + } + + return false; + }, cancellationToken); + } + + public override async Task GetRtcTime(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + InfoMessages.Clear(); + + EnqueueRequest(command); + + DateTimeOffset? now = null; + + var success = await WaitForResult(() => + { + if (InfoMessages.Count > 0) + { + var m = InfoMessages.FirstOrDefault(i => i.Contains(RtcRetrievalToken)); + if (m != null) + { + var timeString = m.Substring(m.IndexOf(RtcRetrievalToken) + RtcRetrievalToken.Length); + now = DateTimeOffset.Parse(timeString); + return true; + } + } + + return false; + }, cancellationToken); + + return now; + } + + public override async Task IsRuntimeEnabled(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + InfoMessages.Clear(); + + EnqueueRequest(command); + + // wait for an information response + var timeout = CommandTimeoutSeconds * 2; + while (timeout-- > 0) + { + if (cancellationToken?.IsCancellationRequested ?? false) + { + return false; + } + if (timeout <= 0) + { + throw new TimeoutException(); + } + + if (InfoMessages.Count > 0) + { + var m = InfoMessages.FirstOrDefault(i => + i.Contains(RuntimeStateToken) || + i.Contains(MonoStateToken)); + if (m != null) + { + return (m == RuntimeIsEnabledToken) || (m == MonoIsEnabledToken); + } + } + + await Task.Delay(500); + } + return false; + } + + public override async Task RuntimeEnable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + InfoMessages.Clear(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task RuntimeDisable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + InfoMessages.Clear(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task NshEnable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(1); + + InfoMessages.Clear(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task NshDisable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(0); + + InfoMessages.Clear(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task TraceEnable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task TraceDisable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task UartTraceEnable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task UartProfilerEnable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task UartProfilerDisable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task UartTraceDisable(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task SetTraceLevel(int level, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.UserData = (uint)level; + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task SetDeveloperParameter(ushort parameter, uint value, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.ExtraData = parameter; + command.UserData = value; + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + } + + public override async Task ResetDevice(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + EnqueueRequest(command); + + // we have to give time for the device to actually reset + await Task.Delay(1500); + + await WaitForMeadowAttach(cancellationToken); + } + + public override async Task GetDeviceInfo(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _deviceInfo = null; + + _lastException = null; + EnqueueRequest(command); + + if (!await WaitForResult( + () => _deviceInfo != null, + cancellationToken)) + { + return null; + } + + return _deviceInfo; + } + + public override async Task GetFileList(string folder, bool includeCrcs, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.IncludeCrcs = includeCrcs; + + command.Path = folder; + + EnqueueRequest(command); + + if (!await WaitForResult( + () => _textListComplete ?? false, + cancellationToken)) + { + _textListComplete = null; + return null; + } + + var list = new List(); + + foreach (var candidate in _textList) + { + var fi = MeadowFileInfo.Parse(candidate, folder); + if (fi != null) + { + list.Add(fi); + } + } + + _textListComplete = null; + return list.ToArray(); + } + + public override async Task WriteFile( + string localFileName, + string? meadowFileName = null, + CancellationToken? cancellationToken = null) + { + return await WriteFile(localFileName, meadowFileName, + RequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER, + RequestType.HCOM_MDOW_REQUEST_END_FILE_TRANSFER, + 0, + cancellationToken); + } + + public override async Task WriteRuntime( + string localFileName, + CancellationToken? cancellationToken = null) + { + var commandTimeout = CommandTimeoutSeconds; + + + CommandTimeoutSeconds = 120; + _lastRequestConcluded = null; + + try + { + InfoMessages.Clear(); + + _lastRequestConcluded = null; + + var status = await WriteFile(localFileName, "Meadow.OS.Runtime.bin", + RequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME, + RequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_FILE_END, + 0, + cancellationToken); + + + if (status) + { + await WaitForConcluded(null, cancellationToken); + } + + return status; + } + finally + { + CommandTimeoutSeconds = commandTimeout; + } + } + + public override async Task WriteCoprocessorFile( + string localFileName, + int destinationAddress, + CancellationToken? cancellationToken = null) + { + // make the timeouts much bigger, as the ESP flash takes a lot of time + var readTimeout = _port.ReadTimeout; + var commandTimeout = CommandTimeoutSeconds; + _lastRequestConcluded = null; + + _port.ReadTimeout = 60000; + CommandTimeoutSeconds = 180; + InfoMessages.Clear(); + + try + { + RaiseConnectionMessage($"Transferring {Path.GetFileName(localFileName)} to coprocessor..."); + + // push the file to the device + if (!await WriteFile(localFileName, null, + RequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER, + RequestType.HCOM_MDOW_REQUEST_END_ESP_FILE_TRANSFER, + destinationAddress, + cancellationToken)) + { + return false; + } + + + _lastRequestConcluded = null; + + // now wait for the STM32 to finish writing to the ESP32 + await WaitForConcluded(null, cancellationToken); + return true; + } + finally + { + _port.ReadTimeout = readTimeout; + CommandTimeoutSeconds = commandTimeout; + } + } + + private async Task WriteFile( + string localFileName, + string? meadowFileName, + RequestType initialRequestType, + RequestType endRequestType, + int writeAddress = 0, + CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + var fileBytes = File.ReadAllBytes(localFileName); + + var fileHash = Encoding.ASCII.GetBytes("12345678901234567890123456789012"); // must be 32 bytes + if (writeAddress != 0) + { + // calculate the MD5 hash of the file - we have to send it as a UTF8 string, not as bytes. + using var md5 = MD5.Create(); + var hashBytes = md5.ComputeHash(fileBytes); + var hashString = BitConverter.ToString(hashBytes) + .Replace("-", "") + .ToLowerInvariant(); + fileHash = Encoding.UTF8.GetBytes(hashString); + } + var fileCrc = NuttxCrc.Crc32part(fileBytes, (uint)fileBytes.Length, 0); + + command.SetParameters( + localFileName, + meadowFileName ?? Path.GetFileName(localFileName), + fileCrc, + writeAddress, + fileHash, + initialRequestType); + + var accepted = false; + Exception? ex = null; + var needsRetry = false; + + void OnFileWriteAccepted(object? sender, EventArgs a) + { + accepted = true; + } + void OnFileError(object? sender, Exception exception) + { + ex = exception; + } + void OnFileRetry(object? sender, EventArgs e) + { + needsRetry = true; + } + + FileWriteAccepted += OnFileWriteAccepted; + FileException += OnFileError; + FileWriteFailed += OnFileRetry; + + EnqueueRequest(command); + + // this will wait for a "file write accepted" from the target + if (!await WaitForResult( + () => + { + if (ex != null) throw ex; + return accepted; + }, + cancellationToken)) + { + return false; + } + + // now send the file data + // The maximum data bytes is max packet size - 2 bytes for the sequence number + byte[] packet = new byte[Protocol.HCOM_PROTOCOL_PACKET_MAX_SIZE - 2]; + ushort sequenceNumber = 0; + + var progress = 0; + var expected = fileBytes.Length; + + var fileName = Path.GetFileName(localFileName); + + base.RaiseFileWriteProgress(fileName, progress, expected); + + var oldTimeout = _port.ReadTimeout; + _port.ReadTimeout = 60000; + + while (true && !needsRetry) + { + if (cancellationToken.HasValue && cancellationToken.Value.IsCancellationRequested) + { + return false; + } + + sequenceNumber++; + + Array.Copy(BitConverter.GetBytes(sequenceNumber), packet, 2); + + var toRead = fileBytes.Length - progress; + if (toRead > packet.Length - 2) + { + toRead = packet.Length - 2; + } + Array.Copy(fileBytes, progress, packet, 2, toRead); + try + { + EncodeAndSendPacket(packet, toRead + 2, cancellationToken); + } + catch (Exception) + { + break; + } + + progress += toRead; + base.RaiseFileWriteProgress(fileName, progress, expected); + if (progress >= fileBytes.Length) break; + } + + if (!needsRetry) + { + _port.ReadTimeout = oldTimeout; + + base.RaiseFileWriteProgress(fileName, expected, expected); + + // finish with an "end" message - not enqued because this is all a serial operation + var request = RequestBuilder.Build(); + request.SetRequestType(endRequestType); + var p = request.Serialize(); + EncodeAndSendPacket(p, cancellationToken); + } + + FileWriteAccepted -= OnFileWriteAccepted; + FileException -= OnFileError; + FileWriteFailed -= OnFileRetry; + + return !needsRetry; + } + + public override async Task ReadFile(string meadowFileName, string? localFileName = null, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.MeadowFileName = meadowFileName; + command.LocalFileName = localFileName; + + var completed = false; + Exception? ex = null; + + void OnFileReadCompleted(object? sender, string filename) + { + completed = true; + } + void OnFileError(object? sender, Exception exception) + { + ex = exception; + } + + try + { + FileReadCompleted += OnFileReadCompleted; + FileException += OnFileError; + ConnectionError += OnFileError; + + EnqueueRequest(command); + + if (!await WaitForFileReadCompleted(cancellationToken)) + { + return false; + } + + return ex == null; + } + finally + { + FileReadCompleted -= OnFileReadCompleted; + FileException -= OnFileError; + } + } + + public override async Task ReadFileString(string fileName, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.MeadowFileName = fileName; + + string? contents = null; + + void OnFileDataReceived(object? sender, string data) + { + contents = data; + } + + FileTextReceived += OnFileDataReceived; + + _lastRequestConcluded = null; + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + + return contents; + } + + public override async Task DeleteFile(string meadowFileName, CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + command.MeadowFileName = meadowFileName; + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + var result = await WaitForConcluded(null, cancellationToken); + return result; + } + + public override async Task EraseFlash(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + _lastRequestConcluded = null; + + var lastTimeout = CommandTimeoutSeconds; + + CommandTimeoutSeconds = 5 * 60; + + EnqueueRequest(command); + + await WaitForConcluded(null, cancellationToken); + + CommandTimeoutSeconds = lastTimeout; + } + + public override async Task GetPublicKey(CancellationToken? cancellationToken = null) + { + var command = RequestBuilder.Build(); + + string contents = string.Empty; + + void OnFileDataReceived(object? sender, string data) + { + contents = data; + } + + FileTextReceived += OnFileDataReceived; + + var lastTimeout = CommandTimeoutSeconds; + + CommandTimeoutSeconds = 5 * 60; + + _lastRequestConcluded = null; + EnqueueRequest(command); + + if (!await WaitForResult( + () => + { + return contents != string.Empty; + }, + cancellationToken)) + { + CommandTimeoutSeconds = lastTimeout; + return string.Empty; + } + + CommandTimeoutSeconds = lastTimeout; + + return contents; + } + + public override async Task StartDebuggingSession(int port, ILogger? logger, CancellationToken cancellationToken) + { + if (Device == null) + { + throw new DeviceNotFoundException(); + } + + var debuggingServer = new DebuggingServer(this, port, logger); + + logger?.LogDebug("Tell the Debugging Server to Start Listening"); + await debuggingServer.StartListening(cancellationToken); + + logger?.LogDebug($"Start Debugging on port: {port}"); + await Device.StartDebugging(port, logger, cancellationToken); + + return debuggingServer; + } + + public override async Task StartDebugging(int port, ILogger? logger, CancellationToken? cancellationToken) + { + var command = RequestBuilder.Build(); + + if (command != null) + { + InfoMessages.Clear(); + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + await WaitForMeadowAttach(cancellationToken); + } + else + { + new Exception($"{typeof(StartDebuggingRequest)} command failed to build"); + } + } + + public override Task SendDebuggerData(byte[] debuggerData, uint userData, CancellationToken? cancellationToken) + { + var command = RequestBuilder.Build(userData); + command.DebuggerData = debuggerData; + + _lastRequestConcluded = null; + + EnqueueRequest(command); + + return Task.CompletedTask; + } } \ No newline at end of file diff --git a/Source/v2/Meadow.HCom/Connections/SimulatorConnection.cs b/Source/Meadow.Hcom/Connections/SimulatorConnection.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/Connections/SimulatorConnection.cs rename to Source/Meadow.Hcom/Connections/SimulatorConnection.cs diff --git a/Source/v2/Meadow.HCom/Connections/TcpConnection.cs b/Source/Meadow.Hcom/Connections/TcpConnection.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/Connections/TcpConnection.cs rename to Source/Meadow.Hcom/Connections/TcpConnection.cs diff --git a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs b/Source/Meadow.Hcom/Debugging/DebuggingServer.ActiveClient.cs similarity index 100% rename from Source/v2/Meadow.HCom/Debugging/DebuggingServer.ActiveClient.cs rename to Source/Meadow.Hcom/Debugging/DebuggingServer.ActiveClient.cs diff --git a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs b/Source/Meadow.Hcom/Debugging/DebuggingServer.cs similarity index 97% rename from Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs rename to Source/Meadow.Hcom/Debugging/DebuggingServer.cs index 62418990..a5e9e20b 100644 --- a/Source/v2/Meadow.HCom/Debugging/DebuggingServer.cs +++ b/Source/Meadow.Hcom/Debugging/DebuggingServer.cs @@ -1,110 +1,110 @@ -using System.Net; -using System.Net.Sockets; - -namespace Meadow.Hcom; - -// This TCP server directly interacts with Visual Studio debugging. -// What it receives from Visual Studio it forwards to Meadow. -// What it receives from Meadow it forwards to Visual Studio. -public partial class DebuggingServer : IDisposable -{ - // VS 2019 - 4024 - // VS 2017 - 4022 - // VS 2015 - 4020 - private readonly object _lck = new(); - private CancellationTokenSource? _cancellationTokenSource; - private readonly ILogger? _logger; - private readonly IMeadowConnection _connection; - private ActiveClient? _activeClient; - private readonly TcpListener _listener; - private readonly Task? _listenerTask; - public bool Disposed; - - // Constructor - /// - /// Create a new DebuggingServer for proxying debug data between VS and Meadow - /// - /// The meadow connection - /// The to listen for incoming debugger connections - /// The to logging state information - public DebuggingServer(IMeadowConnection connection, int port, ILogger? logger) - { - _logger = logger; - _connection = connection; - - var endPoint = new IPEndPoint(IPAddress.Loopback, port); - - _listener = new TcpListener(endPoint); - } - - /// - /// Start the debugging server - /// - /// A that is linked internally to the running task - /// A representing the startup operation - public async Task StartListening(CancellationToken cancellationToken) - { - _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - - _listener.Start(); - _logger?.LogInformation($"Listening for Visual Studio to connect"); - - // This call will wait for the client to connect, before continuing. - _activeClient = await CreateActiveClient(_listener); - } - - /// - /// Stop the - /// - /// A representing the shutdown operation - public async Task StopListening() - { - _listener?.Stop(); - - _cancellationTokenSource?.Cancel(false); - - if (_listenerTask != null) - { - await _listenerTask; - } - } - - private async Task CreateActiveClient(TcpListener listener) - { - try - { - if (_activeClient != null) - { - _logger?.LogDebug("Closing active client"); - _activeClient?.Dispose(); - _activeClient = null; - } - - - var client = new ActiveClient(_connection, _logger, _cancellationTokenSource?.Token); - await client.Start(listener); - _logger?.LogInformation("Debugger has connected" + Environment.NewLine); - return client; - } - catch (Exception ex) - { - _logger?.LogError(ex, "An error occurred while connecting to Visual Studio"); - } - return null; - } - - public void Dispose() - { - lock (_lck) - { - if (Disposed) - { - return; - } - _cancellationTokenSource?.Cancel(false); - _activeClient?.Dispose(); - _listenerTask?.Dispose(); - Disposed = true; - } - } +using System.Net; +using System.Net.Sockets; + +namespace Meadow.Hcom; + +// This TCP server directly interacts with Visual Studio debugging. +// What it receives from Visual Studio it forwards to Meadow. +// What it receives from Meadow it forwards to Visual Studio. +public partial class DebuggingServer : IDisposable +{ + // VS 2019 - 4024 + // VS 2017 - 4022 + // VS 2015 - 4020 + private readonly object _lck = new(); + private CancellationTokenSource? _cancellationTokenSource; + private readonly ILogger? _logger; + private readonly IMeadowConnection _connection; + private ActiveClient? _activeClient; + private readonly TcpListener _listener; + private readonly Task? _listenerTask; + public bool Disposed; + + // Constructor + /// + /// Create a new DebuggingServer for proxying debug data between VS and Meadow + /// + /// The meadow connection + /// The to listen for incoming debugger connections + /// The to logging state information + public DebuggingServer(IMeadowConnection connection, int port, ILogger? logger) + { + _logger = logger; + _connection = connection; + + var endPoint = new IPEndPoint(IPAddress.Loopback, port); + + _listener = new TcpListener(endPoint); + } + + /// + /// Start the debugging server + /// + /// A that is linked internally to the running task + /// A representing the startup operation + public async Task StartListening(CancellationToken cancellationToken) + { + _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + + _listener.Start(); + _logger?.LogInformation($"Listening for Visual Studio to connect"); + + // This call will wait for the client to connect, before continuing. + _activeClient = await CreateActiveClient(_listener); + } + + /// + /// Stop the + /// + /// A representing the shutdown operation + public async Task StopListening() + { + _listener?.Stop(); + + _cancellationTokenSource?.Cancel(false); + + if (_listenerTask != null) + { + await _listenerTask; + } + } + + private async Task CreateActiveClient(TcpListener listener) + { + try + { + if (_activeClient != null) + { + _logger?.LogDebug("Closing active client"); + _activeClient?.Dispose(); + _activeClient = null; + } + + + var client = new ActiveClient(_connection, _logger, _cancellationTokenSource?.Token); + await client.Start(listener); + _logger?.LogInformation("Debugger has connected" + Environment.NewLine); + return client; + } + catch (Exception ex) + { + _logger?.LogError(ex, "An error occurred while connecting to Visual Studio"); + } + return null; + } + + public void Dispose() + { + lock (_lck) + { + if (Disposed) + { + return; + } + _cancellationTokenSource?.Cancel(false); + _activeClient?.Dispose(); + _listenerTask?.Dispose(); + Disposed = true; + } + } } \ No newline at end of file diff --git a/Source/v2/Meadow.HCom/DeviceInfo.cs b/Source/Meadow.Hcom/DeviceInfo.cs similarity index 100% rename from Source/v2/Meadow.HCom/DeviceInfo.cs rename to Source/Meadow.Hcom/DeviceInfo.cs diff --git a/Source/v2/Meadow.HCom/DeviceNotFoundException.cs b/Source/Meadow.Hcom/DeviceNotFoundException.cs similarity index 100% rename from Source/v2/Meadow.HCom/DeviceNotFoundException.cs rename to Source/Meadow.Hcom/DeviceNotFoundException.cs diff --git a/Source/v2/Meadow.HCom/ExtensionMethods.cs b/Source/Meadow.Hcom/ExtensionMethods.cs similarity index 100% rename from Source/v2/Meadow.HCom/ExtensionMethods.cs rename to Source/Meadow.Hcom/ExtensionMethods.cs diff --git a/Source/v2/Meadow.HCom/Firmware/DownloadFileStream.cs b/Source/Meadow.Hcom/Firmware/DownloadFileStream.cs similarity index 100% rename from Source/v2/Meadow.HCom/Firmware/DownloadFileStream.cs rename to Source/Meadow.Hcom/Firmware/DownloadFileStream.cs diff --git a/Source/v2/Meadow.HCom/Firmware/ReleaseMetadata.cs b/Source/Meadow.Hcom/Firmware/ReleaseMetadata.cs similarity index 100% rename from Source/v2/Meadow.HCom/Firmware/ReleaseMetadata.cs rename to Source/Meadow.Hcom/Firmware/ReleaseMetadata.cs diff --git a/Source/v2/Meadow.HCom/HttpResponses/DeviceInfoHttpResponse.cs b/Source/Meadow.Hcom/HttpResponses/DeviceInfoHttpResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/HttpResponses/DeviceInfoHttpResponse.cs rename to Source/Meadow.Hcom/HttpResponses/DeviceInfoHttpResponse.cs diff --git a/Source/v2/Meadow.HCom/IConnectionListener.cs b/Source/Meadow.Hcom/IConnectionListener.cs similarity index 100% rename from Source/v2/Meadow.HCom/IConnectionListener.cs rename to Source/Meadow.Hcom/IConnectionListener.cs diff --git a/Source/v2/Meadow.HCom/IMeadowConnection.cs b/Source/Meadow.Hcom/IMeadowConnection.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/IMeadowConnection.cs rename to Source/Meadow.Hcom/IMeadowConnection.cs diff --git a/Source/v2/Meadow.HCom/IMeadowDevice.cs b/Source/Meadow.Hcom/IMeadowDevice.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/IMeadowDevice.cs rename to Source/Meadow.Hcom/IMeadowDevice.cs diff --git a/Source/v2/Meadow.HCom/Meadow.HCom.Rider.csproj b/Source/Meadow.Hcom/Meadow.HCom.Rider.csproj similarity index 100% rename from Source/v2/Meadow.HCom/Meadow.HCom.Rider.csproj rename to Source/Meadow.Hcom/Meadow.HCom.Rider.csproj diff --git a/Source/v2/Meadow.HCom/Meadow.HCom.csproj b/Source/Meadow.Hcom/Meadow.HCom.csproj similarity index 85% rename from Source/v2/Meadow.HCom/Meadow.HCom.csproj rename to Source/Meadow.Hcom/Meadow.HCom.csproj index 46372e15..2de94942 100644 --- a/Source/v2/Meadow.HCom/Meadow.HCom.csproj +++ b/Source/Meadow.Hcom/Meadow.HCom.csproj @@ -12,7 +12,7 @@ - + diff --git a/Source/v2/Meadow.HCom/Meadow.Hcom.sln b/Source/Meadow.Hcom/Meadow.Hcom.sln similarity index 100% rename from Source/v2/Meadow.HCom/Meadow.Hcom.sln rename to Source/Meadow.Hcom/Meadow.Hcom.sln diff --git a/Source/v2/Meadow.HCom/MeadowDevice.cs b/Source/Meadow.Hcom/MeadowDevice.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/MeadowDevice.cs rename to Source/Meadow.Hcom/MeadowDevice.cs diff --git a/Source/v2/Meadow.HCom/MeadowFileInfo.cs b/Source/Meadow.Hcom/MeadowFileInfo.cs similarity index 100% rename from Source/v2/Meadow.HCom/MeadowFileInfo.cs rename to Source/Meadow.Hcom/MeadowFileInfo.cs diff --git a/Source/v2/Meadow.HCom/Protocol.cs b/Source/Meadow.Hcom/Protocol.cs similarity index 100% rename from Source/v2/Meadow.HCom/Protocol.cs rename to Source/Meadow.Hcom/Protocol.cs diff --git a/Source/v2/Meadow.HCom/ProtocolType.cs b/Source/Meadow.Hcom/ProtocolType.cs similarity index 100% rename from Source/v2/Meadow.HCom/ProtocolType.cs rename to Source/Meadow.Hcom/ProtocolType.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/DebuggerDataRequest.cs b/Source/Meadow.Hcom/SerialRequests/DebuggerDataRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/DebuggerDataRequest.cs rename to Source/Meadow.Hcom/SerialRequests/DebuggerDataRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/DeveloperRequest.cs b/Source/Meadow.Hcom/SerialRequests/DeveloperRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/DeveloperRequest.cs rename to Source/Meadow.Hcom/SerialRequests/DeveloperRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/EndFileWriteRequest.cs b/Source/Meadow.Hcom/SerialRequests/EndFileWriteRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/EndFileWriteRequest.cs rename to Source/Meadow.Hcom/SerialRequests/EndFileWriteRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/FileDeleteRequest.cs b/Source/Meadow.Hcom/SerialRequests/FileDeleteRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/FileDeleteRequest.cs rename to Source/Meadow.Hcom/SerialRequests/FileDeleteRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/FileInitialBytesRequest.cs b/Source/Meadow.Hcom/SerialRequests/FileInitialBytesRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/FileInitialBytesRequest.cs rename to Source/Meadow.Hcom/SerialRequests/FileInitialBytesRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/FileReadDataRequest.cs b/Source/Meadow.Hcom/SerialRequests/FileReadDataRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/FileReadDataRequest.cs rename to Source/Meadow.Hcom/SerialRequests/FileReadDataRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/FlashEraseRequest.cs b/Source/Meadow.Hcom/SerialRequests/FlashEraseRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/FlashEraseRequest.cs rename to Source/Meadow.Hcom/SerialRequests/FlashEraseRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/GetDeviceInfoRequest.cs b/Source/Meadow.Hcom/SerialRequests/GetDeviceInfoRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/GetDeviceInfoRequest.cs rename to Source/Meadow.Hcom/SerialRequests/GetDeviceInfoRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/GetFileListRequest.cs b/Source/Meadow.Hcom/SerialRequests/GetFileListRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/GetFileListRequest.cs rename to Source/Meadow.Hcom/SerialRequests/GetFileListRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/GetPublicKeyRequest.cs b/Source/Meadow.Hcom/SerialRequests/GetPublicKeyRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/GetPublicKeyRequest.cs rename to Source/Meadow.Hcom/SerialRequests/GetPublicKeyRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/GetRtcTimeRequest.cs b/Source/Meadow.Hcom/SerialRequests/GetRtcTimeRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/GetRtcTimeRequest.cs rename to Source/Meadow.Hcom/SerialRequests/GetRtcTimeRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/GetRuntimeStateRequest.cs b/Source/Meadow.Hcom/SerialRequests/GetRuntimeStateRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/GetRuntimeStateRequest.cs rename to Source/Meadow.Hcom/SerialRequests/GetRuntimeStateRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/InitFileReadRequest.cs b/Source/Meadow.Hcom/SerialRequests/InitFileReadRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/InitFileReadRequest.cs rename to Source/Meadow.Hcom/SerialRequests/InitFileReadRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/InitFileWriteRequest.cs b/Source/Meadow.Hcom/SerialRequests/InitFileWriteRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/InitFileWriteRequest.cs rename to Source/Meadow.Hcom/SerialRequests/InitFileWriteRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/NshEnableDisableRequest.cs b/Source/Meadow.Hcom/SerialRequests/NshEnableDisableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/NshEnableDisableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/NshEnableDisableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/Request.cs b/Source/Meadow.Hcom/SerialRequests/Request.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/Request.cs rename to Source/Meadow.Hcom/SerialRequests/Request.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/RequestBuilder.cs b/Source/Meadow.Hcom/SerialRequests/RequestBuilder.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/RequestBuilder.cs rename to Source/Meadow.Hcom/SerialRequests/RequestBuilder.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/RequestType.cs b/Source/Meadow.Hcom/SerialRequests/RequestType.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/RequestType.cs rename to Source/Meadow.Hcom/SerialRequests/RequestType.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/ResetDeviceRequest.cs b/Source/Meadow.Hcom/SerialRequests/ResetDeviceRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/ResetDeviceRequest.cs rename to Source/Meadow.Hcom/SerialRequests/ResetDeviceRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/ResetRequest.cs b/Source/Meadow.Hcom/SerialRequests/ResetRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/ResetRequest.cs rename to Source/Meadow.Hcom/SerialRequests/ResetRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/RuntimeDisableRequest.cs b/Source/Meadow.Hcom/SerialRequests/RuntimeDisableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/RuntimeDisableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/RuntimeDisableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/RuntimeEnableRequest.cs b/Source/Meadow.Hcom/SerialRequests/RuntimeEnableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/RuntimeEnableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/RuntimeEnableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/SetRtcTimeRequest.cs b/Source/Meadow.Hcom/SerialRequests/SetRtcTimeRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/SetRtcTimeRequest.cs rename to Source/Meadow.Hcom/SerialRequests/SetRtcTimeRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/StartDebuggingRequest.cs b/Source/Meadow.Hcom/SerialRequests/StartDebuggingRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/StartDebuggingRequest.cs rename to Source/Meadow.Hcom/SerialRequests/StartDebuggingRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/StartFileDataRequest.cs b/Source/Meadow.Hcom/SerialRequests/StartFileDataRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/StartFileDataRequest.cs rename to Source/Meadow.Hcom/SerialRequests/StartFileDataRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/TraceDisableRequest.cs b/Source/Meadow.Hcom/SerialRequests/TraceDisableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/TraceDisableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/TraceDisableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/TraceEnableRequest.cs b/Source/Meadow.Hcom/SerialRequests/TraceEnableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/TraceEnableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/TraceEnableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/TraceLevelRequest.cs b/Source/Meadow.Hcom/SerialRequests/TraceLevelRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/TraceLevelRequest.cs rename to Source/Meadow.Hcom/SerialRequests/TraceLevelRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/UartProfilerDisableRequest.cs b/Source/Meadow.Hcom/SerialRequests/UartProfilerDisableRequest.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/UartProfilerDisableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/UartProfilerDisableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/UartProfilerEnableRequest.cs b/Source/Meadow.Hcom/SerialRequests/UartProfilerEnableRequest.cs old mode 100755 new mode 100644 similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/UartProfilerEnableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/UartProfilerEnableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/UartTraceDisableRequest.cs b/Source/Meadow.Hcom/SerialRequests/UartTraceDisableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/UartTraceDisableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/UartTraceDisableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialRequests/UartTraceEnableRequest.cs b/Source/Meadow.Hcom/SerialRequests/UartTraceEnableRequest.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialRequests/UartTraceEnableRequest.cs rename to Source/Meadow.Hcom/SerialRequests/UartTraceEnableRequest.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/DebuggingDataResponse.cs b/Source/Meadow.Hcom/SerialResponses/DebuggingDataResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/DebuggingDataResponse.cs rename to Source/Meadow.Hcom/SerialResponses/DebuggingDataResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/DeviceInfoSerialResponse.cs b/Source/Meadow.Hcom/SerialResponses/DeviceInfoSerialResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/DeviceInfoSerialResponse.cs rename to Source/Meadow.Hcom/SerialResponses/DeviceInfoSerialResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/FileDownloadFailedResponse.cs b/Source/Meadow.Hcom/SerialResponses/FileDownloadFailedResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/FileDownloadFailedResponse.cs rename to Source/Meadow.Hcom/SerialResponses/FileDownloadFailedResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/FileInitialBytesSerialResponse.cs b/Source/Meadow.Hcom/SerialResponses/FileInitialBytesSerialResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/FileInitialBytesSerialResponse.cs rename to Source/Meadow.Hcom/SerialResponses/FileInitialBytesSerialResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/FileReadInitFailedResponse.cs b/Source/Meadow.Hcom/SerialResponses/FileReadInitFailedResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/FileReadInitFailedResponse.cs rename to Source/Meadow.Hcom/SerialResponses/FileReadInitFailedResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/FileReadInitOkResponse.cs b/Source/Meadow.Hcom/SerialResponses/FileReadInitOkResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/FileReadInitOkResponse.cs rename to Source/Meadow.Hcom/SerialResponses/FileReadInitOkResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/FileWriteInitFailedSerialResponse.cs b/Source/Meadow.Hcom/SerialResponses/FileWriteInitFailedSerialResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/FileWriteInitFailedSerialResponse.cs rename to Source/Meadow.Hcom/SerialResponses/FileWriteInitFailedSerialResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/FileWriteInitOkSerialResponse.cs b/Source/Meadow.Hcom/SerialResponses/FileWriteInitOkSerialResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/FileWriteInitOkSerialResponse.cs rename to Source/Meadow.Hcom/SerialResponses/FileWriteInitOkSerialResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/ReconnectRequiredResponse.cs b/Source/Meadow.Hcom/SerialResponses/ReconnectRequiredResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/ReconnectRequiredResponse.cs rename to Source/Meadow.Hcom/SerialResponses/ReconnectRequiredResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/RequestErrorTextResponse.cs b/Source/Meadow.Hcom/SerialResponses/RequestErrorTextResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/RequestErrorTextResponse.cs rename to Source/Meadow.Hcom/SerialResponses/RequestErrorTextResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/ResponseType.cs b/Source/Meadow.Hcom/SerialResponses/ResponseType.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/ResponseType.cs rename to Source/Meadow.Hcom/SerialResponses/ResponseType.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/SerialResponse.cs b/Source/Meadow.Hcom/SerialResponses/SerialResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/SerialResponse.cs rename to Source/Meadow.Hcom/SerialResponses/SerialResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextAcceptedResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextAcceptedResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextAcceptedResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextAcceptedResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextConcludedResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextConcludedResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextConcludedResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextConcludedResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextCrcMemberResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextCrcMemberResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextCrcMemberResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextCrcMemberResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextInformationResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextInformationResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextInformationResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextInformationResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextListHeaderResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextListHeaderResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextListHeaderResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextListHeaderResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextListMemberResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextListMemberResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextListMemberResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextListMemberResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextRequestRejectedResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextRequestRejectedResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextRequestRejectedResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextRequestRejectedResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextRequestResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextRequestResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextRequestResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextRequestResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextStdErrResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextStdErrResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextStdErrResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextStdErrResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/TextStdOutResponse.cs b/Source/Meadow.Hcom/SerialResponses/TextStdOutResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/TextStdOutResponse.cs rename to Source/Meadow.Hcom/SerialResponses/TextStdOutResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/UploadCompletedResponse.cs b/Source/Meadow.Hcom/SerialResponses/UploadCompletedResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/UploadCompletedResponse.cs rename to Source/Meadow.Hcom/SerialResponses/UploadCompletedResponse.cs diff --git a/Source/v2/Meadow.HCom/SerialResponses/UploadDataPacketResponse.cs b/Source/Meadow.Hcom/SerialResponses/UploadDataPacketResponse.cs similarity index 100% rename from Source/v2/Meadow.HCom/SerialResponses/UploadDataPacketResponse.cs rename to Source/Meadow.Hcom/SerialResponses/UploadDataPacketResponse.cs diff --git a/Source/v2/Meadow.HCom/Usings.cs b/Source/Meadow.Hcom/Usings.cs similarity index 100% rename from Source/v2/Meadow.HCom/Usings.cs rename to Source/Meadow.Hcom/Usings.cs diff --git a/Source/v2/Meadow.Linker/Linker/ILLinker.cs b/Source/Meadow.Linker/Linker/ILLinker.cs similarity index 100% rename from Source/v2/Meadow.Linker/Linker/ILLinker.cs rename to Source/Meadow.Linker/Linker/ILLinker.cs diff --git a/Source/v2/Meadow.Linker/Linker/MeadowLinker.cs b/Source/Meadow.Linker/Linker/MeadowLinker.cs similarity index 100% rename from Source/v2/Meadow.Linker/Linker/MeadowLinker.cs rename to Source/Meadow.Linker/Linker/MeadowLinker.cs diff --git a/Source/v2/Meadow.Linker/Meadow.Linker.Rider.csproj b/Source/Meadow.Linker/Meadow.Linker.Rider.csproj similarity index 100% rename from Source/v2/Meadow.Linker/Meadow.Linker.Rider.csproj rename to Source/Meadow.Linker/Meadow.Linker.Rider.csproj diff --git a/Source/v2/Meadow.Linker/Meadow.Linker.csproj b/Source/Meadow.Linker/Meadow.Linker.csproj similarity index 100% rename from Source/v2/Meadow.Linker/Meadow.Linker.csproj rename to Source/Meadow.Linker/Meadow.Linker.csproj diff --git a/Meadow.CLI.Core/lib/Mono.Cecil.Pdb.dll b/Source/Meadow.Linker/lib/Mono.Cecil.Pdb.dll similarity index 100% rename from Meadow.CLI.Core/lib/Mono.Cecil.Pdb.dll rename to Source/Meadow.Linker/lib/Mono.Cecil.Pdb.dll diff --git a/Meadow.CLI.Core/lib/Mono.Cecil.dll b/Source/Meadow.Linker/lib/Mono.Cecil.dll similarity index 100% rename from Meadow.CLI.Core/lib/Mono.Cecil.dll rename to Source/Meadow.Linker/lib/Mono.Cecil.dll diff --git a/Meadow.CLI.Core/lib/illink.deps.json b/Source/Meadow.Linker/lib/illink.deps.json similarity index 100% rename from Meadow.CLI.Core/lib/illink.deps.json rename to Source/Meadow.Linker/lib/illink.deps.json diff --git a/Meadow.CLI.Core/lib/illink.dll b/Source/Meadow.Linker/lib/illink.dll similarity index 100% rename from Meadow.CLI.Core/lib/illink.dll rename to Source/Meadow.Linker/lib/illink.dll diff --git a/Meadow.CLI.Core/lib/illink.runtimeconfig.json b/Source/Meadow.Linker/lib/illink.runtimeconfig.json similarity index 100% rename from Meadow.CLI.Core/lib/illink.runtimeconfig.json rename to Source/Meadow.Linker/lib/illink.runtimeconfig.json diff --git a/Source/v2/Meadow.Linker/lib/meadow_link.xml b/Source/Meadow.Linker/lib/meadow_link.xml similarity index 100% rename from Source/v2/Meadow.Linker/lib/meadow_link.xml rename to Source/Meadow.Linker/lib/meadow_link.xml diff --git a/Source/v2/Meadow.Repository/Meadow.Repository.csproj b/Source/Meadow.Repository/Meadow.Repository.csproj similarity index 100% rename from Source/v2/Meadow.Repository/Meadow.Repository.csproj rename to Source/Meadow.Repository/Meadow.Repository.csproj diff --git a/Source/v2/Meadow.Repository/MeadowRoot.cs b/Source/Meadow.Repository/MeadowRoot.cs similarity index 100% rename from Source/v2/Meadow.Repository/MeadowRoot.cs rename to Source/Meadow.Repository/MeadowRoot.cs diff --git a/Source/v2/Meadow.Repository/Repo.cs b/Source/Meadow.Repository/Repo.cs similarity index 100% rename from Source/v2/Meadow.Repository/Repo.cs rename to Source/Meadow.Repository/Repo.cs diff --git a/Source/v2/Meadow.SoftwareManager/AssemblyInfo.cs b/Source/Meadow.SoftwareManager/AssemblyInfo.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/AssemblyInfo.cs rename to Source/Meadow.SoftwareManager/AssemblyInfo.cs diff --git a/Source/v2/Meadow.SoftwareManager/CrcTools.cs b/Source/Meadow.SoftwareManager/CrcTools.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/CrcTools.cs rename to Source/Meadow.SoftwareManager/CrcTools.cs diff --git a/Source/v2/Meadow.SoftwareManager/DownloadFileStream.cs b/Source/Meadow.SoftwareManager/DownloadFileStream.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/DownloadFileStream.cs rename to Source/Meadow.SoftwareManager/DownloadFileStream.cs diff --git a/Source/v2/Meadow.SoftwareManager/F7FirmwareDownloadManager.cs b/Source/Meadow.SoftwareManager/F7FirmwareDownloadManager.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/F7FirmwareDownloadManager.cs rename to Source/Meadow.SoftwareManager/F7FirmwareDownloadManager.cs diff --git a/Source/v2/Meadow.SoftwareManager/F7FirmwarePackageCollection.cs b/Source/Meadow.SoftwareManager/F7FirmwarePackageCollection.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/F7FirmwarePackageCollection.cs rename to Source/Meadow.SoftwareManager/F7FirmwarePackageCollection.cs diff --git a/Source/v2/Meadow.SoftwareManager/F7ReleaseMetadata.cs b/Source/Meadow.SoftwareManager/F7ReleaseMetadata.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/F7ReleaseMetadata.cs rename to Source/Meadow.SoftwareManager/F7ReleaseMetadata.cs diff --git a/Source/v2/Meadow.SoftwareManager/FileManager.cs b/Source/Meadow.SoftwareManager/FileManager.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/FileManager.cs rename to Source/Meadow.SoftwareManager/FileManager.cs diff --git a/Source/v2/Meadow.SoftwareManager/FirmwarePackage.cs b/Source/Meadow.SoftwareManager/FirmwarePackage.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/FirmwarePackage.cs rename to Source/Meadow.SoftwareManager/FirmwarePackage.cs diff --git a/Source/v2/Meadow.SoftwareManager/FirmwareStore.cs b/Source/Meadow.SoftwareManager/FirmwareStore.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/FirmwareStore.cs rename to Source/Meadow.SoftwareManager/FirmwareStore.cs diff --git a/Source/v2/Meadow.SoftwareManager/IFirmwarePackageCollection.cs b/Source/Meadow.SoftwareManager/IFirmwarePackageCollection.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/IFirmwarePackageCollection.cs rename to Source/Meadow.SoftwareManager/IFirmwarePackageCollection.cs diff --git a/Source/v2/Meadow.SoftwareManager/Meadow.SoftwareManager.Rider.csproj b/Source/Meadow.SoftwareManager/Meadow.SoftwareManager.Rider.csproj similarity index 100% rename from Source/v2/Meadow.SoftwareManager/Meadow.SoftwareManager.Rider.csproj rename to Source/Meadow.SoftwareManager/Meadow.SoftwareManager.Rider.csproj diff --git a/Source/v2/Meadow.SoftwareManager/Meadow.SoftwareManager.csproj b/Source/Meadow.SoftwareManager/Meadow.SoftwareManager.csproj similarity index 100% rename from Source/v2/Meadow.SoftwareManager/Meadow.SoftwareManager.csproj rename to Source/Meadow.SoftwareManager/Meadow.SoftwareManager.csproj diff --git a/Source/v2/Meadow.SoftwareManager/Usings.cs b/Source/Meadow.SoftwareManager/Usings.cs similarity index 100% rename from Source/v2/Meadow.SoftwareManager/Usings.cs rename to Source/Meadow.SoftwareManager/Usings.cs diff --git a/Source/v2/Meadow.Tooling.Core/App/AppManager.cs b/Source/Meadow.Tooling.Core/App/AppManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/App/AppManager.cs rename to Source/Meadow.Tooling.Core/App/AppManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Connection/MeadowConnectionManager.cs b/Source/Meadow.Tooling.Core/Connection/MeadowConnectionManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Connection/MeadowConnectionManager.cs rename to Source/Meadow.Tooling.Core/Connection/MeadowConnectionManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Meadow.Tooling.Core.Rider.csproj b/Source/Meadow.Tooling.Core/Meadow.Tooling.Core.Rider.csproj similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Meadow.Tooling.Core.Rider.csproj rename to Source/Meadow.Tooling.Core/Meadow.Tooling.Core.Rider.csproj diff --git a/Source/v2/Meadow.Tooling.Core/Meadow.Tooling.Core.csproj b/Source/Meadow.Tooling.Core/Meadow.Tooling.Core.csproj similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Meadow.Tooling.Core.csproj rename to Source/Meadow.Tooling.Core/Meadow.Tooling.Core.csproj diff --git a/Source/v2/Meadow.Tooling.Core/Package/IPackageManager.cs b/Source/Meadow.Tooling.Core/Package/IPackageManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Package/IPackageManager.cs rename to Source/Meadow.Tooling.Core/Package/IPackageManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Package/PackageManager.AssemblyManager.cs b/Source/Meadow.Tooling.Core/Package/PackageManager.AssemblyManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Package/PackageManager.AssemblyManager.cs rename to Source/Meadow.Tooling.Core/Package/PackageManager.AssemblyManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Package/PackageManager.BuildOptions.cs b/Source/Meadow.Tooling.Core/Package/PackageManager.BuildOptions.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Package/PackageManager.BuildOptions.cs rename to Source/Meadow.Tooling.Core/Package/PackageManager.BuildOptions.cs diff --git a/Source/v2/Meadow.Tooling.Core/Package/PackageManager.cs b/Source/Meadow.Tooling.Core/Package/PackageManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Package/PackageManager.cs rename to Source/Meadow.Tooling.Core/Package/PackageManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Settings/ISettingsManager.cs b/Source/Meadow.Tooling.Core/Settings/ISettingsManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Settings/ISettingsManager.cs rename to Source/Meadow.Tooling.Core/Settings/ISettingsManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Settings/SettingsManager.cs b/Source/Meadow.Tooling.Core/Settings/SettingsManager.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Settings/SettingsManager.cs rename to Source/Meadow.Tooling.Core/Settings/SettingsManager.cs diff --git a/Source/v2/Meadow.Tooling.Core/Telemetry/CIEnvironmentDetector.cs b/Source/Meadow.Tooling.Core/Telemetry/CIEnvironmentDetector.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Telemetry/CIEnvironmentDetector.cs rename to Source/Meadow.Tooling.Core/Telemetry/CIEnvironmentDetector.cs diff --git a/Source/v2/Meadow.Tooling.Core/Telemetry/MeadowTelemetry.cs b/Source/Meadow.Tooling.Core/Telemetry/MeadowTelemetry.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Telemetry/MeadowTelemetry.cs rename to Source/Meadow.Tooling.Core/Telemetry/MeadowTelemetry.cs diff --git a/Source/v2/Meadow.Tooling.Core/Telemetry/RuntimeEnvironment.cs b/Source/Meadow.Tooling.Core/Telemetry/RuntimeEnvironment.cs similarity index 100% rename from Source/v2/Meadow.Tooling.Core/Telemetry/RuntimeEnvironment.cs rename to Source/Meadow.Tooling.Core/Telemetry/RuntimeEnvironment.cs diff --git a/Source/v2/Meadow.UsbLib.Core/ILibUsbDevice.cs b/Source/Meadow.UsbLib.Core/ILibUsbDevice.cs similarity index 100% rename from Source/v2/Meadow.UsbLib.Core/ILibUsbDevice.cs rename to Source/Meadow.UsbLib.Core/ILibUsbDevice.cs diff --git a/Source/v2/Meadow.UsbLib.Core/Meadow.UsbLib.Core.csproj b/Source/Meadow.UsbLib.Core/Meadow.UsbLib.Core.csproj similarity index 100% rename from Source/v2/Meadow.UsbLib.Core/Meadow.UsbLib.Core.csproj rename to Source/Meadow.UsbLib.Core/Meadow.UsbLib.Core.csproj diff --git a/Source/v2/Meadow.UsbLib/LibUsbDevice.cs b/Source/Meadow.UsbLib/LibUsbDevice.cs similarity index 100% rename from Source/v2/Meadow.UsbLib/LibUsbDevice.cs rename to Source/Meadow.UsbLib/LibUsbDevice.cs diff --git a/Source/v2/Meadow.UsbLib/Meadow.UsbLib.csproj b/Source/Meadow.UsbLib/Meadow.UsbLib.csproj similarity index 100% rename from Source/v2/Meadow.UsbLib/Meadow.UsbLib.csproj rename to Source/Meadow.UsbLib/Meadow.UsbLib.csproj diff --git a/Source/v2/Meadow.UsbLibClassic/ClassicLibUsbDevice.cs b/Source/Meadow.UsbLibClassic/ClassicLibUsbDevice.cs similarity index 100% rename from Source/v2/Meadow.UsbLibClassic/ClassicLibUsbDevice.cs rename to Source/Meadow.UsbLibClassic/ClassicLibUsbDevice.cs diff --git a/Source/v2/Meadow.UsbLibClassic/Meadow.UsbLibClassic.csproj b/Source/Meadow.UsbLibClassic/Meadow.UsbLibClassic.csproj similarity index 100% rename from Source/v2/Meadow.UsbLibClassic/Meadow.UsbLibClassic.csproj rename to Source/Meadow.UsbLibClassic/Meadow.UsbLibClassic.csproj diff --git a/Meadow.CLI.Core/MeadowCLIKey.snk b/Source/MeadowCLIKey.snk similarity index 100% rename from Meadow.CLI.Core/MeadowCLIKey.snk rename to Source/MeadowCLIKey.snk diff --git a/Source/TestApps/LinkerTest/LinkerTest.sln b/Source/TestApps/LinkerTest/LinkerTest.sln deleted file mode 100644 index 6d8b8ee0..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.8.34309.116 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkerTest", "LinkerTest\LinkerTest.csproj", "{F18B502F-1D67-4F9A-8F1F-6A3C91C942E9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F18B502F-1D67-4F9A-8F1F-6A3C91C942E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F18B502F-1D67-4F9A-8F1F-6A3C91C942E9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F18B502F-1D67-4F9A-8F1F-6A3C91C942E9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F18B502F-1D67-4F9A-8F1F-6A3C91C942E9}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8AF82077-F626-42F0-81B2-B92439C770DA} - EndGlobalSection -EndGlobal diff --git a/Source/TestApps/LinkerTest/LinkerTest/ILLinker.cs b/Source/TestApps/LinkerTest/LinkerTest/ILLinker.cs deleted file mode 100644 index 825aee14..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/ILLinker.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Microsoft.Extensions.Logging; -using System.Diagnostics; - -namespace LinkerTest -{ - internal class ILLinker - { - readonly ILogger? _logger; - - public ILLinker(ILogger? logger = null) - { - _logger = logger; - } - - public async Task RunILLink( - string illinkerDllPath, - string descriptorXmlPath, - string noLinkArgs, - string prelinkAppPath, - string prelinkDir, - string postlinkDir) - { - if (!File.Exists(illinkerDllPath)) - { - throw new FileNotFoundException("Cannot run trimming operation, illink.dll not found"); - } - - //original - //var monolinker_args = $"\"{illinkerDllPath}\" -x \"{descriptorXmlPath}\" {noLinkArgs} --skip-unresolved --deterministic --keep-facades true --ignore-descriptors true -b true -c link -o \"{postlinkDir}\" -r \"{prelinkAppPath}\" -a \"{prelink_os}\" -d \"{prelinkDir}\""; - - var monolinker_args = $"\"{illinkerDllPath}\"" + - $" -x \"{descriptorXmlPath}\" " + //link files in the descriptor file (needed) - $"{noLinkArgs} " + //arguments to skip linking - will be blank if we are linking - $"-r \"{prelinkAppPath}\" " + //link the app in the prelink folder (needed) - $"--skip-unresolved true " + //skip unresolved references (needed -hangs without) - $"--deterministic true " + //make deterministic (to avoid pushing unchanged files to the device) - $"--keep-facades true " + //keep facades (needed - will skip key libs without) - $"-b true " + //Update debug symbols for each linked module (needed - will skip key libs without) - $"-o \"{postlinkDir}\" " + //output directory - - - //old - //$"--ignore-descriptors false " + //ignore descriptors (doesn't appear to impact behavior) - //$"-c link " + //link framework assemblies - //$"-d \"{prelinkDir}\"" //additional folder to link (not needed) - - //experimental - //$"--explicit-reflection true " + //enable explicit reflection (throws an exception with it) - //$"--keep-dep-attributes true " + //keep dependency attributes (files are slightly larger with, doesn't fix dependency issue) - ""; - - _logger?.Log(LogLevel.Information, "Trimming assemblies"); - - using (var process = new Process()) - { - process.StartInfo.WorkingDirectory = Directory.GetDirectoryRoot(illinkerDllPath); - process.StartInfo.FileName = "dotnet"; - process.StartInfo.Arguments = monolinker_args; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardError = true; - process.StartInfo.RedirectStandardOutput = true; - process.Start(); - - // To avoid deadlocks, read the output stream first and then wait - string stdOutReaderResult; - using (StreamReader stdOutReader = process.StandardOutput) - { - stdOutReaderResult = await stdOutReader.ReadToEndAsync(); - - Console.WriteLine("StandardOutput Contains: " + stdOutReaderResult); - - _logger?.Log(LogLevel.Debug, "StandardOutput Contains: " + stdOutReaderResult); - } - - await process.WaitForExitAsync(); - - if (process.ExitCode != 0) - { - _logger?.Log(LogLevel.Debug, $"Trimming failed - ILLinker execution error!\nProcess Info: {process.StartInfo.FileName} {process.StartInfo.Arguments} \nExit Code: {process.ExitCode}"); - throw new Exception("Trimming failed"); - } - } - } - } -} \ No newline at end of file diff --git a/Source/TestApps/LinkerTest/LinkerTest/LinkerTest.csproj b/Source/TestApps/LinkerTest/LinkerTest/LinkerTest.csproj deleted file mode 100644 index 5f9d9e86..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/LinkerTest.csproj +++ /dev/null @@ -1,47 +0,0 @@ - - - - Exe - net6.0 - enable - enable - preview - - - - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - - diff --git a/Source/TestApps/LinkerTest/LinkerTest/MeadowLinker.cs b/Source/TestApps/LinkerTest/LinkerTest/MeadowLinker.cs deleted file mode 100644 index 8ebcf4a3..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/MeadowLinker.cs +++ /dev/null @@ -1,175 +0,0 @@ -using Microsoft.Extensions.Logging; -using Mono.Cecil; -using Mono.Collections.Generic; -using System.Reflection; - -namespace LinkerTest; - -public class MeadowLinker(string meadowAssembliesPath, ILogger? logger = null) -{ - private const string IL_LINKER_DIR = "lib"; - private const string IL_LINKER_DLL = "illink.dll"; - private const string MEADOW_LINK_XML = "meadow_link.xml"; - - public const string PostLinkDirectoryName = "postlink_bin"; - public const string PreLinkDirectoryName = "prelink_bin"; - - readonly ILLinker _linker = new ILLinker(logger); - readonly ILogger? _logger = logger; - - private readonly string _meadowAssembliesPath = meadowAssembliesPath; - - public async Task Trim( - FileInfo meadowAppFile, - bool includePdbs = false, - IList? noLink = null) - { - var dependencies = MapDependencies(meadowAppFile); - - CopyDependenciesToPreLinkFolder(meadowAppFile, dependencies, includePdbs); - - //run the _linker against the dependencies - await TrimMeadowApp(meadowAppFile, noLink); - } - - List MapDependencies(FileInfo meadowAppFile) - { - //get all dependencies in meadowAppFile and exclude the Meadow App - var dependencyMap = new List(); - - var appRefs = GetAssemblyReferences(meadowAppFile.FullName); - return GetDependencies(meadowAppFile.FullName, appRefs, dependencyMap, meadowAppFile.DirectoryName); - } - - public void CopyDependenciesToPreLinkFolder( - FileInfo meadowApp, - List dependencies, - bool includePdbs) - { - //set up the paths - var prelinkDir = Path.Combine(meadowApp.DirectoryName!, PreLinkDirectoryName); - var postlinkDir = Path.Combine(meadowApp.DirectoryName!, PostLinkDirectoryName); - - //create output directories - CreateEmptyDirectory(prelinkDir); - CreateEmptyDirectory(postlinkDir); - - //copy meadow app - File.Copy(meadowApp.FullName, Path.Combine(prelinkDir, meadowApp.Name), overwrite: true); - - //copy dependencies and optional pdbs from the local folder and the meadow assemblies folder - foreach (var dependency in dependencies) - { - var destination = Path.Combine(prelinkDir, Path.GetFileName(dependency)); - File.Copy(dependency, destination, overwrite: true); - - if (includePdbs) - { - var pdbFile = Path.ChangeExtension(dependency, "pdb"); - if (File.Exists(pdbFile)) - { - destination = Path.ChangeExtension(destination, "pdb"); - File.Copy(pdbFile, destination, overwrite: true); - } - } - } - } - - public async Task?> TrimMeadowApp( - FileInfo file, - IList? noLink) - { - //set up the paths - var prelink_dir = Path.Combine(file.DirectoryName!, PreLinkDirectoryName); - var postlink_dir = Path.Combine(file.DirectoryName!, PostLinkDirectoryName); - var prelink_app = Path.Combine(prelink_dir, file.Name); - var base_path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var illinker_path = Path.Combine(base_path!, IL_LINKER_DIR, IL_LINKER_DLL); - var descriptor_path = Path.Combine(base_path!, IL_LINKER_DIR, MEADOW_LINK_XML); - - //prepare _linker arguments - var no_link_args = noLink != null ? string.Join(" ", noLink.Select(o => $"-p copy \"{o}\"")) : string.Empty; - - try - { - //link the apps - await _linker.RunILLink(illinker_path, descriptor_path, no_link_args, prelink_app, prelink_dir, postlink_dir); - } - catch (Exception ex) - { - _logger?.LogError(ex, "Error trimming Meadow app"); - } - - return Directory.EnumerateFiles(postlink_dir); - } - - /// - /// This method recursively gets all dependencies for the given assembly - /// - private List GetDependencies(string assemblyPath, Collection assemblyReferences, List dependencyMap, string appDir) - { - if (dependencyMap.Contains(assemblyPath)) - { //already have this assembly mapped - return dependencyMap; - } - - dependencyMap.Add(assemblyPath); - - foreach (var reference in assemblyReferences) - { - var fullPath = FindAssemblyFullPath(reference.Name, appDir, _meadowAssembliesPath); - - Collection namedRefs = default!; - - if (fullPath == null) - { - continue; - } - namedRefs = GetAssemblyReferences(fullPath); - - //recursive! - dependencyMap = GetDependencies(fullPath!, namedRefs!, dependencyMap, appDir); - } - - return dependencyMap.Where(x => x.Contains("App.") == false).ToList(); - } - - static string? FindAssemblyFullPath(string fileName, string localPath, string meadowAssembliesPath) - { - //Assembly may not have a file extension, add .dll if it doesn't - if (Path.GetExtension(fileName) != ".exe" && - Path.GetExtension(fileName) != ".dll") - { - fileName += ".dll"; - } - - //meadow assemblies path - if (File.Exists(Path.Combine(meadowAssembliesPath, fileName))) - { - return Path.Combine(meadowAssembliesPath, fileName); - } - - //localPath - if (File.Exists(Path.Combine(localPath, fileName))) - { - return Path.Combine(localPath, fileName); - } - - return null; - } - - private Collection GetAssemblyReferences(string assemblyPath) - { - using var definition = AssemblyDefinition.ReadAssembly(assemblyPath); - return definition.MainModule.AssemblyReferences; - } - - private void CreateEmptyDirectory(string directoryPath) - { - if (Directory.Exists(directoryPath)) - { - Directory.Delete(directoryPath, recursive: true); - } - Directory.CreateDirectory(directoryPath); - } -} \ No newline at end of file diff --git a/Source/TestApps/LinkerTest/LinkerTest/Program.cs b/Source/TestApps/LinkerTest/LinkerTest/Program.cs deleted file mode 100644 index f0f60768..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/Program.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Diagnostics; - -namespace LinkerTest -{ - internal class Program - { - private static readonly string _meadowAssembliesPath = @"C:\Users\adria\AppData\Local\WildernessLabs\Firmware\1.6.0.1\meadow_assemblies\"; - - static async Task Main(string[] args) - { - Console.WriteLine("Hello, World!"); - - // await OtherLink(); - - // return; - - var linker = new MeadowLinker(_meadowAssembliesPath); - - string fileToLink = @"H:\WL\Meadow.ProjectLab\Source\ProjectLab_Demo\bin\Debug\netstandard2.1\App.dll"; - - await linker.Trim(new FileInfo(fileToLink), true); - } - - static async Task OtherLink() - { - var monolinker_args = @"""H:\WL\Meadow.CLI\Meadow.CLI.Classic\bin\Debug\lib\illink.dll"" -x ""H:\WL\Meadow.CLI\Meadow.CLI.Classic\bin\Debug\lib\meadow_link.xml"" --skip-unresolved --deterministic --keep-facades true --ignore-descriptors true -b true -c link -o ""H:\WL\Meadow.ProjectLab\Source\ProjectLab_Demo\bin\Debug\netstandard2.1\postlink_bin"" -r ""H:\WL\Meadow.ProjectLab\Source\ProjectLab_Demo\bin\Debug\netstandard2.1\prelink_bin\App.dll"" -a ""H:\WL\Meadow.ProjectLab\Source\ProjectLab_Demo\bin\Debug\netstandard2.1\prelink_bin\Meadow.dll"" -d ""H:\WL\Meadow.ProjectLab\Source\ProjectLab_Demo\bin\Debug\netstandard2.1\prelink_bin"""; - - Console.WriteLine("Trimming assemblies to reduce size (may take several seconds)..."); - - using (var process = new Process()) - { - process.StartInfo.FileName = "dotnet"; - process.StartInfo.Arguments = monolinker_args; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardError = true; - process.StartInfo.RedirectStandardOutput = true; - process.Start(); - - // To avoid deadlocks, read the output stream first and then wait - string stdOutReaderResult; - using (StreamReader stdOutReader = process.StandardOutput) - { - stdOutReaderResult = await stdOutReader.ReadToEndAsync(); - Console.WriteLine("StandardOutput Contains: " + stdOutReaderResult); - } - } - } - } -} diff --git a/Source/TestApps/LinkerTest/LinkerTest/Readme.md b/Source/TestApps/LinkerTest/LinkerTest/Readme.md deleted file mode 100644 index 52c7eaf0..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/Readme.md +++ /dev/null @@ -1,41 +0,0 @@ -Attempting to diagnose why adding nuget packages is changing the behavior of illink when trimming libraries. - -Notes: -It appears the Mono.Cecil libraries are version 0.11.2 -We do need the nugets to access the Cecil APIs (could dynamically load the lib), I vote we keep the nuget and the libs in sync - -Safe nugets: -Mono.Cecil 0.11.2 -Newtonsoft.Json 13.0.3 -System.Runtime.CompilerServices.Unsafe 6.0.0 -Microsoft.Extensions.DependencyInjection -System.Management - - -Unsafe nugets: -Microsoft.Extensions.Configuration.Json - -Impacts all extension libraries, netstandard.dll, system.core.dll, system.dll -This is probably the one that breaks the world - - -Serilog - impacts Microsoft.Extensions.Primitives - - -Microsoft.Extensions.Logging 7.0.0 -Microsoft.Extensions.Logging.Abstractions 8.0.0 - -Together change the linking behavior of: -Microsoft.Extensions.Configuration -Microsoft.Extensions.Configuration.Abstractions -Microsoft.Extensions.Configuration.FileExtensions -Microsoft.Extensions.Configuration.Primitives - - -Adding a reference to Meadow.CLI.Core also impacts the linking behavior of the above libraries and causes three libraries to be linked out completely - -Microsoft.Bcl.AsyncInterfaces -System.Buffers -System.Threading.Tasks.Extensions - - diff --git a/Source/TestApps/LinkerTest/LinkerTest/lib/Mono.Cecil.Pdb.dll b/Source/TestApps/LinkerTest/LinkerTest/lib/Mono.Cecil.Pdb.dll deleted file mode 100644 index d6f5ee58..00000000 Binary files a/Source/TestApps/LinkerTest/LinkerTest/lib/Mono.Cecil.Pdb.dll and /dev/null differ diff --git a/Source/TestApps/LinkerTest/LinkerTest/lib/Mono.Cecil.dll b/Source/TestApps/LinkerTest/LinkerTest/lib/Mono.Cecil.dll deleted file mode 100644 index 682aef81..00000000 Binary files a/Source/TestApps/LinkerTest/LinkerTest/lib/Mono.Cecil.dll and /dev/null differ diff --git a/Source/TestApps/LinkerTest/LinkerTest/lib/illink.deps.json b/Source/TestApps/LinkerTest/LinkerTest/lib/illink.deps.json deleted file mode 100644 index d7b91143..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/lib/illink.deps.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v3.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v3.0": { - "illink/5.0.0-dev": { - "dependencies": { - "Microsoft.Net.Compilers.Toolset": "3.8.0-4.20503.2", - "Microsoft.SourceLink.AzureRepos.Git": "1.1.0-beta-20206-02", - "Microsoft.SourceLink.GitHub": "1.1.0-beta-20206-02", - "Mono.Cecil": "0.11.2", - "Mono.Cecil.Pdb": "0.11.2", - "XliffTasks": "1.0.0-beta.20502.2" - }, - "runtime": { - "illink.dll": {} - } - }, - "Microsoft.Build.Tasks.Git/1.1.0-beta-20206-02": {}, - "Microsoft.Net.Compilers.Toolset/3.8.0-4.20503.2": {}, - "Microsoft.SourceLink.AzureRepos.Git/1.1.0-beta-20206-02": { - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.0-beta-20206-02", - "Microsoft.SourceLink.Common": "1.1.0-beta-20206-02" - } - }, - "Microsoft.SourceLink.Common/1.1.0-beta-20206-02": {}, - "Microsoft.SourceLink.GitHub/1.1.0-beta-20206-02": { - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.0-beta-20206-02", - "Microsoft.SourceLink.Common": "1.1.0-beta-20206-02" - } - }, - "XliffTasks/1.0.0-beta.20502.2": {}, - "Mono.Cecil/0.11.2": { - "runtime": { - "Mono.Cecil.dll": {} - } - }, - "Mono.Cecil.Pdb/0.11.2": { - "dependencies": { - "Mono.Cecil": "0.11.2" - }, - "runtime": { - "Mono.Cecil.Pdb.dll": {} - } - } - } - }, - "libraries": { - "illink/5.0.0-dev": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Microsoft.Build.Tasks.Git/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-hZ9leS9Yd9MHpqvviMftSJFDcLYu2h1DrapW1TDm1s1fgOy71c8HvArNMd3fseVkXmp3VTfGnkgcw0FR+TI6xw==", - "path": "microsoft.build.tasks.git/1.1.0-beta-20206-02", - "hashPath": "microsoft.build.tasks.git.1.1.0-beta-20206-02.nupkg.sha512" - }, - "Microsoft.Net.Compilers.Toolset/3.8.0-4.20503.2": { - "type": "package", - "serviceable": true, - "sha512": "sha512-jfscID/5IHHPVVEbFCAJEUEWCeWNZCLwyBcUFG3/u44oiRd/aseDOYRzl3OnIIvcwzi0U2lSAs6Lt2+rdRIDMg==", - "path": "microsoft.net.compilers.toolset/3.8.0-4.20503.2", - "hashPath": "microsoft.net.compilers.toolset.3.8.0-4.20503.2.nupkg.sha512" - }, - "Microsoft.SourceLink.AzureRepos.Git/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-vVYhSds9TfraTQkGHHMDMVWnr3kCkTZ7vmqUmrXQBDJFXiWTuMoP5RRa9s1M/KmgB4szi5TOb7sOaHWKDT9qDA==", - "path": "microsoft.sourcelink.azurerepos.git/1.1.0-beta-20206-02", - "hashPath": "microsoft.sourcelink.azurerepos.git.1.1.0-beta-20206-02.nupkg.sha512" - }, - "Microsoft.SourceLink.Common/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-aek0RTQ+4Bf11WvqaXajwYoaBWkX2edBjAr5XJOvhAsHX6/9vPOb7IpHAiE/NyCse7IcpGWslJZHNkv4UBEFqw==", - "path": "microsoft.sourcelink.common/1.1.0-beta-20206-02", - "hashPath": "microsoft.sourcelink.common.1.1.0-beta-20206-02.nupkg.sha512" - }, - "Microsoft.SourceLink.GitHub/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-7A7P0EwL+lypaI/CEvG4IcpAlQeAt04uPPw1SO6Q9Jwz2nE9309pQXJ4TfP/RLL8IOObACidN66+gVR+bJDZHw==", - "path": "microsoft.sourcelink.github/1.1.0-beta-20206-02", - "hashPath": "microsoft.sourcelink.github.1.1.0-beta-20206-02.nupkg.sha512" - }, - "XliffTasks/1.0.0-beta.20502.2": { - "type": "package", - "serviceable": true, - "sha512": "sha512-fnLroyas9Lfo7+YWFHjfAALbTODgNDY4z8GB4uT9OKiqWwYje/bcW5QJuRCWCkGtC1uuAx9oxNYH/MZ9G9/fmw==", - "path": "xlifftasks/1.0.0-beta.20502.2", - "hashPath": "xlifftasks.1.0.0-beta.20502.2.nupkg.sha512" - }, - "Mono.Cecil/0.11.2": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Mono.Cecil.Pdb/0.11.2": { - "type": "project", - "serviceable": false, - "sha512": "" - } - } -} \ No newline at end of file diff --git a/Source/TestApps/LinkerTest/LinkerTest/lib/illink.dll b/Source/TestApps/LinkerTest/LinkerTest/lib/illink.dll deleted file mode 100644 index f392213b..00000000 Binary files a/Source/TestApps/LinkerTest/LinkerTest/lib/illink.dll and /dev/null differ diff --git a/Source/TestApps/LinkerTest/LinkerTest/lib/illink.runtimeconfig.json b/Source/TestApps/LinkerTest/LinkerTest/lib/illink.runtimeconfig.json deleted file mode 100644 index 617ab505..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/lib/illink.runtimeconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "runtimeOptions": { - "tfm": "netcoreapp3.0", - "framework": { - "name": "Microsoft.NETCore.App", - "version": "3.0.0" - }, - "rollForwardOnNoCandidateFx": 2 - } -} \ No newline at end of file diff --git a/Source/TestApps/LinkerTest/LinkerTest/lib/meadow_link.xml b/Source/TestApps/LinkerTest/LinkerTest/lib/meadow_link.xml deleted file mode 100644 index 0fe29752..00000000 --- a/Source/TestApps/LinkerTest/LinkerTest/lib/meadow_link.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/Builders/FakeableHttpMessageHandler.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/Builders/FakeableHttpMessageHandler.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/Builders/FakeableHttpMessageHandler.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/Builders/FakeableHttpMessageHandler.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/DeviceClientTests/AddDeviceTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/DeviceClientTests/AddDeviceTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/DeviceClientTests/AddDeviceTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/DeviceClientTests/AddDeviceTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetDownloadResponseTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetDownloadResponseTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetDownloadResponseTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetDownloadResponseTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionsTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionsTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionsTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/FirmwareClientTests/GetVersionsTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/Meadow.Cloud.Client.Unit.Tests.csproj b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/Meadow.Cloud.Client.Unit.Tests.csproj similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/Meadow.Cloud.Client.Unit.Tests.csproj rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/Meadow.Cloud.Client.Unit.Tests.csproj diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/MeadowCloudClientBaseTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/MeadowCloudClientBaseTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/MeadowCloudClientBaseTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/MeadowCloudClientBaseTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetOrganizationsTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetOrganizationsTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetOrganizationsTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetOrganizationsTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetUserTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetUserTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetUserTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/UserClientTests/GetUserTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/UserServiceTests.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/UserServiceTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/UserServiceTests.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/UserServiceTests.cs diff --git a/Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/Usings.cs b/Source/Tests/Meadow.Cloud.Client.Unit.Tests/Usings.cs similarity index 100% rename from Source/v2/Tests/Meadow.Cloud.Client.Unit.Tests/Usings.cs rename to Source/Tests/Meadow.Cloud.Client.Unit.Tests/Usings.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/CliTests.cs b/Source/Tests/Meadow.HCom.Integration.Tests/CliTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/CliTests.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/CliTests.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/ConnectionManagerTests.cs b/Source/Tests/Meadow.HCom.Integration.Tests/ConnectionManagerTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/ConnectionManagerTests.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/ConnectionManagerTests.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/InMemorySettingsManager.cs b/Source/Tests/Meadow.HCom.Integration.Tests/InMemorySettingsManager.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/InMemorySettingsManager.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/InMemorySettingsManager.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/Meadow.HCom.Integration.Tests.csproj b/Source/Tests/Meadow.HCom.Integration.Tests/Meadow.HCom.Integration.Tests.csproj similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/Meadow.HCom.Integration.Tests.csproj rename to Source/Tests/Meadow.HCom.Integration.Tests/Meadow.HCom.Integration.Tests.csproj diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/SerialCommandTests.cs b/Source/Tests/Meadow.HCom.Integration.Tests/SerialCommandTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/SerialCommandTests.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/SerialCommandTests.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/SerialConnectionTests.cs b/Source/Tests/Meadow.HCom.Integration.Tests/SerialConnectionTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/SerialConnectionTests.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/SerialConnectionTests.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/TcpCommandTests.cs b/Source/Tests/Meadow.HCom.Integration.Tests/TcpCommandTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/TcpCommandTests.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/TcpCommandTests.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/TcpConnectionTests.cs b/Source/Tests/Meadow.HCom.Integration.Tests/TcpConnectionTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/TcpConnectionTests.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/TcpConnectionTests.cs diff --git a/Source/v2/Tests/Meadow.HCom.Integration.Tests/Usings.cs b/Source/Tests/Meadow.HCom.Integration.Tests/Usings.cs similarity index 100% rename from Source/v2/Tests/Meadow.HCom.Integration.Tests/Usings.cs rename to Source/Tests/Meadow.HCom.Integration.Tests/Usings.cs diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Integration.Tests/Meadow.SoftwareManager.Integration.Tests.csproj b/Source/Tests/Meadow.SoftwareManager.Integration.Tests/Meadow.SoftwareManager.Integration.Tests.csproj similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Integration.Tests/Meadow.SoftwareManager.Integration.Tests.csproj rename to Source/Tests/Meadow.SoftwareManager.Integration.Tests/Meadow.SoftwareManager.Integration.Tests.csproj diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Integration.Tests/Usings.cs b/Source/Tests/Meadow.SoftwareManager.Integration.Tests/Usings.cs similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Integration.Tests/Usings.cs rename to Source/Tests/Meadow.SoftwareManager.Integration.Tests/Usings.cs diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetLatestAvailableVersionTests.cs b/Source/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetLatestAvailableVersionTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetLatestAvailableVersionTests.cs rename to Source/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetLatestAvailableVersionTests.cs diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetReleaseMetadataTests.cs b/Source/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetReleaseMetadataTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetReleaseMetadataTests.cs rename to Source/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwareDownloadManagerTests/GetReleaseMetadataTests.cs diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwarePackageCollectionTests.cs b/Source/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwarePackageCollectionTests.cs similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwarePackageCollectionTests.cs rename to Source/Tests/Meadow.SoftwareManager.Unit.Tests/F7FirmwarePackageCollectionTests.cs diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/Meadow.SoftwareManager.Unit.Tests.csproj b/Source/Tests/Meadow.SoftwareManager.Unit.Tests/Meadow.SoftwareManager.Unit.Tests.csproj similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/Meadow.SoftwareManager.Unit.Tests.csproj rename to Source/Tests/Meadow.SoftwareManager.Unit.Tests/Meadow.SoftwareManager.Unit.Tests.csproj diff --git a/Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/Usings.cs b/Source/Tests/Meadow.SoftwareManager.Unit.Tests/Usings.cs similarity index 100% rename from Source/v2/Tests/Meadow.SoftwareManager.Unit.Tests/Usings.cs rename to Source/Tests/Meadow.SoftwareManager.Unit.Tests/Usings.cs diff --git a/Meadow.CLI/images/icon.png b/Source/icon.png similarity index 100% rename from Meadow.CLI/images/icon.png rename to Source/icon.png diff --git a/Source/v2/Meadow.Cli/appsettings.json b/Source/v2/Meadow.Cli/appsettings.json deleted file mode 100644 index d9d2c46c..00000000 --- a/Source/v2/Meadow.Cli/appsettings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "meadowCloudHost": "https://www.meadowcloud.co" -} \ No newline at end of file diff --git a/Source/v2/Meadow.Cloud.Client/Packages/PackageClient.cs b/Source/v2/Meadow.Cloud.Client/Packages/PackageClient.cs deleted file mode 100644 index 6f22328a..00000000 --- a/Source/v2/Meadow.Cloud.Client/Packages/PackageClient.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Meadow.Cloud.Client.Packages; - -public interface IPackageClient -{ -} - -public class PackageClient : IPackageClient -{ -} diff --git a/Source/v2/Meadow.Linker/lib/Mono.Cecil.Pdb.dll b/Source/v2/Meadow.Linker/lib/Mono.Cecil.Pdb.dll deleted file mode 100644 index d6f5ee58..00000000 Binary files a/Source/v2/Meadow.Linker/lib/Mono.Cecil.Pdb.dll and /dev/null differ diff --git a/Source/v2/Meadow.Linker/lib/Mono.Cecil.dll b/Source/v2/Meadow.Linker/lib/Mono.Cecil.dll deleted file mode 100644 index 682aef81..00000000 Binary files a/Source/v2/Meadow.Linker/lib/Mono.Cecil.dll and /dev/null differ diff --git a/Source/v2/Meadow.Linker/lib/illink.deps.json b/Source/v2/Meadow.Linker/lib/illink.deps.json deleted file mode 100644 index d7b91143..00000000 --- a/Source/v2/Meadow.Linker/lib/illink.deps.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v3.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v3.0": { - "illink/5.0.0-dev": { - "dependencies": { - "Microsoft.Net.Compilers.Toolset": "3.8.0-4.20503.2", - "Microsoft.SourceLink.AzureRepos.Git": "1.1.0-beta-20206-02", - "Microsoft.SourceLink.GitHub": "1.1.0-beta-20206-02", - "Mono.Cecil": "0.11.2", - "Mono.Cecil.Pdb": "0.11.2", - "XliffTasks": "1.0.0-beta.20502.2" - }, - "runtime": { - "illink.dll": {} - } - }, - "Microsoft.Build.Tasks.Git/1.1.0-beta-20206-02": {}, - "Microsoft.Net.Compilers.Toolset/3.8.0-4.20503.2": {}, - "Microsoft.SourceLink.AzureRepos.Git/1.1.0-beta-20206-02": { - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.0-beta-20206-02", - "Microsoft.SourceLink.Common": "1.1.0-beta-20206-02" - } - }, - "Microsoft.SourceLink.Common/1.1.0-beta-20206-02": {}, - "Microsoft.SourceLink.GitHub/1.1.0-beta-20206-02": { - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.0-beta-20206-02", - "Microsoft.SourceLink.Common": "1.1.0-beta-20206-02" - } - }, - "XliffTasks/1.0.0-beta.20502.2": {}, - "Mono.Cecil/0.11.2": { - "runtime": { - "Mono.Cecil.dll": {} - } - }, - "Mono.Cecil.Pdb/0.11.2": { - "dependencies": { - "Mono.Cecil": "0.11.2" - }, - "runtime": { - "Mono.Cecil.Pdb.dll": {} - } - } - } - }, - "libraries": { - "illink/5.0.0-dev": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Microsoft.Build.Tasks.Git/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-hZ9leS9Yd9MHpqvviMftSJFDcLYu2h1DrapW1TDm1s1fgOy71c8HvArNMd3fseVkXmp3VTfGnkgcw0FR+TI6xw==", - "path": "microsoft.build.tasks.git/1.1.0-beta-20206-02", - "hashPath": "microsoft.build.tasks.git.1.1.0-beta-20206-02.nupkg.sha512" - }, - "Microsoft.Net.Compilers.Toolset/3.8.0-4.20503.2": { - "type": "package", - "serviceable": true, - "sha512": "sha512-jfscID/5IHHPVVEbFCAJEUEWCeWNZCLwyBcUFG3/u44oiRd/aseDOYRzl3OnIIvcwzi0U2lSAs6Lt2+rdRIDMg==", - "path": "microsoft.net.compilers.toolset/3.8.0-4.20503.2", - "hashPath": "microsoft.net.compilers.toolset.3.8.0-4.20503.2.nupkg.sha512" - }, - "Microsoft.SourceLink.AzureRepos.Git/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-vVYhSds9TfraTQkGHHMDMVWnr3kCkTZ7vmqUmrXQBDJFXiWTuMoP5RRa9s1M/KmgB4szi5TOb7sOaHWKDT9qDA==", - "path": "microsoft.sourcelink.azurerepos.git/1.1.0-beta-20206-02", - "hashPath": "microsoft.sourcelink.azurerepos.git.1.1.0-beta-20206-02.nupkg.sha512" - }, - "Microsoft.SourceLink.Common/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-aek0RTQ+4Bf11WvqaXajwYoaBWkX2edBjAr5XJOvhAsHX6/9vPOb7IpHAiE/NyCse7IcpGWslJZHNkv4UBEFqw==", - "path": "microsoft.sourcelink.common/1.1.0-beta-20206-02", - "hashPath": "microsoft.sourcelink.common.1.1.0-beta-20206-02.nupkg.sha512" - }, - "Microsoft.SourceLink.GitHub/1.1.0-beta-20206-02": { - "type": "package", - "serviceable": true, - "sha512": "sha512-7A7P0EwL+lypaI/CEvG4IcpAlQeAt04uPPw1SO6Q9Jwz2nE9309pQXJ4TfP/RLL8IOObACidN66+gVR+bJDZHw==", - "path": "microsoft.sourcelink.github/1.1.0-beta-20206-02", - "hashPath": "microsoft.sourcelink.github.1.1.0-beta-20206-02.nupkg.sha512" - }, - "XliffTasks/1.0.0-beta.20502.2": { - "type": "package", - "serviceable": true, - "sha512": "sha512-fnLroyas9Lfo7+YWFHjfAALbTODgNDY4z8GB4uT9OKiqWwYje/bcW5QJuRCWCkGtC1uuAx9oxNYH/MZ9G9/fmw==", - "path": "xlifftasks/1.0.0-beta.20502.2", - "hashPath": "xlifftasks.1.0.0-beta.20502.2.nupkg.sha512" - }, - "Mono.Cecil/0.11.2": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Mono.Cecil.Pdb/0.11.2": { - "type": "project", - "serviceable": false, - "sha512": "" - } - } -} \ No newline at end of file diff --git a/Source/v2/Meadow.Linker/lib/illink.dll b/Source/v2/Meadow.Linker/lib/illink.dll deleted file mode 100644 index f392213b..00000000 Binary files a/Source/v2/Meadow.Linker/lib/illink.dll and /dev/null differ diff --git a/Source/v2/Meadow.Linker/lib/illink.runtimeconfig.json b/Source/v2/Meadow.Linker/lib/illink.runtimeconfig.json deleted file mode 100644 index 617ab505..00000000 --- a/Source/v2/Meadow.Linker/lib/illink.runtimeconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "runtimeOptions": { - "tfm": "netcoreapp3.0", - "framework": { - "name": "Microsoft.NETCore.App", - "version": "3.0.0" - }, - "rollForwardOnNoCandidateFx": 2 - } -} \ No newline at end of file diff --git a/Source/v2/MeadowCLIKey.snk b/Source/v2/MeadowCLIKey.snk deleted file mode 100644 index fea5c270..00000000 Binary files a/Source/v2/MeadowCLIKey.snk and /dev/null differ diff --git a/Source/v2/icon.png b/Source/v2/icon.png deleted file mode 100644 index 2c87b8f1..00000000 Binary files a/Source/v2/icon.png and /dev/null differ diff --git a/TestApp/Program.cs b/TestApp/Program.cs deleted file mode 100644 index a5d52d4e..00000000 --- a/TestApp/Program.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace TestApp -{ - class MainClass - { - //static string _devicePort = "/dev/tty.usbmodem3366337830361"; //mac - static string _devicePort = "COM14"; //win - public static void Main(string[] args) - { - ExecuteCLI("download os"); - ExecuteCLI($"flash os -s {_devicePort}"); - - Console.WriteLine("Done!"); - Console.Read(); - } - - static void ExecuteCLI(string arg) - { - char pad = '='; - Console.Write("".PadLeft(40, pad)); - Console.WriteLine($" {arg} ".PadRight(60, pad)); - - using (var process = new Process()) - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - process.StartInfo.FileName = @"..\..\..\..\Meadow.CLI\bin\Debug\net5.0\Meadow.CLI.exe"; - process.StartInfo.Arguments = arg; - } - else - { - // macos, haven't tested on linux :/ - process.StartInfo.FileName = "dotnet"; - process.StartInfo.Arguments = $"./Meadow.CLI/bin/Debug/net5.0/Meadow.CLI.dll {arg}"; - } - - process.StartInfo.UseShellExecute = false; - process.Start(); - - process.WaitForExit(); - } - } - - /* - - FileManager commands to test - - // MonoUpdateRt, PartitionFileSystem, MountFileSystem, InitializeFileSystem, CreateFileSystem, FormatFileSystem - do we still need these? - - Console.WriteLine("WriteFileToFlash"); - File.WriteAllText(".\\hello_meadow.txt", "test"); - - Console.WriteLine("ListFiles"); - await MeadowFileManager.ListFiles(meadow); - - Console.WriteLine("ListFilesAndCrcs"); - await MeadowFileManager.ListFilesAndCrcs(meadow); - - Console.WriteLine("DeleteFile"); - await MeadowFileManager.DeleteFile(meadow, @"hello_meadow.txt"); - - Console.WriteLine("ListFiles"); - await MeadowFileManager.ListFiles(meadow); - - await MeadowFileManager.EraseFlash(meadow); - await MeadowFileManager.VerifyErasedFlash(meadow); - - DeviceManager commands to test - - Console.WriteLine("SetTraceLevel"); - await MeadowDeviceManager.SetTraceLevel(meadow, 1); - - // does not sent Concluded - //Console.WriteLine("ResetMeadow"); - //await MeadowDeviceManager.ResetMeadow(meadow); - - // not implemented - //Console.WriteLine("EnterDfuMode"); - //await MeadowDeviceManager.EnterDfuMode(meadow); - - // request rejected; unknown command - //Console.WriteLine("NshEnable"); - //await MeadowDeviceManager.NshEnable(meadow); - - Console.WriteLine("MonoRunState"); - await MeadowDeviceManager.MonoRunState(meadow); - - Console.WriteLine("GetDeviceInfo"); - await MeadowDeviceManager.GetDeviceInfo(meadow); - - Console.WriteLine("GetDeviceName"); - await MeadowDeviceManager.GetDeviceName(meadow); - - Console.WriteLine("SetDeveloper1"); - await MeadowDeviceManager.SetDeveloper1(meadow, 1); - - Console.WriteLine("SetDeveloper2"); - await MeadowDeviceManager.SetDeveloper2(meadow, 1); - - Console.WriteLine("SetDeveloper3"); - await MeadowDeviceManager.SetDeveloper3(meadow, 1); - - Console.WriteLine("SetDeveloper4"); - await MeadowDeviceManager.SetDeveloper4(meadow, 1); - - Console.WriteLine("TraceDisable"); - await MeadowDeviceManager.TraceDisable(meadow); - - Console.WriteLine("TraceEnable"); - await MeadowDeviceManager.TraceEnable(meadow); - - Console.WriteLine("Uart1Apps"); - await MeadowDeviceManager.Uart1Apps(meadow); - - Console.WriteLine("Uart1Trace"); - await MeadowDeviceManager.Uart1Trace(meadow); - - // restarts device. send reconnect? - //Console.WriteLine("RenewFileSys"); - //await MeadowDeviceManager.RenewFileSys(meadow); - - // request rejected; unknown command - //Console.WriteLine("QspiWrite"); - //await MeadowDeviceManager.QspiWrite(meadow, 1); - - // request rejected; unknown command - //Console.WriteLine("QspiRead"); - //await MeadowDeviceManager.QspiRead(meadow, 1); - - //request rejected; unknown command - //Console.WriteLine("QspiInit"); - //await MeadowDeviceManager.QspiInit(meadow, 1); - - // mono needs to be disabled for the ESP commands - await MeadowDeviceManager.MonoDisable(meadow); - - Console.WriteLine("Esp32ReadMac"); - await MeadowDeviceManager.Esp32ReadMac(meadow); - - Console.WriteLine("Esp32Restart"); - await MeadowDeviceManager.Esp32Restart(meadow); - */ - } -} diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj deleted file mode 100644 index a2d0814d..00000000 --- a/TestApp/TestApp.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - Exe - net5.0 - AnyCPU;x86;x64 - - - - - - - diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml deleted file mode 100644 index 9761b2d7..00000000 --- a/azure-pipelines-release.yml +++ /dev/null @@ -1,52 +0,0 @@ - -trigger: - branches: - exclude: - - '*' - -pr: - branches: - exclude: - - '*' - -variables: - solution: '**/MeadowCLI.sln' - buildPlatform: 'Any CPU' - buildConfiguration: 'Release' - -pool: - vmImage: windows-2019 - -stages: -- stage: Build_Release - jobs: - - job: Create_Release - steps: - - task: NuGetToolInstaller@1 - - task: NuGetCommand@2 - inputs: - feedsToUse: 'select' - restoreSolution: '$(solution)' - - task: VSBuild@1 - inputs: - solution: '$(solution)' - platform: '$(buildPlatform)' - configuration: '$(buildConfiguration)' - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: 'MeadowCLI\bin\Release\net472' - includeRootFolder: false - archiveType: 'zip' - archiveFile: '$(Build.ArtifactStagingDirectory)\Meadow.CLI.$(tagName).zip' - - task: GitHubRelease@1 - inputs: - gitHubConnection: 'github.com_lamebrain' - repositoryName: '$(Build.Repository.Name)' - action: 'create' - target: '$(Build.SourceVersion)' - tagSource: 'userSpecifiedTag' - tag: '$(tagName)' - title: '$(title)' - assets: '$(Build.ArtifactStagingDirectory)\Meadow.CLI.$(tagName).zip' - isPreRelease: true - addChangeLog: false \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 168479a5..00000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,49 +0,0 @@ -# Meadow.CLI pipeline -# Reference: https://aka.ms/yaml - -trigger: - - main - - develop - -variables: - solution: "**/MeadowCLI.sln" - buildPlatform: "Any CPU" - buildConfiguration: "Release" - internalFeedName: "Meadow" - preReleasePackageBranch: "refs/heads/develop" - meadowNugetServiceConnectionName: "Meadow_Nuget" - -pool: - vmImage: windows-2019 - -stages: - - stage: Build - jobs: - - job: Build_Solution - steps: - - task: NuGetToolInstaller@1 - - task: NuGetCommand@2 - inputs: - feedsToUse: "select" - restoreSolution: "$(solution)" - - task: VSBuild@1 - inputs: - solution: "$(solution)" - platform: "$(buildPlatform)" - configuration: "$(buildConfiguration)" - - task: CopyFiles@2 - inputs: - Contents: 'MeadowCLI\bin\Release\net472\*' - TargetFolder: '$(Build.ArtifactStagingDirectory)\Meadow.CLI' - cleanTargetFolder: true - flattenFolders: true - - task: CopyFiles@2 - inputs: - Contents: '**\*.nupkg' - TargetFolder: "$(Build.ArtifactStagingDirectory)" - cleanTargetFolder: false - flattenFolders: true - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: "$(Build.ArtifactStagingDirectory)" - artifactName: artifacts diff --git a/build.sh b/build.sh deleted file mode 100755 index 2353252b..00000000 --- a/build.sh +++ /dev/null @@ -1,27 +0,0 @@ -scriptdir="$( cd "$(dirname "$0")" ; pwd -P )" - -SLN=$scriptdir/MeadowCLI.sln - -NUGET=nuget -if [[ $(command -v nuget) == "" ]]; then - NUGET=/Library/Frameworks/Mono.framework/Versions/Current/bin/nuget -fi - -$NUGET restore $SLN - -UNAMECMD=`uname` -if [[ "$UNAMECMD" == "Darwin" ]]; then - echo "Mac OS detected, using MSBuild from Visual Studio." - MSBUILD="mono '/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/msbuild.dll'" -else - echo "Unknown OS, defaulting to msbuild." - MSBUILD=msbuild -fi - - -if [[ $(command -v msbuild) == "" ]]; then - MSBUILD=/Library/Frameworks/Mono.framework/Versions/Current/bin/msbuild -fi - -eval $MSBUILD /t:restore $SLN -eval $MSBUILD $SLN \ No newline at end of file