meshtastic 0.0.178 → 0.0.179
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/README.md +3 -175
- data/documentation/README.md +59 -0
- data/documentation/admin.md +54 -0
- data/documentation/apponly.md +22 -0
- data/documentation/atak.md +27 -0
- data/documentation/bluetooth-bluez.md +35 -0
- data/documentation/bluetooth.md +87 -0
- data/documentation/cannedmessages.md +25 -0
- data/documentation/channel.md +30 -0
- data/documentation/clientonly.md +21 -0
- data/documentation/config.md +29 -0
- data/documentation/connection-status.md +22 -0
- data/documentation/deviceonly.md +22 -0
- data/documentation/localonly.md +21 -0
- data/documentation/mesh-interface.md +52 -0
- data/documentation/meshtastic.md +45 -0
- data/documentation/module-config.md +26 -0
- data/documentation/mqtt.md +101 -0
- data/documentation/paxcount.md +25 -0
- data/documentation/portnums.md +67 -0
- data/documentation/position.md +34 -0
- data/documentation/protobufs.md +162 -0
- data/documentation/remote-hardware.md +33 -0
- data/documentation/rtttl.md +24 -0
- data/documentation/serial.md +78 -0
- data/documentation/storeforward.md +24 -0
- data/documentation/stream-interface.md +15 -0
- data/documentation/tcp.md +43 -0
- data/documentation/telemetry.md +32 -0
- data/documentation/traceroute.md +28 -0
- data/documentation/util.md +27 -0
- data/documentation/xmodem.md +22 -0
- data/lib/meshtastic/admin.rb +66 -8
- data/lib/meshtastic/apponly.rb +14 -8
- data/lib/meshtastic/atak.rb +21 -8
- data/lib/meshtastic/cannedmessages.rb +16 -8
- data/lib/meshtastic/channel.rb +13 -9
- data/lib/meshtastic/clientonly.rb +14 -8
- data/lib/meshtastic/config.rb +12 -9
- data/lib/meshtastic/connection_status.rb +7 -9
- data/lib/meshtastic/deviceonly.rb +11 -8
- data/lib/meshtastic/localonly.rb +11 -8
- data/lib/meshtastic/module_config.rb +12 -9
- data/lib/meshtastic/paxcount.rb +19 -9
- data/lib/meshtastic/portnums.rb +12 -9
- data/lib/meshtastic/position.rb +35 -0
- data/lib/meshtastic/remote_hardware.rb +34 -9
- data/lib/meshtastic/rtttl.rb +17 -8
- data/lib/meshtastic/storeforward.rb +16 -8
- data/lib/meshtastic/tcp.rb +102 -0
- data/lib/meshtastic/telemetry.rb +18 -9
- data/lib/meshtastic/traceroute.rb +33 -0
- data/lib/meshtastic/version.rb +1 -1
- data/lib/meshtastic/xmodem.rb +11 -9
- data/lib/meshtastic.rb +26 -5
- data/spec/lib/meshtastic/admin_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/admin_spec.rb +39 -0
- data/spec/lib/meshtastic/apponly_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/apponly_spec.rb +4 -0
- data/spec/lib/meshtastic/atak_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/atak_spec.rb +22 -0
- data/spec/lib/meshtastic/cannedmessages_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/cannedmessages_spec.rb +3 -0
- data/spec/lib/meshtastic/channel_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/channel_spec.rb +21 -0
- data/spec/lib/meshtastic/clientonly_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/clientonly_spec.rb +5 -0
- data/spec/lib/meshtastic/config_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/config_spec.rb +22 -1
- data/spec/lib/meshtastic/connection_status_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/connection_status_spec.rb +3 -0
- data/spec/lib/meshtastic/deviceonly_legacy_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/deviceonly_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/deviceonly_spec.rb +3 -0
- data/spec/lib/meshtastic/localonly_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/localonly_spec.rb +3 -0
- data/spec/lib/meshtastic/mesh_beacon_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/mesh_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/module_config_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/module_config_spec.rb +21 -0
- data/spec/lib/meshtastic/mqtt_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/paxcount_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/paxcount_spec.rb +23 -0
- data/spec/lib/meshtastic/portnums_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/portnums_spec.rb +4 -0
- data/spec/lib/meshtastic/position_spec.rb +33 -0
- data/spec/lib/meshtastic/remote_hardware_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/remote_hardware_spec.rb +24 -0
- data/spec/lib/meshtastic/rtttl_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/rtttl_spec.rb +21 -0
- data/spec/lib/meshtastic/storeforward_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/storeforward_spec.rb +21 -0
- data/spec/lib/meshtastic/tcp_spec.rb +48 -0
- data/spec/lib/meshtastic/telemetry_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/telemetry_spec.rb +21 -0
- data/spec/lib/meshtastic/traceroute_spec.rb +27 -0
- data/spec/lib/meshtastic/xmodem_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/xmodem_spec.rb +6 -1
- data/spec/lib/meshtastic_spec.rb +3 -0
- metadata +38 -1
data/lib/meshtastic/portnums.rb
CHANGED
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
require 'meshtastic/portnums_pb'
|
|
4
4
|
|
|
5
|
-
# Plugin used to interact with Meshtastic nodes
|
|
6
5
|
module Meshtastic
|
|
7
6
|
module Portnums
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
def self.lookup(name_or_number)
|
|
8
|
+
if name_or_number.is_a?(Integer)
|
|
9
|
+
Meshtastic::PortNum.lookup(name_or_number)
|
|
10
|
+
else
|
|
11
|
+
Meshtastic::PortNum.resolve(name_or_number.to_sym)
|
|
12
|
+
end
|
|
14
13
|
end
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
def self.authors
|
|
16
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
def self.help
|
|
19
20
|
puts "USAGE:
|
|
21
|
+
#{self}.lookup(:TEXT_MESSAGE_APP)
|
|
22
|
+
#{self}.lookup(1)
|
|
20
23
|
#{self}.authors
|
|
21
24
|
"
|
|
22
25
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'meshtastic/mesh_pb'
|
|
4
|
+
|
|
5
|
+
module Meshtastic
|
|
6
|
+
class Position
|
|
7
|
+
def self.build(opts = {})
|
|
8
|
+
position = new
|
|
9
|
+
position.latitude_i = (opts.fetch(:lat).to_f * 10_000_000).round
|
|
10
|
+
position.longitude_i = (opts.fetch(:lon).to_f * 10_000_000).round
|
|
11
|
+
position.altitude = opts[:altitude].to_i if opts[:altitude]
|
|
12
|
+
position.time = opts[:time].to_i if opts[:time]
|
|
13
|
+
position
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.transmit(opts = {})
|
|
17
|
+
data = Meshtastic::Data.new(
|
|
18
|
+
portnum: :POSITION_APP,
|
|
19
|
+
payload: build(opts).to_proto
|
|
20
|
+
)
|
|
21
|
+
Meshtastic.deliver_data(opts.merge(data: data, port_num: Meshtastic::PortNum::POSITION_APP))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.authors
|
|
25
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.help
|
|
29
|
+
puts "USAGE:
|
|
30
|
+
#{self}.transmit(serial_obj: serial_obj, lat: 37.7749, lon: -122.4194, altitude: 10)
|
|
31
|
+
#{self}.authors
|
|
32
|
+
"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'meshtastic/
|
|
3
|
+
require 'meshtastic/mesh_pb'
|
|
4
4
|
|
|
5
|
-
# Plugin used to interact with Meshtastic nodes
|
|
6
5
|
module Meshtastic
|
|
7
6
|
module RemoteHardware
|
|
8
|
-
|
|
7
|
+
def self.encode(opts = {})
|
|
8
|
+
message = Meshtastic::HardwareMessage.new
|
|
9
|
+
message.type = opts.fetch(:type, :READ_GPIOS)
|
|
10
|
+
message.gpio_mask = opts.fetch(:gpio_mask, 0)
|
|
11
|
+
message.gpio_value = opts[:gpio_value].to_i if opts[:gpio_value]
|
|
12
|
+
message
|
|
13
|
+
end
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
def self.send(opts = {})
|
|
16
|
+
data = Meshtastic::Data.new(
|
|
17
|
+
portnum: :REMOTE_HARDWARE_APP,
|
|
18
|
+
payload: encode(opts).to_proto,
|
|
19
|
+
want_response: opts.fetch(:want_response, true)
|
|
20
|
+
)
|
|
21
|
+
Meshtastic.deliver_data(opts.merge(data: data, port_num: Meshtastic::PortNum::REMOTE_HARDWARE_APP))
|
|
14
22
|
end
|
|
15
23
|
|
|
16
|
-
|
|
24
|
+
def self.read_gpios(opts = {})
|
|
25
|
+
send(opts.merge(type: :READ_GPIOS))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.write_gpios(opts = {})
|
|
29
|
+
send(opts.merge(type: :WRITE_GPIOS, want_response: false))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.watch_gpios(opts = {})
|
|
33
|
+
send(opts.merge(type: :WATCH_GPIOS))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.authors
|
|
37
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
38
|
+
end
|
|
17
39
|
|
|
18
|
-
|
|
40
|
+
def self.help
|
|
19
41
|
puts "USAGE:
|
|
42
|
+
#{self}.read_gpios(serial_obj: serial_obj, gpio_mask: 0x01)
|
|
43
|
+
#{self}.write_gpios(serial_obj: serial_obj, gpio_mask: 0x01, gpio_value: 0x01)
|
|
44
|
+
#{self}.watch_gpios(serial_obj: serial_obj, gpio_mask: 0x01)
|
|
20
45
|
#{self}.authors
|
|
21
46
|
"
|
|
22
47
|
end
|
data/lib/meshtastic/rtttl.rb
CHANGED
|
@@ -2,21 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
require 'meshtastic/rtttl_pb'
|
|
4
4
|
|
|
5
|
-
# Plugin used to interact with Meshtastic nodes
|
|
6
5
|
module Meshtastic
|
|
7
6
|
module RTTTL
|
|
8
|
-
|
|
7
|
+
def self.encode(opts = {})
|
|
8
|
+
config = Meshtastic::RTTTLConfig.new
|
|
9
|
+
config.ringtone = opts.fetch(:ringtone, '')
|
|
10
|
+
config
|
|
11
|
+
end
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
0day Inc. <support@0dayinc.com>
|
|
13
|
-
"
|
|
13
|
+
def self.set(opts = {})
|
|
14
|
+
Admin.send(opts.merge(set_ringtone_message: opts.fetch(:ringtone)))
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
def self.get(opts = {})
|
|
18
|
+
Admin.send(opts.merge(get_ringtone_request: true))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.authors
|
|
22
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
23
|
+
end
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
def self.help
|
|
19
26
|
puts "USAGE:
|
|
27
|
+
#{self}.set(serial_obj: serial_obj, ringtone: 'Mario:d=4,o=5,b=125:16e6')
|
|
28
|
+
#{self}.get(serial_obj: serial_obj)
|
|
20
29
|
#{self}.authors
|
|
21
30
|
"
|
|
22
31
|
end
|
|
@@ -2,21 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
require 'meshtastic/storeforward_pb'
|
|
4
4
|
|
|
5
|
-
# Plugin used to interact with Meshtastic nodes
|
|
6
5
|
module Meshtastic
|
|
7
6
|
module Storeforward
|
|
8
|
-
|
|
7
|
+
def self.encode(opts = {})
|
|
8
|
+
message = Meshtastic::StoreAndForward.new
|
|
9
|
+
message.rr = opts.fetch(:rr, :ROUTER_HEARTBEAT)
|
|
10
|
+
message
|
|
11
|
+
end
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
def self.send(opts = {})
|
|
14
|
+
data = Meshtastic::Data.new(
|
|
15
|
+
portnum: :STORE_FORWARD_APP,
|
|
16
|
+
payload: encode(opts).to_proto
|
|
17
|
+
)
|
|
18
|
+
Meshtastic.deliver_data(opts.merge(data: data, port_num: Meshtastic::PortNum::STORE_FORWARD_APP))
|
|
14
19
|
end
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
def self.authors
|
|
22
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
23
|
+
end
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
def self.help
|
|
19
26
|
puts "USAGE:
|
|
27
|
+
#{self}.send(serial_obj: serial_obj, rr: :CLIENT_HISTORY)
|
|
20
28
|
#{self}.authors
|
|
21
29
|
"
|
|
22
30
|
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'socket'
|
|
4
|
+
|
|
5
|
+
# Meshtastic client API over TCP. Framing matches Serial (START1/START2 + protobuf).
|
|
6
|
+
# Default port is 4403, same as the official TCP interface.
|
|
7
|
+
module Meshtastic
|
|
8
|
+
module TCP
|
|
9
|
+
DEFAULT_PORT = 4403
|
|
10
|
+
|
|
11
|
+
def self.connect(opts = {})
|
|
12
|
+
host = opts[:host] ||= '127.0.0.1'
|
|
13
|
+
port = opts[:port] ||= DEFAULT_PORT
|
|
14
|
+
tcp_obj = nil
|
|
15
|
+
socket = opts[:socket] || TCPSocket.new(host, port)
|
|
16
|
+
socket.binmode
|
|
17
|
+
|
|
18
|
+
tcp_obj = {
|
|
19
|
+
serial_conn: socket,
|
|
20
|
+
tcp_socket: socket,
|
|
21
|
+
block_dev: "#{host}:#{port}",
|
|
22
|
+
host: host,
|
|
23
|
+
port: port,
|
|
24
|
+
tx_mutex: Mutex.new,
|
|
25
|
+
my_info: nil,
|
|
26
|
+
my_node_num: nil,
|
|
27
|
+
metadata: nil
|
|
28
|
+
}
|
|
29
|
+
tcp_obj[:rx_thread] = Meshtastic::Serial.send(
|
|
30
|
+
:init_rx_thread,
|
|
31
|
+
serial_conn: socket,
|
|
32
|
+
serial_obj: tcp_obj,
|
|
33
|
+
debug_out: opts[:debug_out]
|
|
34
|
+
)
|
|
35
|
+
Meshtastic::Serial.wake_up_device(serial_obj: tcp_obj)
|
|
36
|
+
if opts.fetch(:want_config, true)
|
|
37
|
+
mesh = Meshtastic::MeshInterface.new
|
|
38
|
+
bytes = mesh.start_config
|
|
39
|
+
tcp_obj[:config_id] = mesh.config_id
|
|
40
|
+
Meshtastic::Serial.send_to_radio(serial_obj: tcp_obj, to_radio: bytes)
|
|
41
|
+
end
|
|
42
|
+
tcp_obj
|
|
43
|
+
rescue StandardError
|
|
44
|
+
disconnect(tcp_obj: tcp_obj) if tcp_obj
|
|
45
|
+
raise
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.wait_for_config(opts = {})
|
|
49
|
+
Meshtastic::Serial.wait_for_config(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.send_to_radio(opts = {})
|
|
53
|
+
Meshtastic::Serial.send_to_radio(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.send_text(opts = {})
|
|
57
|
+
Meshtastic::Serial.send_text(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.send_data(opts = {})
|
|
61
|
+
Meshtastic::Serial.send_data(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.recv_from_radio(opts = {})
|
|
65
|
+
Meshtastic::Serial.recv_from_radio(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.drain_from_radio(opts = {})
|
|
69
|
+
Meshtastic::Serial.drain_from_radio(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.subscribe(opts = {}, &)
|
|
73
|
+
Meshtastic::Serial.subscribe(opts.merge(serial_obj: opts[:tcp_obj] || opts[:serial_obj]), &)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.disconnect(opts = {})
|
|
77
|
+
Meshtastic::Serial.disconnect(serial_obj: opts[:tcp_obj] || opts[:serial_obj])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.authors
|
|
81
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.help
|
|
85
|
+
puts "Send and receive Meshtastic messages over TCP (default port #{DEFAULT_PORT}).
|
|
86
|
+
|
|
87
|
+
USAGE:
|
|
88
|
+
tcp_obj = #{self}.connect(
|
|
89
|
+
host: 'optional - (default: 127.0.0.1)',
|
|
90
|
+
port: 'optional - (default: 4403)',
|
|
91
|
+
want_config: 'optional - request full node DB after connect (default: true)'
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
#{self}.wait_for_config(tcp_obj: tcp_obj, timeout: 10)
|
|
95
|
+
#{self}.send_text(tcp_obj: tcp_obj, to: '!ffffffff', channel: 0, text: 'Hello over TCP!')
|
|
96
|
+
#{self}.subscribe(tcp_obj: tcp_obj, include: 'TEXT_MESSAGE_APP')
|
|
97
|
+
#{self}.disconnect(tcp_obj: tcp_obj)
|
|
98
|
+
#{self}.authors
|
|
99
|
+
"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/meshtastic/telemetry.rb
CHANGED
|
@@ -2,21 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
require 'meshtastic/telemetry_pb'
|
|
4
4
|
|
|
5
|
-
# Plugin used to interact with Meshtastic nodes
|
|
6
5
|
module Meshtastic
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
class Telemetry
|
|
7
|
+
def self.build(opts = {})
|
|
8
|
+
telemetry = new
|
|
9
|
+
telemetry.time = opts[:time].to_i if opts[:time]
|
|
10
|
+
telemetry
|
|
11
|
+
end
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
def self.request(opts = {})
|
|
14
|
+
data = Meshtastic::Data.new(
|
|
15
|
+
portnum: :TELEMETRY_APP,
|
|
16
|
+
payload: build(opts).to_proto,
|
|
17
|
+
want_response: true
|
|
18
|
+
)
|
|
19
|
+
Meshtastic.deliver_data(opts.merge(data: data, port_num: Meshtastic::PortNum::TELEMETRY_APP, want_response: true))
|
|
14
20
|
end
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
def self.authors
|
|
23
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
24
|
+
end
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
def self.help
|
|
19
27
|
puts "USAGE:
|
|
28
|
+
#{self}.request(serial_obj: serial_obj, to: '!aabbccdd')
|
|
20
29
|
#{self}.authors
|
|
21
30
|
"
|
|
22
31
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'meshtastic/mesh_pb'
|
|
4
|
+
|
|
5
|
+
module Meshtastic
|
|
6
|
+
module Traceroute
|
|
7
|
+
def self.encode(opts = {})
|
|
8
|
+
discovery = Meshtastic::RouteDiscovery.new
|
|
9
|
+
Array(opts[:route]).each { |hop| discovery.route << hop }
|
|
10
|
+
discovery
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.send(opts = {})
|
|
14
|
+
data = Meshtastic::Data.new(
|
|
15
|
+
portnum: :TRACEROUTE_APP,
|
|
16
|
+
payload: encode(opts).to_proto,
|
|
17
|
+
want_response: true
|
|
18
|
+
)
|
|
19
|
+
Meshtastic.deliver_data(opts.merge(data: data, port_num: Meshtastic::PortNum::TRACEROUTE_APP, want_response: true))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.authors
|
|
23
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.help
|
|
27
|
+
puts "USAGE:
|
|
28
|
+
#{self}.send(serial_obj: serial_obj, to: '!aabbccdd')
|
|
29
|
+
#{self}.authors
|
|
30
|
+
"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/meshtastic/version.rb
CHANGED
data/lib/meshtastic/xmodem.rb
CHANGED
|
@@ -2,21 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
require 'meshtastic/xmodem_pb'
|
|
4
4
|
|
|
5
|
-
# Plugin used to interact with Meshtastic nodes
|
|
6
5
|
module Meshtastic
|
|
7
6
|
module Xmodem
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
def self.encode(opts = {})
|
|
8
|
+
packet = Meshtastic::XModem.new
|
|
9
|
+
packet.control = opts.fetch(:control, :SOH)
|
|
10
|
+
packet.seq = opts[:seq].to_i if opts[:seq]
|
|
11
|
+
packet.buffer = opts[:buffer] if opts[:buffer]
|
|
12
|
+
packet
|
|
14
13
|
end
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
def self.authors
|
|
16
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
def self.help
|
|
19
20
|
puts "USAGE:
|
|
21
|
+
#{self}.encode(control: :SOH, seq: 1, buffer: data)
|
|
20
22
|
#{self}.authors
|
|
21
23
|
"
|
|
22
24
|
end
|
data/lib/meshtastic.rb
CHANGED
|
@@ -12,11 +12,13 @@ module Meshtastic
|
|
|
12
12
|
require 'meshtastic/clientonly_pb'
|
|
13
13
|
require 'meshtastic/config_pb'
|
|
14
14
|
require 'meshtastic/connection_status_pb'
|
|
15
|
+
require 'meshtastic/deviceonly_legacy_pb'
|
|
15
16
|
require 'meshtastic/deviceonly_pb'
|
|
16
17
|
require 'meshtastic/device_ui_pb'
|
|
17
18
|
require 'meshtastic/interdevice_pb'
|
|
18
19
|
require 'meshtastic/localonly_pb'
|
|
19
20
|
require 'meshtastic/lorawan_bridge_pb'
|
|
21
|
+
require 'meshtastic/mesh_beacon_pb'
|
|
20
22
|
require 'meshtastic/mesh_pb'
|
|
21
23
|
require 'meshtastic/module_config_pb'
|
|
22
24
|
require 'meshtastic/mqtt_pb'
|
|
@@ -25,6 +27,7 @@ module Meshtastic
|
|
|
25
27
|
require 'meshtastic/powermon_pb'
|
|
26
28
|
require 'meshtastic/remote_hardware_pb'
|
|
27
29
|
require 'meshtastic/rtttl_pb'
|
|
30
|
+
require 'meshtastic/serial_hal_pb'
|
|
28
31
|
require 'meshtastic/storeforward_pb'
|
|
29
32
|
require 'meshtastic/telemetry_pb'
|
|
30
33
|
require 'meshtastic/version'
|
|
@@ -38,23 +41,20 @@ module Meshtastic
|
|
|
38
41
|
autoload :ATAK, 'meshtastic/atak'
|
|
39
42
|
autoload :Bluetooth, 'meshtastic/bluetooth'
|
|
40
43
|
autoload :Cannedmessages, 'meshtastic/cannedmessages'
|
|
41
|
-
autoload :Channel, 'meshtastic/channel'
|
|
42
44
|
autoload :Clientonly, 'meshtastic/clientonly'
|
|
43
|
-
autoload :Config, 'meshtastic/config'
|
|
44
45
|
autoload :ConnectionStatus, 'meshtastic/connection_status'
|
|
45
46
|
autoload :Deviceonly, 'meshtastic/deviceonly'
|
|
46
47
|
autoload :Localonly, 'meshtastic/localonly'
|
|
47
48
|
autoload :MeshInterface, 'meshtastic/mesh_interface'
|
|
48
|
-
autoload :ModuleConfig, 'meshtastic/module_config'
|
|
49
49
|
autoload :MQTT, 'meshtastic/mqtt'
|
|
50
|
-
autoload :Paxcount, 'meshtastic/paxcount'
|
|
51
50
|
autoload :Portnums, 'meshtastic/portnums'
|
|
52
51
|
autoload :RemoteHardware, 'meshtastic/remote_hardware'
|
|
53
52
|
autoload :RTTTL, 'meshtastic/rtttl'
|
|
54
53
|
autoload :Serial, 'meshtastic/serial'
|
|
55
54
|
autoload :Storeforward, 'meshtastic/storeforward'
|
|
56
55
|
autoload :StreamInterface, 'meshtastic/stream_interface'
|
|
57
|
-
autoload :
|
|
56
|
+
autoload :TCP, 'meshtastic/tcp'
|
|
57
|
+
autoload :Traceroute, 'meshtastic/traceroute'
|
|
58
58
|
autoload :Util, 'meshtastic/util'
|
|
59
59
|
autoload :Xmodem, 'meshtastic/xmodem'
|
|
60
60
|
|
|
@@ -70,4 +70,25 @@ module Meshtastic
|
|
|
70
70
|
public_class_method def self.help
|
|
71
71
|
constants.sort
|
|
72
72
|
end
|
|
73
|
+
|
|
74
|
+
def self.deliver_data(opts = {})
|
|
75
|
+
raise ArgumentError, 'data is required' unless opts[:data].is_a?(Meshtastic::Data)
|
|
76
|
+
|
|
77
|
+
if opts[:serial_obj]
|
|
78
|
+
Serial.send_data(opts)
|
|
79
|
+
elsif opts[:bluetooth_obj]
|
|
80
|
+
Bluetooth.send_data(opts)
|
|
81
|
+
elsif opts[:tcp_obj]
|
|
82
|
+
TCP.send_data(opts)
|
|
83
|
+
else
|
|
84
|
+
raise ArgumentError, 'serial_obj, bluetooth_obj, or tcp_obj is required'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
73
87
|
end
|
|
88
|
+
|
|
89
|
+
require 'meshtastic/channel'
|
|
90
|
+
require 'meshtastic/config'
|
|
91
|
+
require 'meshtastic/module_config'
|
|
92
|
+
require 'meshtastic/paxcount'
|
|
93
|
+
require 'meshtastic/position'
|
|
94
|
+
require 'meshtastic/telemetry'
|
|
@@ -3,4 +3,43 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Admin do
|
|
6
|
+
def fake_serial_obj
|
|
7
|
+
written = +''.b
|
|
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
|
+
def decode_admin(serial_obj)
|
|
20
|
+
frame = serial_obj[:written]
|
|
21
|
+
body = frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))
|
|
22
|
+
packet = Meshtastic::ToRadio.decode(body).packet
|
|
23
|
+
[packet, Meshtastic::AdminMessage.decode(packet.decoded.payload)]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'sends a reboot AdminMessage on ADMIN_APP' do
|
|
27
|
+
serial_obj = fake_serial_obj
|
|
28
|
+
described_class.reboot(serial_obj: serial_obj, seconds: 7)
|
|
29
|
+
packet, admin = decode_admin(serial_obj)
|
|
30
|
+
expect(packet.decoded.portnum).to eq(:ADMIN_APP)
|
|
31
|
+
expect(admin.reboot_seconds).to eq(7)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'sends a set_owner AdminMessage' do
|
|
35
|
+
serial_obj = fake_serial_obj
|
|
36
|
+
described_class.set_owner(serial_obj: serial_obj, long_name: 'Test Node', short_name: 'TN')
|
|
37
|
+
_packet, admin = decode_admin(serial_obj)
|
|
38
|
+
expect(admin.set_owner.long_name).to eq('Test Node')
|
|
39
|
+
expect(admin.set_owner.short_name).to eq('TN')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'prints usage without raising' do
|
|
43
|
+
expect { described_class.help }.to output(/USAGE/).to_stdout
|
|
44
|
+
end
|
|
6
45
|
end
|
|
@@ -3,4 +3,26 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::ATAK do
|
|
6
|
+
def fake_serial_obj
|
|
7
|
+
written = +''.b
|
|
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 'sends a GeoChat TAKPacket' do
|
|
20
|
+
serial_obj = fake_serial_obj
|
|
21
|
+
described_class.send(serial_obj: serial_obj, message: 'ATAK chat')
|
|
22
|
+
frame = serial_obj[:written]
|
|
23
|
+
packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
|
|
24
|
+
expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
|
|
25
|
+
tak = Meshtastic::TAKPacket.decode(packet.decoded.payload)
|
|
26
|
+
expect(tak.chat.message).to eq('ATAK chat')
|
|
27
|
+
end
|
|
6
28
|
end
|
|
@@ -3,4 +3,25 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe Meshtastic::Channel do
|
|
6
|
+
def fake_serial_obj
|
|
7
|
+
written = +''.b
|
|
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)
|
|
26
|
+
end
|
|
6
27
|
end
|