Skip to content

Commit 53c15cd

Browse files
committed
Fixes
1 parent 1a62342 commit 53c15cd

File tree

6 files changed

+233
-78
lines changed

6 files changed

+233
-78
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Meshtastic.Data;
2+
using Meshtastic.Data.MessageFactories;
3+
using Meshtastic.Protobufs;
4+
using Microsoft.Extensions.Logging;
5+
6+
namespace Meshtastic.Cli.CommandHandlers;
7+
8+
public class SendInputEventCommandHandler : DeviceCommandHandler
9+
{
10+
private readonly uint eventCode;
11+
private readonly uint? kbChar;
12+
private readonly uint? touchX;
13+
private readonly uint? touchY;
14+
15+
public SendInputEventCommandHandler(uint eventCode,
16+
uint? kbChar,
17+
uint? touchX,
18+
uint? touchY,
19+
DeviceConnectionContext context,
20+
CommandContext commandContext) : base(context, commandContext)
21+
{
22+
this.eventCode = eventCode;
23+
this.kbChar = kbChar;
24+
this.touchX = touchX;
25+
this.touchY = touchY;
26+
}
27+
28+
public async Task<DeviceStateContainer> Handle()
29+
{
30+
var wantConfig = new ToRadioMessageFactory().CreateWantConfigMessage();
31+
var container = await Connection.WriteToRadio(wantConfig, CompleteOnConfigReceived);
32+
Connection.Disconnect();
33+
return container;
34+
}
35+
36+
public override async Task OnCompleted(FromRadio packet, DeviceStateContainer container)
37+
{
38+
var adminMessageFactory = new AdminMessageFactory(container, Destination);
39+
40+
var inputEvent = new AdminMessage.Types.InputEvent()
41+
{
42+
EventCode = eventCode
43+
};
44+
45+
if (kbChar.HasValue)
46+
inputEvent.KbChar = kbChar.Value;
47+
48+
if (touchX.HasValue)
49+
inputEvent.TouchX = touchX.Value;
50+
51+
if (touchY.HasValue)
52+
inputEvent.TouchY = touchY.Value;
53+
54+
Logger.LogInformation($"Sending input event (code: {eventCode}) to device...");
55+
var adminMessage = adminMessageFactory.CreateSendInputEventMessage(inputEvent);
56+
await Connection.WriteToRadio(ToRadioMessageFactory.CreateMeshPacketMessage(adminMessage), AnyResponseReceived);
57+
}
58+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Meshtastic.Cli.Binders;
2+
using Meshtastic.Cli.CommandHandlers;
3+
using Meshtastic.Cli.Enums;
4+
using Microsoft.Extensions.Logging;
5+
6+
namespace Meshtastic.Cli.Commands;
7+
8+
public class SendInputEventCommand : Command
9+
{
10+
public SendInputEventCommand(string name, string description, Option<string> port, Option<string> host,
11+
Option<OutputFormat> output, Option<LogLevel> log, Option<uint?> dest, Option<bool> selectDest) : base(name, description)
12+
{
13+
var eventCodeArg = new Argument<uint>("event-code", description: "The input event code");
14+
AddArgument(eventCodeArg);
15+
16+
var kbCharOption = new Option<uint?>("--kb-char", description: "Keyboard character code");
17+
AddOption(kbCharOption);
18+
19+
var touchXOption = new Option<uint?>("--touch-x", description: "Touch X coordinate");
20+
AddOption(touchXOption);
21+
22+
var touchYOption = new Option<uint?>("--touch-y", description: "Touch Y coordinate");
23+
AddOption(touchYOption);
24+
25+
this.SetHandler(async (eventCode, kbChar, touchX, touchY, context, commandContext) =>
26+
{
27+
var handler = new SendInputEventCommandHandler(eventCode, kbChar, touchX, touchY, context, commandContext);
28+
await handler.Handle();
29+
},
30+
eventCodeArg,
31+
kbCharOption,
32+
touchXOption,
33+
touchYOption,
34+
new DeviceConnectionBinder(port, host),
35+
new CommandContextBinder(log, output, dest, selectDest));
36+
}
37+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Meshtastic.Cli.Commands;
2+
using System.CommandLine;
3+
4+
namespace Meshtastic.Test.Commands;
5+
6+
[TestFixture]
7+
public class SendInputEventCommandTests : CommandTestBase
8+
{
9+
private RootCommand rootCommand;
10+
11+
[SetUp]
12+
public void Setup()
13+
{
14+
rootCommand = GetRootCommand();
15+
var command = new SendInputEventCommand("input-event", "input-event description", portOption, hostOption, outputOption, logLevelOption, destOption, selectDestOption);
16+
rootCommand.AddCommand(command);
17+
}
18+
19+
[Test]
20+
public async Task SendInputEventCommand_Should_Fail_ForMissingEventCode()
21+
{
22+
var result = await rootCommand.InvokeAsync("input-event --port SIMPORT", Console);
23+
result.Should().BeGreaterThan(0);
24+
Out.Output.Should().Contain("Required argument missing for command: 'input-event'");
25+
}
26+
27+
[Test]
28+
public async Task SendInputEventCommand_Should_Succeed_ForValidEventCode()
29+
{
30+
var result = await rootCommand.InvokeAsync("input-event 1 --port SIMPORT", Console);
31+
result.Should().Be(0);
32+
}
33+
34+
[Test]
35+
public async Task SendInputEventCommand_Should_Succeed_WithAllOptions()
36+
{
37+
var result = await rootCommand.InvokeAsync("input-event 1 --kb-char 65 --touch-x 100 --touch-y 200 --port SIMPORT", Console);
38+
result.Should().Be(0);
39+
}
40+
}

Meshtastic.Test/Data/AdminMessageFactoryTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,19 @@ public void CreateGetCannedMessage_Should_ReturnValidAdminMessage()
150150
var result = factory.CreateGetCannedMessage();
151151
result.Decoded.Portnum.Should().Be(PortNum.AdminApp);
152152
}
153+
154+
[Test]
155+
public void CreateSendInputEventMessage_Should_ReturnValidAdminMessage()
156+
{
157+
var inputEvent = new AdminMessage.Types.InputEvent()
158+
{
159+
EventCode = 1,
160+
KbChar = 65,
161+
TouchX = 100,
162+
TouchY = 200
163+
};
164+
165+
var result = factory.CreateSendInputEventMessage(inputEvent);
166+
result.Decoded.Portnum.Should().Be(PortNum.AdminApp);
167+
}
153168
}
Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,87 @@
1-
using System;
2-
using System.Threading.Tasks;
3-
using Microsoft.Extensions.Logging;
4-
using InTheHand.BluetoothLE;
5-
using System.Collections.Generic;
1+
// using System;
2+
// using System.Threading.Tasks;
3+
// using Microsoft.Extensions.Logging;
4+
// using InTheHand.BluetoothLE;
5+
// using System.Collections.Generic;
66

