meshtastic 0.0.178 → 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/README.md +3 -175
- data/documentation/README.md +60 -0
- 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 +55 -0
- data/documentation/apponly.md +22 -0
- data/documentation/atak.md +110 -0
- data/documentation/bluetooth-bluez.md +35 -0
- data/documentation/bluetooth.md +87 -0
- data/documentation/cannedmessages.md +25 -0
- data/documentation/channel.md +3 -0
- data/documentation/clientonly.md +21 -0
- data/documentation/config.md +3 -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/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 +495 -7
- data/lib/meshtastic/apponly.rb +26 -8
- data/lib/meshtastic/atak.rb +298 -7
- data/lib/meshtastic/bluetooth/bluez.rb +20 -1
- data/lib/meshtastic/bluetooth.rb +70 -59
- data/lib/meshtastic/cannedmessages.rb +23 -8
- data/lib/meshtastic/channel.rb +3 -21
- data/lib/meshtastic/clientonly.rb +26 -8
- data/lib/meshtastic/config.rb +3 -21
- data/lib/meshtastic/connection_status.rb +13 -8
- data/lib/meshtastic/deviceonly.rb +23 -8
- data/lib/meshtastic/localonly.rb +23 -8
- data/lib/meshtastic/mesh_interface.rb +11 -0
- data/lib/meshtastic/module_config.rb +18 -9
- data/lib/meshtastic/mqtt.rb +72 -35
- data/lib/meshtastic/paxcount.rb +30 -9
- data/lib/meshtastic/portnums.rb +18 -8
- data/lib/meshtastic/position.rb +45 -0
- data/lib/meshtastic/remote_hardware.rb +50 -9
- data/lib/meshtastic/rtttl.rb +26 -8
- data/lib/meshtastic/serial.rb +81 -70
- data/lib/meshtastic/storeforward.rb +23 -8
- data/lib/meshtastic/stream_interface.rb +11 -0
- data/lib/meshtastic/tcp.rb +153 -0
- data/lib/meshtastic/telemetry.rb +27 -9
- data/lib/meshtastic/traceroute.rb +42 -0
- data/lib/meshtastic/util.rb +3 -1
- data/lib/meshtastic/version.rb +1 -1
- data/lib/meshtastic/xmodem.rb +17 -8
- data/lib/meshtastic.rb +46 -6
- 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_pb_spec.rb +1 -1
- data/spec/lib/meshtastic/admin_spec.rb +79 -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 +147 -0
- data/spec/lib/meshtastic/bluetooth_spec.rb +1 -1
- 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 +3 -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 +4 -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 +48 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'meshtastic/config_pb'
|
|
4
|
+
|
|
5
|
+
module Meshtastic
|
|
6
|
+
module Admin
|
|
7
|
+
module Config
|
|
8
|
+
public_class_method def self.get(opts = {})
|
|
9
|
+
Admin.get_config(opts.merge(config_type: opts[:config_type] || :DEVICE_CONFIG))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
public_class_method def self.set(opts = {})
|
|
13
|
+
Admin.set_config(opts.merge(config: opts[:config]))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
public_class_method def self.get_device(opts = {})
|
|
17
|
+
get(opts.merge(config_type: :DEVICE_CONFIG))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
public_class_method def self.get_position(opts = {})
|
|
21
|
+
get(opts.merge(config_type: :POSITION_CONFIG))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
public_class_method def self.get_power(opts = {})
|
|
25
|
+
get(opts.merge(config_type: :POWER_CONFIG))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
public_class_method def self.get_network(opts = {})
|
|
29
|
+
get(opts.merge(config_type: :NETWORK_CONFIG))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
public_class_method def self.get_display(opts = {})
|
|
33
|
+
get(opts.merge(config_type: :DISPLAY_CONFIG))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
public_class_method def self.get_lora(opts = {})
|
|
37
|
+
get(opts.merge(config_type: :LORA_CONFIG))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
public_class_method def self.get_bluetooth(opts = {})
|
|
41
|
+
get(opts.merge(config_type: :BLUETOOTH_CONFIG))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
public_class_method def self.get_security(opts = {})
|
|
45
|
+
get(opts.merge(config_type: :SECURITY_CONFIG))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
public_class_method def self.get_sessionkey(opts = {})
|
|
49
|
+
get(opts.merge(config_type: :SESSIONKEY_CONFIG))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
public_class_method def self.get_device_ui(opts = {})
|
|
53
|
+
get(opts.merge(config_type: :DEVICEUI_CONFIG))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
public_class_method def self.set_device(opts = {})
|
|
57
|
+
config = Meshtastic::Config.new
|
|
58
|
+
config.device = opts[:device]
|
|
59
|
+
set(opts.merge(config: config))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
public_class_method def self.set_lora(opts = {})
|
|
63
|
+
config = Meshtastic::Config.new
|
|
64
|
+
config.lora = opts[:lora]
|
|
65
|
+
set(opts.merge(config: config))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
public_class_method def self.authors
|
|
69
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
public_class_method def self.help
|
|
73
|
+
puts "USAGE:
|
|
74
|
+
# Request a radio Config section by ConfigType.
|
|
75
|
+
#{self}.get(
|
|
76
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
77
|
+
config_type: 'optional - :DEVICE_CONFIG or another ConfigType (default: :DEVICE_CONFIG)'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Write a Config protobuf to the node.
|
|
81
|
+
#{self}.set(
|
|
82
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
83
|
+
config: 'required - Meshtastic::Config protobuf to write'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Request DEVICE_CONFIG from the node.
|
|
87
|
+
#{self}.get_device(
|
|
88
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Request POSITION_CONFIG from the node.
|
|
92
|
+
#{self}.get_position(
|
|
93
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Request POWER_CONFIG from the node.
|
|
97
|
+
#{self}.get_power(
|
|
98
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Request NETWORK_CONFIG from the node.
|
|
102
|
+
#{self}.get_network(
|
|
103
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Request DISPLAY_CONFIG from the node.
|
|
107
|
+
#{self}.get_display(
|
|
108
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Request LORA_CONFIG from the node.
|
|
112
|
+
#{self}.get_lora(
|
|
113
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Request BLUETOOTH_CONFIG from the node.
|
|
117
|
+
#{self}.get_bluetooth(
|
|
118
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Request SECURITY_CONFIG from the node.
|
|
122
|
+
#{self}.get_security(
|
|
123
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Request SESSIONKEY_CONFIG from the node.
|
|
127
|
+
#{self}.get_sessionkey(
|
|
128
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Request DEVICEUI_CONFIG from the node.
|
|
132
|
+
#{self}.get_device_ui(
|
|
133
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Write DeviceConfig wrapped in a Config protobuf.
|
|
137
|
+
#{self}.set_device(
|
|
138
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
139
|
+
device: 'required - Meshtastic::Config::DeviceConfig protobuf to write'
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Write LoRaConfig wrapped in a Config protobuf.
|
|
143
|
+
#{self}.set_lora(
|
|
144
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
145
|
+
lora: 'required - Meshtastic::Config::LoRaConfig protobuf to write'
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Print the AUTHOR(S) string for this module.
|
|
149
|
+
#{self}.authors
|
|
150
|
+
"
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
require 'meshtastic/xmodem_pb'
|
|
5
|
+
|
|
6
|
+
module Meshtastic
|
|
7
|
+
module Admin
|
|
8
|
+
module Firmware
|
|
9
|
+
SOH_SIZE = 128
|
|
10
|
+
PAD = 0x1A
|
|
11
|
+
|
|
12
|
+
public_class_method def self.sha256(opts = {})
|
|
13
|
+
Digest::SHA256.digest(firmware_bytes(opts.merge({})))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
public_class_method def self.request_ota(opts = {})
|
|
17
|
+
hash = opts[:ota_hash] || sha256(opts)
|
|
18
|
+
raise ArgumentError, 'ota_hash must be 32 bytes' unless hash.to_s.bytesize == 32
|
|
19
|
+
|
|
20
|
+
event = Meshtastic::AdminMessage::OTAEvent.new(
|
|
21
|
+
reboot_ota_mode: opts[:mode] || :OTA_BLE,
|
|
22
|
+
ota_hash: hash.to_s.b
|
|
23
|
+
)
|
|
24
|
+
Admin.send(opts.merge(ota_request: event))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
public_class_method def self.enter_dfu(opts = {})
|
|
28
|
+
Admin.send(opts.merge(enter_dfu_mode_request: true))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
public_class_method def self.reboot_ota(opts = {})
|
|
32
|
+
Admin.send(opts.merge(reboot_ota_seconds: opts[:seconds] || 10))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
public_class_method def self.xmodem_blocks(opts = {})
|
|
36
|
+
payload = opts[:bytes].to_s.b
|
|
37
|
+
block_size = opts[:block_size] || SOH_SIZE
|
|
38
|
+
raise ArgumentError, 'firmware bytes are empty' if payload.empty?
|
|
39
|
+
|
|
40
|
+
blocks = []
|
|
41
|
+
seq = 1
|
|
42
|
+
offset = 0
|
|
43
|
+
while offset < payload.bytesize
|
|
44
|
+
chunk = payload.byteslice(offset, block_size).to_s.b
|
|
45
|
+
chunk = chunk.ljust(block_size, PAD.chr) if chunk.bytesize < block_size
|
|
46
|
+
blocks << Meshtastic::XModem.new(
|
|
47
|
+
control: block_size > SOH_SIZE ? :STX : :SOH,
|
|
48
|
+
seq: seq,
|
|
49
|
+
crc16: crc16(data: chunk),
|
|
50
|
+
buffer: chunk
|
|
51
|
+
)
|
|
52
|
+
seq += 1
|
|
53
|
+
offset += block_size
|
|
54
|
+
end
|
|
55
|
+
blocks << Meshtastic::XModem.new(control: :EOT, seq: seq)
|
|
56
|
+
blocks
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
public_class_method def self.send_xmodem(opts = {})
|
|
60
|
+
packet = opts[:xmodem]
|
|
61
|
+
to_radio = Meshtastic::ToRadio.new
|
|
62
|
+
to_radio.xmodemPacket = packet
|
|
63
|
+
send_phone(opts.merge(to_radio: to_radio))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
public_class_method def self.install(opts = {})
|
|
67
|
+
bytes = firmware_bytes(opts.merge({}))
|
|
68
|
+
request_ota(opts.merge(bytes: bytes))
|
|
69
|
+
return if opts[:mqtt_obj]
|
|
70
|
+
|
|
71
|
+
xmodem_blocks(bytes: bytes).each do |packet|
|
|
72
|
+
send_xmodem(opts.merge(xmodem: packet))
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
public_class_method def self.authors
|
|
77
|
+
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
public_class_method def self.help
|
|
81
|
+
puts "USAGE:
|
|
82
|
+
# SHA-256 the firmware image bytes or file.
|
|
83
|
+
#{self}.sha256(
|
|
84
|
+
firmware: 'optional - path to a firmware .bin on disk',
|
|
85
|
+
bytes: 'optional - raw firmware image bytes if no path is given'
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Send Admin ota_request with the image hash and OTA mode.
|
|
89
|
+
#{self}.request_ota(
|
|
90
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
91
|
+
mqtt_obj: 'optional - MQTT client from Meshtastic::MQTT.connect',
|
|
92
|
+
firmware: 'optional - path to a firmware .bin on disk',
|
|
93
|
+
ota_hash: 'optional - 32-byte SHA-256 digest if not hashing firmware',
|
|
94
|
+
mode: 'optional - :OTA_BLE or :OTA_WIFI (default: :OTA_BLE)'
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Ask the node to enter DFU / UF2 bootloader mode.
|
|
98
|
+
#{self}.enter_dfu(
|
|
99
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect'
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Send the legacy reboot_ota_seconds admin field.
|
|
103
|
+
#{self}.reboot_ota(
|
|
104
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
105
|
+
seconds: 'optional - delay before OTA reboot in seconds (default: 10)'
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Split firmware bytes into XModem SOH blocks plus EOT.
|
|
109
|
+
#{self}.xmodem_blocks(
|
|
110
|
+
bytes: 'required - raw firmware image bytes to chunk',
|
|
111
|
+
block_size: 'optional - XModem block size in bytes (default: 128)'
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Write one XModem protobuf as a PhoneAPI ToRadio frame.
|
|
115
|
+
#{self}.send_xmodem(
|
|
116
|
+
xmodem: 'required - Meshtastic::XModem protobuf to write',
|
|
117
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
118
|
+
tcp_obj: 'optional - TCP handle from Meshtastic::TCP.connect',
|
|
119
|
+
bluetooth_obj: 'optional - BLE handle from Meshtastic::Bluetooth.connect'
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Hash, send ota_request, then stream XModem on serial/TCP/BLE.
|
|
123
|
+
#{self}.install(
|
|
124
|
+
firmware: 'optional - path to a firmware .bin on disk',
|
|
125
|
+
bytes: 'optional - raw firmware image bytes if no path is given',
|
|
126
|
+
serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
|
|
127
|
+
tcp_obj: 'optional - TCP handle from Meshtastic::TCP.connect',
|
|
128
|
+
bluetooth_obj: 'optional - BLE handle from Meshtastic::Bluetooth.connect',
|
|
129
|
+
mqtt_obj: 'optional - MQTT client; publishes ota_request only',
|
|
130
|
+
mode: 'optional - :OTA_BLE or :OTA_WIFI (default: :OTA_BLE)'
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Print the AUTHOR(S) string for this module.
|
|
134
|
+
#{self}.authors
|
|
135
|
+
"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private_class_method def self.firmware_bytes(opts = {})
|
|
139
|
+
if opts[:bytes]
|
|
140
|
+
opts[:bytes].to_s.b
|
|
141
|
+
elsif opts[:firmware]
|
|
142
|
+
File.binread(opts[:firmware])
|
|
143
|
+
else
|
|
144
|
+
raise ArgumentError, 'firmware path or bytes is required'
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private_class_method def self.crc16(opts = {})
|
|
149
|
+
crc = 0
|
|
150
|
+
opts[:data].to_s.b.each_byte do |byte|
|
|
151
|
+
crc ^= byte << 8
|
|
152
|
+
8.times do
|
|
153
|
+
crc = crc[15] == 1 ? ((crc << 1) ^ 0x1021) : (crc << 1)
|
|
154
|
+
crc &= 0xffff
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
crc
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private_class_method def self.send_phone(opts = {})
|
|
161
|
+
if opts[:serial_obj]
|
|
162
|
+
Serial.send_to_radio(opts)
|
|
163
|
+
elsif opts[:tcp_obj]
|
|
164
|
+
TCP.send_to_radio(opts)
|
|
165
|
+
elsif opts[:bluetooth_obj]
|
|
166
|
+
Bluetooth.send_to_radio(opts)
|
|
167
|
+
else
|
|
168
|
+
raise ArgumentError, 'serial_obj, bluetooth_obj, or tcp_obj is required for XModem'
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|