Skip to content

Commit 93253da

Browse files
committed
Add console command
1 parent 8154f68 commit 93253da

File tree

4 files changed

+128
-28
lines changed

4 files changed

+128
-28
lines changed

minitool/Commands/Console.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using CommandLine.Text;
2+
using CommandLine;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using minitool.Enums;
9+
using minitool.Models;
10+
using System.IO.Ports;
11+
12+
namespace minitool.Commands;
13+
14+
public static class Console_
15+
{
16+
[Verb("console", HelpText = "Opens a raw command console for the specified minipad.")]
17+
public class Options
18+
{
19+
[Value(0, Required = true, HelpText = "The port number of the minipad.")]
20+
public int Port { get; private set; }
21+
22+
public Options() { }
23+
}
24+
25+
public static int Handle(Options options)
26+
{
27+
MinipadDevice device;
28+
try
29+
{
30+
// Get the minipad device from the port.
31+
device = MinipadHelper.GetDeviceAsync(options.Port).Result;
32+
}
33+
catch (Exception ex)
34+
{
35+
// If any error occured, output it to the user.
36+
Console.ForegroundColor = ConsoleColor.Red;
37+
Console.WriteLine($"Error: {ex.InnerException!.Message}");
38+
Console.WriteLine(ex.InnerException!.StackTrace);
39+
Console.ForegroundColor = ConsoleColor.Gray;
40+
return 3;
41+
}
42+
43+
// Just output the state of the device if it's not connected.
44+
if (device.State == DeviceState.DISCONNECTED)
45+
{
46+
Console.Write($"The minipad on COM{options.Port} is currently ");
47+
Console.ForegroundColor = ConsoleColor.Red;
48+
Console.WriteLine("disconneted");
49+
Console.ForegroundColor = ConsoleColor.Gray;
50+
return 2;
51+
}
52+
else if (device.State == DeviceState.BUSY)
53+
{
54+
Console.Write($"The minipad on COM{options.Port} is currently ");
55+
Console.ForegroundColor = ConsoleColor.Yellow;
56+
Console.WriteLine("busy");
57+
Console.ForegroundColor = ConsoleColor.Gray;
58+
return 1;
59+
}
60+
61+
// Keep a serial port opened through-out the console session to block other applications from using it.
62+
SerialPort port = MinipadHelper.Open(device.PortName);
63+
64+
// Ask for user input in a loop and only exit if the user types an exit keyword.
65+
string input = "";
66+
while(true)
67+
{
68+
// Ask for user input.
69+
Console.Write($"{device.Configuration.Name} ({device.PortName})> ");
70+
input = Console.ReadLine()!;
71+
72+
// If the user typed an exit keyword, exit the loop.
73+
if (input is "exit" or "q" or "quit")
74+
break;
75+
76+
// Try to send the command to the minipad.
77+
try
78+
{
79+
port.WriteLine(input);
80+
}
81+
catch (Exception ex)
82+
{
83+
// If any error occured, output it to the user.
84+
Console.ForegroundColor = ConsoleColor.Red;
85+
Console.Write("Error: ");
86+
Console.WriteLine($"{ex.InnerException!.Message}");
87+
Console.ForegroundColor = ConsoleColor.Gray;
88+
}
89+
}
90+
91+
// Close the serial port and return 0 exit code for success.
92+
port.Close();
93+
return 0;
94+
}
95+
}

minitool/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ public static void Main(string[] args)
3131
{
3232
x.EnableDashDash = true;
3333
x.HelpWriter = Console.Out;
34-
}).ParseArguments<Devices.Options, Info.Options, Boot.Options, Send.Options, Calibrate.Options, Visualize.Options, Flash.Options>(args).MapResult(
34+
}).ParseArguments<Devices.Options, Info.Options, Boot.Options, Send.Options, Calibrate.Options, Visualize.Options, Flash.Options, Console_.Options>(args).MapResult(
3535
(Devices.Options o) => Devices.Handle(o),
3636
(Info.Options o) => Info.Handle(o),
3737
(Boot.Options o) => Boot.Handle(o),
3838
(Send.Options o) => Send.Handle(o),
3939
(Calibrate.Options o) => Calibrate.Handle(o),
4040
(Visualize.Options o) => Visualize.Handle(o),
4141
(Flash.Options o) => Flash.Handle(o),
42+
(Console_.Options o) => Console_.Handle(o),
4243
Error);
4344
}
4445

minitool/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"minitool": {
44
"commandName": "Project",
5-
"commandLineArgs": "visualize 37"
5+
"commandLineArgs": "console 4"
66
}
77
}
88
}

minitool/Utils/MinipadHelper.cs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Diagnostics;
22
using System.IO.Ports;
33
using System.Reflection;
4+
using System.Reflection.Metadata.Ecma335;
45
using minitool.Enums;
56
using minitool.Models;
67