7-
namespace Meshtastic.Connections;
7+
// namespace Meshtastic.Connections;
88

9-
// Placeholder for BluetoothConnection using Plugin.BLE or similar library
10-
public class BluetoothConnection : DeviceConnection
11-
{
12-
private IDevice? _device;
13-
private IGattCharacteristic? _writeCharacteristic;
14-
private IGattCharacteristic? _readCharacteristic;
15-
private BluetoothLEScan? _scan;
9+
// // Placeholder for BluetoothConnection using Plugin.BLE or similar library
10+
// public class BluetoothConnection : DeviceConnection
11+
// {
12+
// private IDevice? _device;
13+
// private IGattCharacteristic? _writeCharacteristic;
14+
// private IGattCharacteristic? _readCharacteristic;
15+
// private BluetoothLEScan? _scan;
1616

17-
public BluetoothConnection(ILogger logger) : base(logger) { }
17+
// public BluetoothConnection(ILogger logger) : base(logger) { }
1818

19-
// Example: Discover and connect to a device by name (adjust as needed)
20-
public async Task<bool> ConnectAsync(string deviceName)
21-
{
22-
var devices = new List<IDevice>();
23-
_scan = Bluetooth.ScanForDevices(async dev =>
24-
{
25-
if (dev.Name == deviceName)
26-
{
27-
devices.Add(dev);
28-
await _scan.StopAsync();
29-
}
30-
});
31-
await _scan.Task;
32-
if (devices.Count == 0) return false;
33-
_device = devices[0];
34-
await _device.Gatt.ConnectAsync();
35-
// TODO: Discover and assign _writeCharacteristic and _readCharacteristic
36-
return true;
37-
}
19+
// // Example: Discover and connect to a device by name (adjust as needed)
20+
// public async Task<bool> ConnectAsync(string deviceName)
21+
// {
22+
// var devices = new List<IDevice>();
23+
// _scan = Bluetooth.ScanForDevices(async dev =>
24+
// {
25+
// if (dev.Name == deviceName)
26+
// {
27+
// devices.Add(dev);
28+
// await _scan.StopAsync();
29+
// }
30+
// });
31+
// await _scan.Task;
32+
// if (devices.Count == 0) return false;
33+
// _device = devices[0];
34+
// await _device.Gatt.ConnectAsync();
35+
// // TODO: Discover and assign _writeCharacteristic and _readCharacteristic
36+
// return true;
37+
// }
3838

39-
public async Task<bool> DiscoverCharacteristicsAsync(Guid serviceUuid, Guid writeCharUuid, Guid readCharUuid)
40-
{
41-
if (_device == null) throw new InvalidOperationException("Device not connected.");
42-
var services = await _device.Gatt.GetPrimaryServicesAsync();
43-
var service = services?.Find(s => s.Uuid == serviceUuid);
44-
if (service == null) return false;
45-
var characteristics = await service.GetCharacteristicsAsync();
46-
_writeCharacteristic = characteristics?.Find(c => c.Uuid == writeCharUuid);
47-
_readCharacteristic = characteristics?.Find(c => c.Uuid == readCharUuid);
48-
return _writeCharacteristic != null && _readCharacteristic != null;
49-
}
39+
// public async Task<bool> DiscoverCharacteristicsAsync(Guid serviceUuid, Guid writeCharUuid, Guid readCharUuid)
40+
// {
41+
// if (_device == null) throw new InvalidOperationException("Device not connected.");
42+
// var services = await _device.Gatt.GetPrimaryServicesAsync();
43+
// var service = services?.Find(s => s.Uuid == serviceUuid);
44+
// if (service == null) return false;
45+
// var characteristics = await service.GetCharacteristicsAsync();
46+
// _writeCharacteristic = characteristics?.Find(c => c.Uuid == writeCharUuid);
47+
// _readCharacteristic = characteristics?.Find(c => c.Uuid == readCharUuid);
48+
// return _writeCharacteristic != null && _readCharacteristic != null;
49+
// }
5050

51-
public override async Task<DeviceStateContainer> WriteToRadio(ToRadio toRadio, Func<FromRadio, DeviceStateContainer, Task<bool>> isComplete)
52-
{
53-
if (_writeCharacteristic == null) throw new InvalidOperationException("Not connected to a Bluetooth device.");
54-
var data = toRadio.ToByteArray();
55-
await _writeCharacteristic.WriteValueWithResponseAsync(data);
56-
// Optionally, wait for a response using ReadFromRadio
57-
return DeviceStateContainer;
58-
}
51+
// public override async Task<DeviceStateContainer> WriteToRadio(ToRadio toRadio, Func<FromRadio, DeviceStateContainer, Task<bool>> isComplete)
52+
// {
53+
// if (_writeCharacteristic == null) throw new InvalidOperationException("Not connected to a Bluetooth device.");
54+
// var data = toRadio.ToByteArray();
55+
// await _writeCharacteristic.WriteValueWithResponseAsync(data);
56+
// // Optionally, wait for a response using ReadFromRadio
57+
// return DeviceStateContainer;
58+
// }
5959

60-
public override async Task WriteToRadio(ToRadio toRadio)
61-
{
62-
if (_writeCharacteristic == null) throw new InvalidOperationException("Not connected to a Bluetooth device.");
63-
var data = toRadio.ToByteArray();
64-
await _writeCharacteristic.WriteValueWithResponseAsync(data);
65-
}
60+
// public override async Task WriteToRadio(ToRadio toRadio)
61+
// {
62+
// if (_writeCharacteristic == null) throw new InvalidOperationException("Not connected to a Bluetooth device.");
63+
// var data = toRadio.ToByteArray();
64+
// await _writeCharacteristic.WriteValueWithResponseAsync(data);
65+
// }
6666

67-
public override void Disconnect()
68-
{
69-
_device?.Gatt.Disconnect();
70-
_device = null;
71-
_writeCharacteristic = null;
72-
_readCharacteristic = null;
73-
}
67+
// public override void Disconnect()
68+
// {
69+
// _device?.Gatt.Disconnect();
70+
// _device = null;
71+
// _writeCharacteristic = null;
72+
// _readCharacteristic = null;
73+
// }
7474

75-
public override async Task ReadFromRadio(Func<FromRadio?, DeviceStateContainer, Task<bool>> isComplete, int readTimeoutMs = Resources.DEFAULT_READ_TIMEOUT)
76-
{
77-
if (_readCharacteristic == null) throw new InvalidOperationException("Not connected to a Bluetooth device.");
78-
var value = await _readCharacteristic.ReadValueAsync();
79-
if (value != null && value.Length > 0)
80-
{
81-
// Example: parse value into FromRadio
82-
var fromRadioMsg = new FromDeviceMessage(Logger);
83-
var fromRadio = fromRadioMsg.ParsedFromRadio(value);
84-
await isComplete(fromRadio, DeviceStateContainer);
85-
}
86-
}
87-
}
75+
// public override async Task ReadFromRadio(Func<FromRadio?, DeviceStateContainer, Task<bool>> isComplete, int readTimeoutMs = Resources.DEFAULT_READ_TIMEOUT)
76+
// {
77+
// if (_readCharacteristic == null) throw new InvalidOperationException("Not connected to a Bluetooth device.");
78+
// var value = await _readCharacteristic.ReadValueAsync();
79+
// if (value != null && value.Length > 0)
80+
// {
81+
// // Example: parse value into FromRadio
82+
// var fromRadioMsg = new FromDeviceMessage(Logger);
83+
// var fromRadio = fromRadioMsg.ParsedFromRadio(value);
84+
// await isComplete(fromRadio, DeviceStateContainer);
85+
// }
86+
// }
87+
// }

Meshtastic/Data/MessageFactories/AdminMessageFactory.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,9 @@ public MeshPacket RemovedFixedPositionMessage()
156156
{
157157
return GetNewMeshPacket(new AdminMessage() { RemoveFixedPosition = true });
158158
}
159+
160+
public MeshPacket CreateSendInputEventMessage(AdminMessage.Types.InputEvent inputEvent)
161+
{
162+
return GetNewMeshPacket(new AdminMessage() { SendInputEvent = inputEvent });
163+
}
159164
}

0 commit comments

Comments
 (0)