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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -175
  3. data/documentation/README.md +59 -0
  4. data/documentation/admin.md +54 -0
  5. data/documentation/apponly.md +22 -0
  6. data/documentation/atak.md +27 -0
  7. data/documentation/bluetooth-bluez.md +35 -0
  8. data/documentation/bluetooth.md +87 -0
  9. data/documentation/cannedmessages.md +25 -0
  10. data/documentation/channel.md +30 -0
  11. data/documentation/clientonly.md +21 -0
  12. data/documentation/config.md +29 -0
  13. data/documentation/connection-status.md +22 -0
  14. data/documentation/deviceonly.md +22 -0
  15. data/documentation/localonly.md +21 -0
  16. data/documentation/mesh-interface.md +52 -0
  17. data/documentation/meshtastic.md +45 -0
  18. data/documentation/module-config.md +26 -0
  19. data/documentation/mqtt.md +101 -0
  20. data/documentation/paxcount.md +25 -0
  21. data/documentation/portnums.md +67 -0
  22. data/documentation/position.md +34 -0
  23. data/documentation/protobufs.md +162 -0
  24. data/documentation/remote-hardware.md +33 -0
  25. data/documentation/rtttl.md +24 -0
  26. data/documentation/serial.md +78 -0
  27. data/documentation/storeforward.md +24 -0
  28. data/documentation/stream-interface.md +15 -0
  29. data/documentation/tcp.md +43 -0
  30. data/documentation/telemetry.md +32 -0
  31. data/documentation/traceroute.md +28 -0
  32. data/documentation/util.md +27 -0
  33. data/documentation/xmodem.md +22 -0
  34. data/lib/meshtastic/admin.rb +66 -8
  35. data/lib/meshtastic/apponly.rb +14 -8
  36. data/lib/meshtastic/atak.rb +21 -8
  37. data/lib/meshtastic/cannedmessages.rb +16 -8
  38. data/lib/meshtastic/channel.rb +13 -9
  39. data/lib/meshtastic/clientonly.rb +14 -8
  40. data/lib/meshtastic/config.rb +12 -9
  41. data/lib/meshtastic/connection_status.rb +7 -9
  42. data/lib/meshtastic/deviceonly.rb +11 -8
  43. data/lib/meshtastic/localonly.rb +11 -8
  44. data/lib/meshtastic/module_config.rb +12 -9
  45. data/lib/meshtastic/paxcount.rb +19 -9
  46. data/lib/meshtastic/portnums.rb +12 -9
  47. data/lib/meshtastic/position.rb +35 -0
  48. data/lib/meshtastic/remote_hardware.rb +34 -9
  49. data/lib/meshtastic/rtttl.rb +17 -8
  50. data/lib/meshtastic/storeforward.rb +16 -8
  51. data/lib/meshtastic/tcp.rb +102 -0
  52. data/lib/meshtastic/telemetry.rb +18 -9
  53. data/lib/meshtastic/traceroute.rb +33 -0
  54. data/lib/meshtastic/version.rb +1 -1
  55. data/lib/meshtastic/xmodem.rb +11 -9
  56. data/lib/meshtastic.rb +26 -5
  57. data/spec/lib/meshtastic/admin_pb_spec.rb +1 -1
  58. data/spec/lib/meshtastic/admin_spec.rb +39 -0
  59. data/spec/lib/meshtastic/apponly_pb_spec.rb +1 -1
  60. data/spec/lib/meshtastic/apponly_spec.rb +4 -0
  61. data/spec/lib/meshtastic/atak_pb_spec.rb +1 -1
  62. data/spec/lib/meshtastic/atak_spec.rb +22 -0
  63. data/spec/lib/meshtastic/cannedmessages_pb_spec.rb +1 -1
  64. data/spec/lib/meshtastic/cannedmessages_spec.rb +3 -0
  65. data/spec/lib/meshtastic/channel_pb_spec.rb +1 -1
  66. data/spec/lib/meshtastic/channel_spec.rb +21 -0
  67. data/spec/lib/meshtastic/clientonly_pb_spec.rb +1 -1
  68. data/spec/lib/meshtastic/clientonly_spec.rb +5 -0
  69. data/spec/lib/meshtastic/config_pb_spec.rb +1 -1
  70. data/spec/lib/meshtastic/config_spec.rb +22 -1
  71. data/spec/lib/meshtastic/connection_status_pb_spec.rb +1 -1
  72. data/spec/lib/meshtastic/connection_status_spec.rb +3 -0
  73. data/spec/lib/meshtastic/deviceonly_legacy_pb_spec.rb +1 -1
  74. data/spec/lib/meshtastic/deviceonly_pb_spec.rb +1 -1
  75. data/spec/lib/meshtastic/deviceonly_spec.rb +3 -0
  76. data/spec/lib/meshtastic/localonly_pb_spec.rb +1 -1
  77. data/spec/lib/meshtastic/localonly_spec.rb +3 -0
  78. data/spec/lib/meshtastic/mesh_beacon_pb_spec.rb +1 -1
  79. data/spec/lib/meshtastic/mesh_pb_spec.rb +1 -1
  80. data/spec/lib/meshtastic/module_config_pb_spec.rb +1 -1
  81. data/spec/lib/meshtastic/module_config_spec.rb +21 -0
  82. data/spec/lib/meshtastic/mqtt_pb_spec.rb +1 -1
  83. data/spec/lib/meshtastic/paxcount_pb_spec.rb +1 -1
  84. data/spec/lib/meshtastic/paxcount_spec.rb +23 -0
  85. data/spec/lib/meshtastic/portnums_pb_spec.rb +1 -1
  86. data/spec/lib/meshtastic/portnums_spec.rb +4 -0
  87. data/spec/lib/meshtastic/position_spec.rb +33 -0
  88. data/spec/lib/meshtastic/remote_hardware_pb_spec.rb +1 -1
  89. data/spec/lib/meshtastic/remote_hardware_spec.rb +24 -0
  90. data/spec/lib/meshtastic/rtttl_pb_spec.rb +1 -1
  91. data/spec/lib/meshtastic/rtttl_spec.rb +21 -0
  92. data/spec/lib/meshtastic/storeforward_pb_spec.rb +1 -1
  93. data/spec/lib/meshtastic/storeforward_spec.rb +21 -0
  94. data/spec/lib/meshtastic/tcp_spec.rb +48 -0
  95. data/spec/lib/meshtastic/telemetry_pb_spec.rb +1 -1
  96. data/spec/lib/meshtastic/telemetry_spec.rb +21 -0
  97. data/spec/lib/meshtastic/traceroute_spec.rb +27 -0
  98. data/spec/lib/meshtastic/xmodem_pb_spec.rb +1 -1
  99. data/spec/lib/meshtastic/xmodem_spec.rb +6 -1
  100. data/spec/lib/meshtastic_spec.rb +3 -0
  101. metadata +38 -1
