meshtastic 0.0.179 → 0.0.180
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/documentation/README.md +3 -2
- data/documentation/admin-channel.md +33 -0
- data/documentation/admin-config.md +28 -0
- data/documentation/admin-firmware.md +69 -0
- data/documentation/admin.md +2 -1
- data/documentation/atak.md +93 -10
- data/documentation/channel.md +1 -28
- data/documentation/config.md +1 -27
- data/documentation/meshtastic.md +2 -2
- data/lib/meshtastic/admin/channel.rb +90 -0
- data/lib/meshtastic/admin/config.rb +154 -0
- data/lib/meshtastic/admin/firmware.rb +173 -0
- data/lib/meshtastic/admin.rb +458 -28
- data/lib/meshtastic/apponly.rb +19 -7
- data/lib/meshtastic/atak.rb +295 -17
- data/lib/meshtastic/bluetooth/bluez.rb +20 -1
- data/lib/meshtastic/bluetooth.rb +70 -59
- data/lib/meshtastic/cannedmessages.rb +13 -6
- data/lib/meshtastic/channel.rb +3 -25
- data/lib/meshtastic/clientonly.rb +19 -7
- data/lib/meshtastic/config.rb +3 -24
- data/lib/meshtastic/connection_status.rb +12 -5
- data/lib/meshtastic/deviceonly.rb +19 -7
- data/lib/meshtastic/localonly.rb +19 -7
- data/lib/meshtastic/mesh_interface.rb +11 -0
- data/lib/meshtastic/module_config.rb +13 -7
- data/lib/meshtastic/mqtt.rb +72 -35
- data/lib/meshtastic/paxcount.rb +17 -6
- data/lib/meshtastic/portnums.rb +13 -6
- data/lib/meshtastic/position.rb +16 -6
- data/lib/meshtastic/remote_hardware.rb +27 -11
- data/lib/meshtastic/rtttl.rb +17 -8
- data/lib/meshtastic/serial.rb +81 -70
- data/lib/meshtastic/storeforward.rb +13 -6
- data/lib/meshtastic/stream_interface.rb +11 -0
- data/lib/meshtastic/tcp.rb +73 -22
- data/lib/meshtastic/telemetry.rb +15 -6
- data/lib/meshtastic/traceroute.rb +15 -6
- data/lib/meshtastic/util.rb +3 -1
- data/lib/meshtastic/version.rb +1 -1
- data/lib/meshtastic/xmodem.rb +12 -5
- data/lib/meshtastic.rb +22 -3
- data/spec/conventions_spec.rb +321 -0
- data/spec/lib/meshtastic/admin/channel_spec.rb +45 -0
- data/spec/lib/meshtastic/admin/config_spec.rb +48 -0
- data/spec/lib/meshtastic/admin/firmware_spec.rb +118 -0
- data/spec/lib/meshtastic/admin_spec.rb +40 -0
- data/spec/lib/meshtastic/apponly_spec.rb +1 -1
- data/spec/lib/meshtastic/atak_spec.rb +129 -4
- data/spec/lib/meshtastic/bluetooth_spec.rb +1 -1
- data/spec/lib/meshtastic/channel_spec.rb +2 -20
- data/spec/lib/meshtastic/config_spec.rb +2 -20
- data/spec/lib/meshtastic/connection_status_spec.rb +1 -1
- data/spec/lib/meshtastic/deviceonly_spec.rb +1 -1
- data/spec/lib/meshtastic/localonly_spec.rb +1 -1
- data/spec/lib/meshtastic/portnums_spec.rb +2 -2
- metadata +11 -1
|
@@ -16,13 +16,138 @@ describe Meshtastic::ATAK do
|
|
|
16
16
|
{ serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
serial_obj = fake_serial_obj
|
|
21
|
-
described_class.send(serial_obj: serial_obj, message: 'ATAK chat')
|
|
19
|
+
def decode_to_radio(serial_obj)
|
|
22
20
|
frame = serial_obj[:written]
|
|
23
|
-
|
|
21
|
+
body = frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))
|
|
22
|
+
Meshtastic::ToRadio.decode(body).packet
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'encodes V1 GeoChat with contact, group, and status' do
|
|
26
|
+
packet = described_class.encode_v1(
|
|
27
|
+
message: 'ATAK chat',
|
|
28
|
+
to: 'ANDROID-aabbccdd',
|
|
29
|
+
callsign: 'ALPHA',
|
|
30
|
+
device_callsign: 'RADIO-1',
|
|
31
|
+
team: :Cyan,
|
|
32
|
+
role: :TeamMember,
|
|
33
|
+
battery: 87
|
|
34
|
+
)
|
|
35
|
+
expect(packet).to be_a(Meshtastic::TAKPacket)
|
|
36
|
+
expect(packet.chat.message).to eq('ATAK chat')
|
|
37
|
+
expect(packet.chat.to).to eq('ANDROID-aabbccdd')
|
|
38
|
+
expect(packet.contact.callsign).to eq('ALPHA')
|
|
39
|
+
expect(packet.group.team).to eq(:Cyan)
|
|
40
|
+
expect(packet.group.role).to eq(:TeamMember)
|
|
41
|
+
expect(packet.status.battery).to eq(87)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'encodes V1 PLI with 1e7-scaled coordinates' do
|
|
45
|
+
packet = described_class.encode_v1(
|
|
46
|
+
lat: 37.7749,
|
|
47
|
+
lon: -122.4194,
|
|
48
|
+
altitude: 12,
|
|
49
|
+
speed: 3,
|
|
50
|
+
course: 90
|
|
51
|
+
)
|
|
52
|
+
expect(packet.pli.latitude_i).to eq(377_749_000)
|
|
53
|
+
expect(packet.pli.longitude_i).to eq(-1_224_194_000)
|
|
54
|
+
expect(packet.pli.altitude).to eq(12)
|
|
55
|
+
expect(packet.pli.speed).to eq(3)
|
|
56
|
+
expect(packet.pli.course).to eq(90)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'sends V1 GeoChat on ATAK_PLUGIN' do
|
|
60
|
+
serial_obj = fake_serial_obj
|
|
61
|
+
described_class.send_chat(serial_obj: serial_obj, message: 'ATAK chat')
|
|
62
|
+
packet = decode_to_radio(serial_obj)
|
|
24
63
|
expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
|
|
25
64
|
tak = Meshtastic::TAKPacket.decode(packet.decoded.payload)
|
|
26
65
|
expect(tak.chat.message).to eq('ATAK chat')
|
|
27
66
|
end
|
|
67
|
+
|
|
68
|
+
it 'sends V1 PLI on ATAK_PLUGIN' do
|
|
69
|
+
serial_obj = fake_serial_obj
|
|
70
|
+
described_class.send_pli(serial_obj: serial_obj, lat: 37.7749, lon: -122.4194)
|
|
71
|
+
packet = decode_to_radio(serial_obj)
|
|
72
|
+
expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
|
|
73
|
+
tak = Meshtastic::TAKPacket.decode(packet.decoded.payload)
|
|
74
|
+
expect(tak.pli.latitude_i).to eq(377_749_000)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'encodes uncompressed V2 GeoChat wire frames with flags 0xFF' do
|
|
78
|
+
wire = described_class.encode_v2(
|
|
79
|
+
callsign: 'ALPHA',
|
|
80
|
+
team: :Cyan,
|
|
81
|
+
role: :TeamMember,
|
|
82
|
+
lat: 37.7749,
|
|
83
|
+
lon: -122.4194,
|
|
84
|
+
message: 'v2 chat'
|
|
85
|
+
)
|
|
86
|
+
expect(wire.getbyte(0)).to eq(0xFF)
|
|
87
|
+
v2 = Meshtastic::TAKPacketV2.decode(wire.byteslice(1..))
|
|
88
|
+
expect(v2.chat.message).to eq('v2 chat')
|
|
89
|
+
expect(v2.callsign).to eq('ALPHA')
|
|
90
|
+
expect(v2.latitude_i).to eq(377_749_000)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'round-trips V2 typed payloads' do
|
|
94
|
+
{
|
|
95
|
+
aircraft: Meshtastic::AircraftTrack.new(icao: 'ABC123', flight: 'N1'),
|
|
96
|
+
shape: Meshtastic::DrawnShape.new(kind: :Kind_Circle, major_cm: 1000),
|
|
97
|
+
marker: Meshtastic::Marker.new(kind: :Kind_Spot),
|
|
98
|
+
route: Meshtastic::Route.new(prefix: 'R1'),
|
|
99
|
+
casevac: Meshtastic::CasevacReport.new(title: 'CASEVAC'),
|
|
100
|
+
emergency: Meshtastic::EmergencyAlert.new(type: :Type_Alert911),
|
|
101
|
+
task: Meshtastic::TaskRequest.new(task_type: 'recon', note: 'look'),
|
|
102
|
+
taktalk: Meshtastic::TakTalkMessage.new(text: 'voice', chatroom_id: 'room1'),
|
|
103
|
+
taktalk_room: Meshtastic::TakTalkRoomData.new(room_id: 'room1', room_name: 'Ops'),
|
|
104
|
+
rab: Meshtastic::RangeAndBearing.new(range_cm: 500)
|
|
105
|
+
}.each do |field, value|
|
|
106
|
+
v2 = described_class.build_v2(field => value, callsign: 'ALPHA')
|
|
107
|
+
expect(v2.public_send(field)).to eq(value)
|
|
108
|
+
decoded = described_class.decode_v2(wire: described_class.wrap_v2(packet: v2))
|
|
109
|
+
expect(decoded.public_send(field).to_h).to eq(value.to_h)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'sends V2 packets on ATAK_PLUGIN_V2' do
|
|
114
|
+
serial_obj = fake_serial_obj
|
|
115
|
+
described_class.send_v2(serial_obj: serial_obj, message: 'v2 chat', callsign: 'ALPHA')
|
|
116
|
+
packet = decode_to_radio(serial_obj)
|
|
117
|
+
expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN_V2)
|
|
118
|
+
decoded = described_class.decode_v2(payload: packet.decoded.payload)
|
|
119
|
+
expect(decoded.chat.message).to eq('v2 chat')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'zlib-compresses CoT XML on ATAK_FORWARDER' do
|
|
123
|
+
serial_obj = fake_serial_obj
|
|
124
|
+
cot = '<event type="b-m-p-s-m" uid="marker-1"><point lat="37.77" lon="-122.41"/></event>'
|
|
125
|
+
described_class.send_cot(serial_obj: serial_obj, cot: cot)
|
|
126
|
+
packet = decode_to_radio(serial_obj)
|
|
127
|
+
expect(packet.decoded.portnum).to eq(:ATAK_FORWARDER)
|
|
128
|
+
xml = described_class.decompress_cot(payload: packet.decoded.payload)
|
|
129
|
+
expect(xml).to include('marker-1')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'decodes inbound payloads by portnum' do
|
|
133
|
+
v1 = described_class.encode_v1(message: 'hi')
|
|
134
|
+
expect(described_class.decode(payload: v1.to_proto, portnum: :ATAK_PLUGIN).chat.message).to eq('hi')
|
|
135
|
+
|
|
136
|
+
v2 = described_class.encode_v2(message: 'v2')
|
|
137
|
+
expect(described_class.decode(payload: v2, portnum: :ATAK_PLUGIN_V2).chat.message).to eq('v2')
|
|
138
|
+
|
|
139
|
+
cot = described_class.compress_cot(cot: '<event uid="x"/>')
|
|
140
|
+
expect(described_class.decode(payload: cot, portnum: :ATAK_FORWARDER)).to include('uid="x"')
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'keeps send as a V1 GeoChat alias' do
|
|
144
|
+
serial_obj = fake_serial_obj
|
|
145
|
+
described_class.send(serial_obj: serial_obj, message: 'ATAK chat')
|
|
146
|
+
packet = decode_to_radio(serial_obj)
|
|
147
|
+
expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it 'prints usage without raising' do
|
|
151
|
+
expect { described_class.help }.to output(/ATAK_PLUGIN_V2/).to_stdout
|
|
152
|
+
end
|
|
28
153
|
end
|
|
@@ -136,7 +136,7 @@ describe Meshtastic::Bluetooth do
|
|
|
136
136
|
|
|
137
137
|
it 'scans with the selected adapter and bounded discovery timeout' do
|
|
138
138
|
devices = [{ address: 'AA:BB:CC:DD:EE:FF', name: 'Meshtastic_test', paired: true }]
|
|
139
|
-
expect(described_class::BlueZ).to receive(:scan).with(adapter: 'hci1', timeout: 2).and_return(devices)
|
|
139
|
+
expect(described_class::BlueZ).to receive(:scan).with({ adapter: 'hci1', timeout: 2 }).and_return(devices)
|
|
140
140
|
expect(described_class.scan(adapter: 'hci1', timeout: 2)).to eq(devices)
|
|
141
141
|
end
|
|
142
142
|
|
|
@@ -3,25 +3,7 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Channel do
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
serial_conn = Object.new
|
|
9
|
-
serial_conn.define_singleton_method(:write) do |b|
|
|
10
|
-
written << b
|
|
11
|
-
b.bytesize
|
|
12
|
-
end
|
|
13
|
-
serial_conn.define_singleton_method(:flush) { true }
|
|
14
|
-
serial_conn.define_singleton_method(:closed?) { false }
|
|
15
|
-
serial_conn.define_singleton_method(:close) { true }
|
|
16
|
-
{ serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it 'requests a channel via Admin' do
|
|
20
|
-
serial_obj = fake_serial_obj
|
|
21
|
-
described_class.get(serial_obj: serial_obj, index: 1)
|
|
22
|
-
frame = serial_obj[:written]
|
|
23
|
-
packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
|
|
24
|
-
admin = Meshtastic::AdminMessage.decode(packet.decoded.payload)
|
|
25
|
-
expect(admin.get_channel_request).to eq(1)
|
|
6
|
+
it 'is the generated Channel protobuf' do
|
|
7
|
+
expect(described_class.new).to be_a(Google::Protobuf::MessageExts)
|
|
26
8
|
end
|
|
27
9
|
end
|
|
@@ -3,25 +3,7 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Config do
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
serial_conn = Object.new
|
|
9
|
-
serial_conn.define_singleton_method(:write) do |b|
|
|
10
|
-
written << b
|
|
11
|
-
b.bytesize
|
|
12
|
-
end
|
|
13
|
-
serial_conn.define_singleton_method(:flush) { true }
|
|
14
|
-
serial_conn.define_singleton_method(:closed?) { false }
|
|
15
|
-
serial_conn.define_singleton_method(:close) { true }
|
|
16
|
-
{ serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it 'requests LoRa config via Admin' do
|
|
20
|
-
serial_obj = fake_serial_obj
|
|
21
|
-
described_class.get(serial_obj: serial_obj, config_type: :LORA_CONFIG)
|
|
22
|
-
frame = serial_obj[:written]
|
|
23
|
-
packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
|
|
24
|
-
admin = Meshtastic::AdminMessage.decode(packet.decoded.payload)
|
|
25
|
-
expect(admin.get_config_request).to eq(:LORA_CONFIG)
|
|
6
|
+
it 'is the generated Config protobuf' do
|
|
7
|
+
expect(described_class.new).to be_a(Google::Protobuf::MessageExts)
|
|
26
8
|
end
|
|
27
9
|
end
|
|
@@ -4,6 +4,6 @@ require 'spec_helper'
|
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::ConnectionStatus do
|
|
6
6
|
it 'decodes DeviceConnectionStatus bytes' do
|
|
7
|
-
expect(described_class.decode(Meshtastic::DeviceConnectionStatus.new.to_proto)).to be_a(Meshtastic::DeviceConnectionStatus)
|
|
7
|
+
expect(described_class.decode(bytes: Meshtastic::DeviceConnectionStatus.new.to_proto)).to be_a(Meshtastic::DeviceConnectionStatus)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -4,6 +4,6 @@ require 'spec_helper'
|
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Deviceonly do
|
|
6
6
|
it 'decodes an empty DeviceState' do
|
|
7
|
-
expect(described_class.decode_state(Meshtastic::DeviceState.new.to_proto)).to be_a(Meshtastic::DeviceState)
|
|
7
|
+
expect(described_class.decode_state(bytes: Meshtastic::DeviceState.new.to_proto)).to be_a(Meshtastic::DeviceState)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -4,6 +4,6 @@ require 'spec_helper'
|
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Localonly do
|
|
6
6
|
it 'decodes an empty LocalConfig' do
|
|
7
|
-
expect(described_class.decode_config(Meshtastic::LocalConfig.new.to_proto)).to be_a(Meshtastic::LocalConfig)
|
|
7
|
+
expect(described_class.decode_config(bytes: Meshtastic::LocalConfig.new.to_proto)).to be_a(Meshtastic::LocalConfig)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -4,7 +4,7 @@ require 'spec_helper'
|
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Portnums do
|
|
6
6
|
it 'resolves names and numbers' do
|
|
7
|
-
expect(described_class.lookup(:TEXT_MESSAGE_APP)).to eq(1)
|
|
8
|
-
expect(described_class.lookup(1)).to eq(:TEXT_MESSAGE_APP)
|
|
7
|
+
expect(described_class.lookup(value: :TEXT_MESSAGE_APP)).to eq(1)
|
|
8
|
+
expect(described_class.lookup(value: 1)).to eq(:TEXT_MESSAGE_APP)
|
|
9
9
|
end
|
|
10
10
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: meshtastic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.180
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 0day Inc.
|
|
@@ -285,6 +285,9 @@ files:
|
|
|
285
285
|
- bin/meshtastic_autoinc_version
|
|
286
286
|
- build_gem.sh
|
|
287
287
|
- documentation/README.md
|
|
288
|
+
- documentation/admin-channel.md
|
|
289
|
+
- documentation/admin-config.md
|
|
290
|
+
- documentation/admin-firmware.md
|
|
288
291
|
- documentation/admin.md
|
|
289
292
|
- documentation/apponly.md
|
|
290
293
|
- documentation/atak.md
|
|
@@ -318,6 +321,9 @@ files:
|
|
|
318
321
|
- git_commit.sh
|
|
319
322
|
- lib/meshtastic.rb
|
|
320
323
|
- lib/meshtastic/admin.rb
|
|
324
|
+
- lib/meshtastic/admin/channel.rb
|
|
325
|
+
- lib/meshtastic/admin/config.rb
|
|
326
|
+
- lib/meshtastic/admin/firmware.rb
|
|
321
327
|
- lib/meshtastic/admin_pb.rb
|
|
322
328
|
- lib/meshtastic/apponly.rb
|
|
323
329
|
- lib/meshtastic/apponly_pb.rb
|
|
@@ -377,6 +383,10 @@ files:
|
|
|
377
383
|
- meshtastic.gemspec
|
|
378
384
|
- reinstall_gemset.sh
|
|
379
385
|
- sig/meshtastic.rbs
|
|
386
|
+
- spec/conventions_spec.rb
|
|
387
|
+
- spec/lib/meshtastic/admin/channel_spec.rb
|
|
388
|
+
- spec/lib/meshtastic/admin/config_spec.rb
|
|
389
|
+
- spec/lib/meshtastic/admin/firmware_spec.rb
|
|
380
390
|
- spec/lib/meshtastic/admin_pb_spec.rb
|
|
381
391
|
- spec/lib/meshtastic/admin_spec.rb
|
|
382
392
|
- spec/lib/meshtastic/apponly_pb_spec.rb
|