@@ -11,20 +12,29 @@ namespace minitool;
1112
/// </summary>
1213
public static class MinipadHelper
1314
{
15+
public static SerialPort Open(string portName)
16+
{
17+
// Create the SerialPort instance with the correct settings.
18+
SerialPort port = new SerialPort(portName, 115200, Parity.Even, 8, StopBits.One);
19+
port.RtsEnable = true;
20+
port.DtrEnable = true;
21+
22+
// Open the port and return it.
23+
port.Open();
24+
return port;
25+
}
26+
1427
public static void Send(MinipadDevice device, params string[] commands)
1528
{
1629
// Open the serial port.
17-
SerialPort serialPort = new SerialPort(device.PortName, 115200, Parity.Even, 8, StopBits.One);
18-
serialPort.RtsEnable = true;
19-
serialPort.DtrEnable = true;
20-
serialPort.Open();
30+
SerialPort port = Open(device.PortName);
2131

2232
// Write all specified commands to the serial interface.
2333
foreach (string command in commands)
24-
serialPort.WriteLine(command);
34+
port.WriteLine(command);
2535

2636
// Safely close the serial port for usage by other processes.
27-
serialPort.Close();
37+
port.Close();
2838
}
2939

3040
public static (int[] raw, int[] mapped) GetSensorValues(MinipadDevice device)
@@ -38,9 +48,7 @@ public static (int[] raw, int[] mapped) GetSensorValues(MinipadDevice device)
3848
mappedValues[i] = -1;
3949
}
4050

41-
SerialPort port = new SerialPort(device.PortName, 115200, Parity.None, 8, StopBits.One);
42-
port.RtsEnable = true;
43-
port.DtrEnable = true;
51+
SerialPort port = Open(device.PortName);
4452
port.DataReceived += (sender, e) =>
4553
{
4654
lock (port)
@@ -63,8 +71,7 @@ public static (int[] raw, int[] mapped) GetSensorValues(MinipadDevice device)
6371
}
6472
};
6573

66-
// Open the port, send the out command, wait until no value in the array is -1 anymore and safely close it.
67-
port.Open();
74+
// Send the out command, wait until no value in the array is -1 anymore and safely close it.
6875
port.WriteLine("out");
6976
while (rawValues.Any(x => x == -1))
7077
;
@@ -75,15 +82,12 @@ public static (int[] raw, int[] mapped) GetSensorValues(MinipadDevice device)
7582
return (rawValues, mappedValues);
7683
}
7784

78-
public static async Task<MinipadDevice> GetDeviceAsync(int port)
85+
public static async Task<MinipadDevice> GetDeviceAsync(int portNumber)
7986
{
8087
try
8188
{
8289
// Open the serial port.
83-
SerialPort serialPort = new SerialPort($"COM{port}", 115200, Parity.Even, 8, StopBits.One);
84-
serialPort.RtsEnable = true;
85-
serialPort.DtrEnable = true;
86-
serialPort.Open();
90+
SerialPort port = Open($"COM{portNumber}");
8791

8892
// Create a semaphore for timeouting the serial data reading.
8993
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0);
@@ -93,13 +97,13 @@ public static async Task<MinipadDevice> GetDeviceAsync(int port)
9397
void DataReceivedCallback(object sender, SerialDataReceivedEventArgs e)
9498
{
9599
// Lock the serial port to make sure it's not being closed when the 200ms timeout runs out.
96-
lock (serialPort)
100+
lock (port)
97101
{
98102
// Read the data all the way to the end, line by line.
99-
while (serialPort.BytesToRead > 0)
103+
while (port.BytesToRead > 0)
100104
{
101105
// Read the next line.
102-
string line = serialPort.ReadLine().TrimEnd('\r');
106+
string line = port.ReadLine().TrimEnd('\r');
103107

104108
// If the end of the 'get' command was reached (indicated by "GET END"), release the semaphore thus returning.
105109
if (line == "GET END")
@@ -116,15 +120,15 @@ void DataReceivedCallback(object sender, SerialDataReceivedEventArgs e)
116120
}
117121

118122
// Subscribe to the callback method, write the 'get' command that returns the keypad specifications.
119-
serialPort.DataReceived += DataReceivedCallback;
120-
serialPort.WriteLine("get");
123+
port.DataReceived += DataReceivedCallback;
124+
port.WriteLine("get");
121125

122126
// Give the response 200ms until this reading process times out.
123127
await semaphoreSlim.WaitAsync(10);
124128

125129
// Safely close the serial port for usage by other processes.
126-
lock (serialPort)
127-
serialPort.Close();
130+
lock (port)
131+
port.Close();
128132

129133
// Create a Configuration object from the retrieved values, starting with the global settings.
130134
Configuration configuration = new Configuration()
@@ -165,17 +169,17 @@ void DataReceivedCallback(object sender, SerialDataReceivedEventArgs e)
165169
};
166170

167171
// Create a MinipadDevice object with the parsed info and return it.
168-
return new MinipadDevice(port, DeviceState.CONNECTED, values.ContainsKey("version") ? values["version"] : null, configuration);
172+
return new MinipadDevice(portNumber, DeviceState.CONNECTED, values.ContainsKey("version") ? values["version"] : null, configuration);
169173
}
170174
catch (UnauthorizedAccessException)
171175
{
172176
// If an UnauthorizedAccessException was thrown, the device is connected but the serial interface occupied by another process.
173-
return new MinipadDevice(port, DeviceState.BUSY, null, new Configuration());
177+
return new MinipadDevice(portNumber, DeviceState.BUSY, null, new Configuration());
174178
}
175179
catch (FileNotFoundException)
176180
{
177181
// If a FileNotFoundException was thrown, the device is disconnected.
178-
return new MinipadDevice(port, DeviceState.DISCONNECTED, null, new Configuration());
182+
return new MinipadDevice(portNumber, DeviceState.DISCONNECTED, null, new Configuration());
179183
}
180184
}
181185

0 commit comments

Comments
 (0)