@@ -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
- # Author(s):: 0day Inc. <support@0dayinc.com>
9
-
10
- public_class_method def self.authors
11
- "AUTHOR(S):
12
- 0day Inc. <support@0dayinc.com>
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
- # Display Usage for this Module
15
+ def self.authors
16
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
17
+ end
17
18
 
18
- public_class_method def self.help
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/remote_hardware_pb'
3
+ require 'meshtastic/mesh_pb'
4
4
 
5
- # Plugin used to interact with Meshtastic nodes
6
5
  module Meshtastic
7
6
  module RemoteHardware
8
- # Author(s):: 0day Inc. <support@0dayinc.com>
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
- public_class_method def self.authors
11
- "AUTHOR(S):
12
- 0day Inc. <support@0dayinc.com>
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
- # Display Usage for this Module
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
- public_class_method def self.help
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
@@ -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
- # Author(s):: 0day Inc. <support@0dayinc.com>
7
+ def self.encode(opts = {})
8
+ config = Meshtastic::RTTTLConfig.new
9
+ config.ringtone = opts.fetch(:ringtone, '')
10
+ config
11
+ end
9
12
 
10
- public_class_method def self.authors
11
- "AUTHOR(S):
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
- # Display Usage for this Module
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
- public_class_method def self.help
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
- # Author(s):: 0day Inc. <support@0dayinc.com>
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
- public_class_method def self.authors
11
- "AUTHOR(S):
12
- 0day Inc. <support@0dayinc.com>
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
- # Display Usage for this Module
21
+ def self.authors
22
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
23
+ end
17
24
 
18
- public_class_method def self.help
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
@@ -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
- module Telemetry
8
- # Author(s):: 0day Inc. <support@0dayinc.com>
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
- public_class_method def self.authors
11
- "AUTHOR(S):
12
- 0day Inc. <support@0dayinc.com>
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
- # Display Usage for this Module
22
+ def self.authors
23
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
24
+ end
17
25
 
18
- public_class_method def self.help
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Meshtastic
4
- VERSION = '0.0.178'
4
+ VERSION = '0.0.179'
5
5
  end
@@ -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
- # Author(s):: 0day Inc. <support@0dayinc.com>
9
-
10
- public_class_method def self.authors
11
- "AUTHOR(S):
12
- 0day Inc. <support@0dayinc.com>
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
- # Display Usage for this Module
15
+ def self.authors
16
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
17
+ end
17
18
 
18
- public_class_method def self.help
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 :Telemetry, 'meshtastic/telemetry'
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'
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::AdminPB do
5
+ describe Meshtastic::AdminMessage do
6
6
  end
@@ -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
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ApponlyPB do
5
+ describe Meshtastic::ChannelSet do
6
6
  end
@@ -3,4 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Apponly do
6
+ it 'round-trips a ChannelSet' do
7
+ set = described_class.encode
8
+ expect(described_class.decode(set.to_proto)).to be_a(Meshtastic::ChannelSet)
9
+ end
6
10
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ATAKPB do
5
+ describe Meshtastic::TAKPacket do
6
6
  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
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::CannedmessagesPB do
5
+ describe Meshtastic::CannedMessageModuleConfig do
6
6
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Cannedmessages do
6
+ it 'encodes canned message lines' do
7
+ expect(described_class.encode(messages: "Yes\nNo").messages).to eq("Yes\nNo")
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ChannelPB do
5
+ describe Meshtastic::ChannelSettings do
6
6
  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
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ClientonlyPB do
5
+ describe Meshtastic::DeviceProfile do
6
6
  end
@@ -3,4 +3,9 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Clientonly do
6
+ it 'encodes a DeviceProfile' do
7
+ profile = described_class.encode(long_name: 'Node', short_name: 'N1')
8
+ expect(profile.long_name).to eq('Node')
9
+ expect(profile.short_name).to eq('N1')
10
+ end
6
11
  end