SerialModem 0.2.1
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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +3 -0
- data/README.md +139 -0
- data/Rakefile +2 -0
- data/commit +17 -0
- data/lib/serialmodem.rb +399 -0
- data/serialmodem.gemspec +23 -0
- data/test/run_test +10 -0
- data/test/test_hw.rb +59 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 839d274ffc8a28dce56ffbe71d819fe8e4e18c54
|
4
|
+
data.tar.gz: fbf47a8b2d3f16115cf2ed83a7d3445b35b61450
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca30509c6a7c5faf90a7ad53720c53ecd4b27206a516b5f477131e99c7bf4b2d36412b24afa4bbbc11c46b8d73a979bd4f58c91c37f47f1a06ca892be06098bd
|
7
|
+
data.tar.gz: a0a68c388895b0d1e9983b3b19d979c4a4bb34637edd3c41c8768611621d43977b242cd013b512e6fa6d4bd58ea3b54ea470d1a400bd398b30c190ac3dfc6f0d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
# SerialModem
|
2
|
+
|
3
|
+
Simple interface for Serial Modems. Tested:
|
4
|
+
- Huawei E303 in serial mode
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'SerialModem'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install SerialModem
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Simple
|
25
|
+
|
26
|
+
If everything is connected and the modem is recognized (/dev/ttyUSB* is
|
27
|
+
available), then you can simply do:
|
28
|
+
|
29
|
+
```
|
30
|
+
require 'serialmodem'
|
31
|
+
|
32
|
+
SerialModem::setup_modem
|
33
|
+
return unless SerialModem.attached?
|
34
|
+
|
35
|
+
SerialModem::ussd_send('*100#')
|
36
|
+
SerialModem::sms_send('+23599999999', 'Hello from SerialModem')
|
37
|
+
```
|
38
|
+
|
39
|
+
### Ussd
|
40
|
+
|
41
|
+
Huawei-modems with Hilink don't support USSD, so you have to switch them
|
42
|
+
to serial-mode. Older modems (pre-2015) are handled with _HilinkModem_, newer versions
|
43
|
+
not yet. Once the modem is in serial-mode, you can send and receive USSD-codes.
|
44
|
+
It is even possible to use USSD-menus.
|
45
|
+
|
46
|
+
#### Sending
|
47
|
+
|
48
|
+
Supposing the modem is setup, you can do
|
49
|
+
|
50
|
+
```
|
51
|
+
SerialModem::send_ussd('*100#')
|
52
|
+
```
|
53
|
+
|
54
|
+
Or, if you need a menu where each step needs an answer, you can do
|
55
|
+
|
56
|
+
```
|
57
|
+
SerialModem::send_ussd('*800#', '1', '2', '1234')
|
58
|
+
```
|
59
|
+
|
60
|
+
Now each command waits for the last command to be completed.
|
61
|
+
|
62
|
+
#### Receiving
|
63
|
+
|
64
|
+
The received codes are stored in an array of hashes, where each hash has
|
65
|
+
three fields:
|
66
|
+
|
67
|
+
- time: a string of "%H:%M"
|
68
|
+
- code: the ussd-code as sent out by 'ussd_send'
|
69
|
+
- result
|
70
|
+
|
71
|
+
There is a maximum of _SerialModem::serial_ussd_results_max_ messages
|
72
|
+
stored.
|
73
|
+
|
74
|
+
```
|
75
|
+
SerialModem::send_ussd('*128#')
|
76
|
+
sleep 10
|
77
|
+
result = SerialModem.serial_ussd_results.first.result
|
78
|
+
```
|
79
|
+
|
80
|
+
#### Asynchronous receiving
|
81
|
+
|
82
|
+
You can also define a listener in _SerialModem.serial_ussd_new_
|
83
|
+
|
84
|
+
### SMS
|
85
|
+
|
86
|
+
Similar to USSD, you can send and receive SMS. Due to some restrictions in
|
87
|
+
Huawei-modems, there is a thread that checks for new SMSs every 20s. Normally
|
88
|
+
modems should reply as soon as an SMS is received, but most of the Huawei-modems
|
89
|
+
tested delete SMS automatically when in this mode. If you prefer nonethelss to
|
90
|
+
rely on this mode, set _SerialModem.serial_sms_autoscan_ to 0.
|
91
|
+
|
92
|
+
#### Sending
|
93
|
+
|
94
|
+
If everything is recognized, simply do:
|
95
|
+
|
96
|
+
```
|
97
|
+
SerialModem.sms_send('+23599999999', 'Hello from SerialModem')
|
98
|
+
```
|
99
|
+
|
100
|
+
And the message should be sent.
|
101
|
+
|
102
|
+
#### Receiving
|
103
|
+
|
104
|
+
All SMS are put in a hash of arrays with the key of the hash being the message-id
|
105
|
+
and the elements of the array as follows:
|
106
|
+
|
107
|
+
0: sms-flag
|
108
|
+
1: number of sender
|
109
|
+
2: unknown field
|
110
|
+
3: date and time of SMS
|
111
|
+
4: the message
|
112
|
+
|
113
|
+
#### Asynchronous receiving
|
114
|
+
|
115
|
+
You can also use the _SerialModem.serial_sms_new_ variable to set up an
|
116
|
+
automatic callback whenever a new SMS is received:
|
117
|
+
|
118
|
+
```
|
119
|
+
|
120
|
+
def treat_sms(list, id)
|
121
|
+
p "Received SMS from #{list[id][1]}"
|
122
|
+
end
|
123
|
+
|
124
|
+
SerialModem.serial_sms_new.push(Proc.new { |list, id| treat_sms(list, id) })
|
125
|
+
|
126
|
+
# Wait for SMS
|
127
|
+
```
|
128
|
+
|
129
|
+
## Special
|
130
|
+
|
131
|
+
Some care has been taken that the serial modem is recognized and can be
|
132
|
+
functional again in case of error:
|
133
|
+
|
134
|
+
### detach and re-attach in case of power-failure
|
135
|
+
|
136
|
+
It can happen that the modem is in use and is reattached because of errors in the
|
137
|
+
power. In that case it is not attached anymore to '/dev/ttyUSB2', but to
|
138
|
+
'/dev/ttyUSB3'. With some luck, the _SerialModem.reload_option_ can help to
|
139
|
+
make things OK again.
|
data/Rakefile
ADDED
data/commit
ADDED
data/lib/serialmodem.rb
ADDED
@@ -0,0 +1,399 @@
|
|
1
|
+
require 'serialmodem/version'
|
2
|
+
require 'serialport'
|
3
|
+
require 'helperclasses'
|
4
|
+
|
5
|
+
module SerialModem
|
6
|
+
DEBUG_LVL = 1
|
7
|
+
attr_accessor :serial_sms_new, :serial_sms_to_delete, :serial_sms,
|
8
|
+
:serial_ussd_new
|
9
|
+
extend self
|
10
|
+
include HelperClasses
|
11
|
+
include HelperClasses::DPuts
|
12
|
+
extend HelperClasses::DPuts
|
13
|
+
|
14
|
+
def setup_modem(dev = nil)
|
15
|
+
@serial_debug = false
|
16
|
+
@serial_tty = @serial_tty_error = @serial_sp = nil
|
17
|
+
@serial_replies = []
|
18
|
+
@serial_codes = {}
|
19
|
+
@serial_sms = {}
|
20
|
+
@serial_sms_new = []
|
21
|
+
@serial_sms_to_delete = []
|
22
|
+
@serial_sms_autoscan = 20
|
23
|
+
@serial_sms_autoscan_last = Time.now
|
24
|
+
@serial_ussd = []
|
25
|
+
@serial_ussd_last = Time.now
|
26
|
+
@serial_ussd_timeout = 30
|
27
|
+
@serial_ussd_results = []
|
28
|
+
@serial_ussd_results_max = 100
|
29
|
+
@serial_ussd_new = []
|
30
|
+
@serial_mutex_rcv = Mutex.new
|
31
|
+
@serial_mutex_send = Mutex.new
|
32
|
+
# Some Huawei-modems eat SMS once they send a +CMTI-message - this
|
33
|
+
# turns off the CMTI-messages which slows down incoming SMS detection
|
34
|
+
@serial_eats_sms = false
|
35
|
+
setup_tty
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_reply(wait = nil)
|
39
|
+
@serial_debug and dputs_func
|
40
|
+
raise IOError.new('NoModemHere') unless @serial_sp
|
41
|
+
ret = []
|
42
|
+
begin
|
43
|
+
@serial_mutex_rcv.synchronize {
|
44
|
+
while !@serial_sp.eof? || wait
|
45
|
+
begin
|
46
|
+
@serial_replies.push rep = @serial_sp.readline.chomp
|
47
|
+
break if rep == wait
|
48
|
+
rescue EOFError => e
|
49
|
+
dputs(4) { 'Waited for string, but got nothing' }
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
}
|
54
|
+
|
55
|
+
while m = @serial_replies.shift
|
56
|
+
@serial_debug and dputs_func
|
57
|
+
next if (m == '' || m =~ /^\^/)
|
58
|
+
dputs(3) { "Reply: #{m}" }
|
59
|
+
ret.push m
|
60
|
+
if m =~ /\+[\w]{4}: /
|
61
|
+
code, msg = m[1..4], m[7..-1]
|
62
|
+
dputs(2) { "found code #{code.inspect} - #{msg.inspect}" }
|
63
|
+
@serial_codes[code] = msg
|
64
|
+
case code
|
65
|
+
when /CMGL/
|
66
|
+
sms_id, sms_flag, sms_number, sms_unknown, sms_date =
|
67
|
+
msg.scan(/(".*?"|[^",]+\s*|,,)/).flatten
|
68
|
+
ret.push @serial_replies.shift
|
69
|
+
@serial_sms[sms_id] = [sms_flag, sms_number, sms_unknown, sms_date,
|
70
|
+
ret.last]
|
71
|
+
@serial_sms_new.each { |s|
|
72
|
+
s.call(@serial_sms, sms_id)
|
73
|
+
}
|
74
|
+
when /CUSD/
|
75
|
+
if pdu = msg.match(/.*\"(.*)\".*/)
|
76
|
+
ussd_received(pdu_to_ussd(pdu[1]))
|
77
|
+
elsif msg == '2'
|
78
|
+
log_msg :serialmodem, 'Closed USSD.'
|
79
|
+
#ussd_received('')
|
80
|
+
#ussd_close
|
81
|
+
else
|
82
|
+
log_msg :serialmodem, "Unknown: CUSD - #{msg}"
|
83
|
+
end
|
84
|
+
when /CMTI/
|
85
|
+
if msg =~ /^.ME.,/
|
86
|
+
dputs(2) { "I think I got a new message: #{msg}" }
|
87
|
+
sms_scan true
|
88
|
+
else
|
89
|
+
log_msg :serialmodem, "Unknown: CMTI - #{msg}"
|
90
|
+
end
|
91
|
+
@serial_eats_sms and modem_send('AT+CNMI=0,0,0,0,0', 'OK')
|
92
|
+
# Probably a message or so - '+CMTI: "ME",0' is a new message
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
rescue IOError => e
|
97
|
+
raise e
|
98
|
+
=begin
|
99
|
+
rescue Exception => e
|
100
|
+
puts "#{e.inspect}"
|
101
|
+
puts "#{e.to_s}"
|
102
|
+
puts e.backtrace
|
103
|
+
=end
|
104
|
+
end
|
105
|
+
ret
|
106
|
+
end
|
107
|
+
|
108
|
+
def modem_send(str, reply = true)
|
109
|
+
return unless @serial_sp
|
110
|
+
@serial_debug and dputs_func
|
111
|
+
dputs(3) { "Sending string #{str} to modem" }
|
112
|
+
@serial_mutex_send.synchronize {
|
113
|
+
begin
|
114
|
+
@serial_sp.write("#{str}\r\n")
|
115
|
+
rescue Errno::EIO => e
|
116
|
+
log_msg :SerialModem, "Couldn't write to device"
|
117
|
+
kill
|
118
|
+
return
|
119
|
+
rescue Errno::ENODEV => e
|
120
|
+
log_msg :SerialModem, 'Device is not here anymore'
|
121
|
+
kill
|
122
|
+
return
|
123
|
+
end
|
124
|
+
}
|
125
|
+
read_reply(reply)
|
126
|
+
end
|
127
|
+
|
128
|
+
def switch_to_hilink
|
129
|
+
modem_send('AT^U2DIAG=119', 'OK')
|
130
|
+
end
|
131
|
+
|
132
|
+
def save_modem
|
133
|
+
modem_send('AT^U2DIAG=0', 'OK')
|
134
|
+
end
|
135
|
+
|
136
|
+
def ussd_to_pdu(str)
|
137
|
+
str.unpack('b*').join.scan(/.{8}/).map { |s| s[0..6] }.join.
|
138
|
+
scan(/.{1,8}/).map { |s| [s].pack('b*').unpack('H*')[0].upcase }.join
|
139
|
+
end
|
140
|
+
|
141
|
+
def pdu_to_ussd(str)
|
142
|
+
[str].pack('H*').unpack('b*').join.scan(/.{7}/).
|
143
|
+
map { |s| [s+"0"].pack('b*') }.join
|
144
|
+
end
|
145
|
+
|
146
|
+
def ussd_send_now
|
147
|
+
return unless @serial_ussd.length > 0
|
148
|
+
str_send = @serial_ussd.first
|
149
|
+
@serial_ussd_last = Time.now
|
150
|
+
if str_send
|
151
|
+
log_msg :SerialModem, "Sending ussd-string #{str_send} with add of #{@ussd_add} "+
|
152
|
+
"and queue #{@serial_ussd}"
|
153
|
+
modem_send("AT+CUSD=1,\"#{ussd_to_pdu(str_send)}\"#{@ussd_add}", 'OK')
|
154
|
+
else
|
155
|
+
dputs(2) { 'Sending ussd-close' }
|
156
|
+
@serial_ussd.shift
|
157
|
+
ussd_close
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def ussd_close
|
162
|
+
modem_send("AT+CUSD=2#{@ussd_add}", 'OK')
|
163
|
+
@serial_ussd.length > 0 and ussd_send_now
|
164
|
+
end
|
165
|
+
|
166
|
+
def ussd_send(str)
|
167
|
+
if str.class == String
|
168
|
+
dputs(3) { "Sending ussd-code #{str}" }
|
169
|
+
@serial_ussd.push str
|
170
|
+
@serial_ussd.length == 1 and ussd_send_now
|
171
|
+
elsif str.class == Array
|
172
|
+
dputs(3) { "Sending menu-command #{str}" }
|
173
|
+
@serial_ussd.concat str
|
174
|
+
@serial_ussd.push nil
|
175
|
+
@serial_ussd.length == str.length + 1 and ussd_send_now
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def ussd_store_result(str)
|
180
|
+
if @serial_ussd.length > 0
|
181
|
+
code = @serial_ussd.shift
|
182
|
+
dputs(2) { "Got USSD-reply for #{code}: #{str}" }
|
183
|
+
@serial_ussd_results.push(time: Time.now.strftime('%H:%M'),
|
184
|
+
code: code, result: str)
|
185
|
+
@serial_ussd_results.shift([0, @serial_ussd_results.length -
|
186
|
+
@serial_ussd_results_max].max)
|
187
|
+
ussd_send_now
|
188
|
+
code
|
189
|
+
else
|
190
|
+
log_msg :serialmodem, "Got unasked code #{str}"
|
191
|
+
'unknown'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def ussd_received(str)
|
196
|
+
code = ussd_store_result(str)
|
197
|
+
dputs(2) { "Got result for #{code}: -#{str}-" }
|
198
|
+
@serial_ussd_new.each { |s|
|
199
|
+
s.call(code, str)
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
def ussd_fetch(str)
|
204
|
+
return nil unless @serial_ussd_results
|
205
|
+
dputs(3) { "Fetching str #{str} - #{@serial_ussd_results.inspect}" }
|
206
|
+
res = @serial_ussd_results.reverse.find { |u| u._code == str }
|
207
|
+
res ? res._result : nil
|
208
|
+
end
|
209
|
+
|
210
|
+
def sms_send(number, msg)
|
211
|
+
modem_send('AT+CMGF=1', 'OK')
|
212
|
+
modem_send("AT+CMGS=\"#{number}\"")
|
213
|
+
modem_send("#{msg}\x1a", 'OK')
|
214
|
+
end
|
215
|
+
|
216
|
+
def sms_scan(force = false)
|
217
|
+
if force || (@serial_sms_autoscan > 0 &&
|
218
|
+
Time.now - @serial_sms_autoscan_last > @serial_sms_autoscan)
|
219
|
+
dputs(3) { 'Auto-scanning sms' }
|
220
|
+
@serial_sms_autoscan_last = Time.now
|
221
|
+
modem_send('AT+CMGF=1', 'OK')
|
222
|
+
modem_send('AT+CMGL="ALL"', 'OK')
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def sms_delete(number)
|
227
|
+
dputs(3) { "Asking to delete #{number} from #{@serial_sms.inspect}" }
|
228
|
+
if @serial_sms.has_key? number
|
229
|
+
dputs(3) { "Deleting #{number}" }
|
230
|
+
modem_send("AT+CMGD=#{number}", 'OK')
|
231
|
+
@serial_sms.delete number
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def get_operator
|
236
|
+
modem_send('AT+COPS=3,0', 'OK')
|
237
|
+
modem_send('AT+COPS?', 'OK')
|
238
|
+
(1..6).each {
|
239
|
+
if @serial_codes.has_key? 'COPS'
|
240
|
+
return '' if @serial_codes['COPS'] == '0'
|
241
|
+
@serial_eats_sms and modem_send('AT+CNMI=0,0,0,0,0', 'OK')
|
242
|
+
op = @serial_codes['COPS'].scan(/".*?"|[^",]\s*|,,/)[2].gsub(/"/, '')
|
243
|
+
dputs(2) { "Found operator-string #{op}" }
|
244
|
+
return op
|
245
|
+
end
|
246
|
+
sleep 0.5
|
247
|
+
}
|
248
|
+
return ''
|
249
|
+
end
|
250
|
+
|
251
|
+
def set_connection_type(net, modem = :e303)
|
252
|
+
# According to https://wiki.archlinux.org/index.php/3G_and_GPRS_modems_with_pppd
|
253
|
+
cmds = {e303: {c3go: '14,2,3FFFFFFF,0,2', c3g: '2,2,3FFFFFFF,0,2',
|
254
|
+
c2go: '13,1,3FFFFFFF,0,2', c2g: '2,1,3FFFFFFF,0,2'}}
|
255
|
+
modem_send "AT^SYSCFG=#{cmds[modem]["c#{net}".to_sym]}", 'OK'
|
256
|
+
end
|
257
|
+
|
258
|
+
def traffic_statistics
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
def init_modem
|
263
|
+
%w( ATZ
|
264
|
+
AT+CNMI=0,0,0,0,0
|
265
|
+
AT+CPMS="SM","SM","SM"
|
266
|
+
AT+CFUN=1
|
267
|
+
AT+CMGF=1 ).each { |at| modem_send(at, 'OK') }
|
268
|
+
@serial_eats_sms and modem_send('AT+CNMI=0,0,0,0,0', 'OK')
|
269
|
+
set_connection_type '3g'
|
270
|
+
end
|
271
|
+
|
272
|
+
def setup_tty
|
273
|
+
check_presence
|
274
|
+
|
275
|
+
@serial_mutex_rcv.synchronize {
|
276
|
+
if !@serial_sp && @serial_tty
|
277
|
+
if File.exists? @serial_tty
|
278
|
+
log_msg :SerialModem, 'setting up SerialPort'
|
279
|
+
@serial_sp = SerialPort.new(@serial_tty, 115200)
|
280
|
+
@serial_sp.read_timeout = 500
|
281
|
+
end
|
282
|
+
elsif @serial_sp &&
|
283
|
+
(!@serial_tty||(@serial_tty && !File.exists?(@serial_tty)))
|
284
|
+
log_msg :SerialModem, 'disconnecting modem'
|
285
|
+
kill
|
286
|
+
end
|
287
|
+
}
|
288
|
+
if @serial_sp
|
289
|
+
log_msg :SerialModem, 'initialising modem'
|
290
|
+
init_modem
|
291
|
+
start_serial_thread
|
292
|
+
if !@serial_sp
|
293
|
+
log_msg :SerialModem, 'Lost serial-connection while initialising - trying again'
|
294
|
+
kill
|
295
|
+
reload_option
|
296
|
+
setup_tty
|
297
|
+
return
|
298
|
+
end
|
299
|
+
log_msg :SerialModem, 'finished connecting'
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def check_presence
|
304
|
+
@serial_mutex_rcv.synchronize {
|
305
|
+
@serial_tty.to_s.length > 0 and File.exists?(@serial_tty) and return
|
306
|
+
case lsusb = System.run_str('lsusb')
|
307
|
+
when /12d1:1506/, /12d1:14ac/, /12d1:1c05/
|
308
|
+
log_msg :SerialModem, 'Found 3G-modem with ttyUSB0-ttyUSB2'
|
309
|
+
@serial_tty_error = '/dev/ttyUSB3'
|
310
|
+
@serial_tty = '/dev/ttyUSB2'
|
311
|
+
@ussd_add = (lsusb =~ /12d1:14ac/) ? ',15' : ''
|
312
|
+
@serial_eats_sms = true
|
313
|
+
when /airtel-modem/
|
314
|
+
log_msg :SerialModem, 'Found 3G-modem with ttyUSB0-ttyUSB4'
|
315
|
+
@serial_tty_error = '/dev/ttyUSB5'
|
316
|
+
@serial_tty = '/dev/ttyUSB4'
|
317
|
+
@ussd_add = ''
|
318
|
+
else
|
319
|
+
#puts caller.join("\n")
|
320
|
+
@serial_tty = @serial_tty_error = nil
|
321
|
+
end
|
322
|
+
log_msg(:SerialModem, "serial_tty is #{@serial_tty.inspect} and exists " +
|
323
|
+
"#{File.exists?(@serial_tty.to_s)}")
|
324
|
+
if @serial_tty_error && File.exists?(@serial_tty_error)
|
325
|
+
log_msg :SerialModem, 'resetting modem'
|
326
|
+
reload_option
|
327
|
+
end
|
328
|
+
}
|
329
|
+
end
|
330
|
+
|
331
|
+
def start_serial_thread
|
332
|
+
@serial_thread = Thread.new {
|
333
|
+
#dputs_func
|
334
|
+
log_msg :SerialModem, 'Thread started'
|
335
|
+
loop {
|
336
|
+
begin
|
337
|
+
dputs(5) { 'Reading out modem' }
|
338
|
+
if read_reply.length == 0
|
339
|
+
@serial_sms_to_delete.each { |id|
|
340
|
+
dputs(3) { "Deleting sms #{id} afterwards" }
|
341
|
+
sms_delete(id)
|
342
|
+
}
|
343
|
+
@serial_sms_to_delete = []
|
344
|
+
end
|
345
|
+
|
346
|
+
dputs(4) { (Time.now - @serial_ussd_last).to_s }
|
347
|
+
if (Time.now - @serial_ussd_last > @serial_ussd_timeout) &&
|
348
|
+
(@serial_ussd.length > 0)
|
349
|
+
log_msg :SerialModem, "Re-sending #{@serial_ussd.first}"
|
350
|
+
ussd_send_now
|
351
|
+
end
|
352
|
+
|
353
|
+
sms_scan
|
354
|
+
|
355
|
+
sleep 0.5
|
356
|
+
rescue IOError
|
357
|
+
log_msg :SerialModem, 'IOError - killing modem'
|
358
|
+
kill
|
359
|
+
return
|
360
|
+
end
|
361
|
+
dputs(5) { 'Finished' }
|
362
|
+
}
|
363
|
+
dputs(1) { 'Finished thread' }
|
364
|
+
}
|
365
|
+
end
|
366
|
+
|
367
|
+
def reload_option
|
368
|
+
@serial_sp and @serial_sp.close
|
369
|
+
@serial_sp = nil
|
370
|
+
dputs(1) { 'Trying to reload modem-driver - killing and reloading' }
|
371
|
+
%w( chat ppp).each { |pro|
|
372
|
+
System.run_str("killall -9 #{pro}")
|
373
|
+
}
|
374
|
+
%w(rmmod modprobe).each { |cmd|
|
375
|
+
System.run_str("#{cmd} option")
|
376
|
+
}
|
377
|
+
end
|
378
|
+
|
379
|
+
def kill
|
380
|
+
#dputs_func
|
381
|
+
if @serial_thread
|
382
|
+
if @serial_thread.alive?
|
383
|
+
dputs(3) { 'Killing thread' }
|
384
|
+
@serial_thread.kill
|
385
|
+
dputs(3) { 'Joining thread' }
|
386
|
+
@serial_thread.join
|
387
|
+
dputs(3) { 'Thread joined' }
|
388
|
+
end
|
389
|
+
end
|
390
|
+
@serial_sp and @serial_sp.close
|
391
|
+
dputs(1) { 'SerialModem killed' }
|
392
|
+
@serial_sp = nil
|
393
|
+
end
|
394
|
+
|
395
|
+
def attached?
|
396
|
+
@serial_sp != nil
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|
data/serialmodem.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'SerialModem'
|
7
|
+
spec.version = '0.2.1'
|
8
|
+
spec.authors = ['Linus Gasser']
|
9
|
+
spec.email = ['ineiti@linusetviviane.ch']
|
10
|
+
spec.summary = %q{Interface to serial-usb-modems}
|
11
|
+
spec.description = %q{This can interface a lot of different usb-modems}
|
12
|
+
spec.homepage = 'https://github.com/ineiti/SerialModem'
|
13
|
+
spec.license = 'GPLv3'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
spec.add_runtime_dependency 'serialport', '1.3.1'
|
23
|
+
end
|
data/test/run_test
ADDED
data/test/test_hw.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
#$LOAD_PATH.push '../lib'
|
3
|
+
DEBUG_LVL=5
|
4
|
+
|
5
|
+
require 'serialmodem'
|
6
|
+
include SerialModem
|
7
|
+
|
8
|
+
def main
|
9
|
+
test_send_ussd
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_remove
|
13
|
+
setup_modem
|
14
|
+
check_presence
|
15
|
+
sleep 3
|
16
|
+
kill
|
17
|
+
sleep 5
|
18
|
+
reload_option
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_send_ussd
|
22
|
+
setup_modem
|
23
|
+
#check_presence
|
24
|
+
ussd_send('*100#')
|
25
|
+
sleep 5
|
26
|
+
dp 'done'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_old
|
30
|
+
setup_modem nil
|
31
|
+
check_presence
|
32
|
+
#set_connection_type '2go'
|
33
|
+
#sleep 10
|
34
|
+
ussd_send('*128#')
|
35
|
+
sleep 5
|
36
|
+
#set_connection_type '3g'
|
37
|
+
#sleep 10
|
38
|
+
#ussd_send('*128#')
|
39
|
+
#sleep 10
|
40
|
+
#ussd_send('*128#')
|
41
|
+
#sleep 10
|
42
|
+
#sleep 1
|
43
|
+
#ussd_send('*128#')
|
44
|
+
#sms_send('93999699', 'SMS from Dreamplug')
|
45
|
+
#sms_send('100', 'internet')
|
46
|
+
#sms_scan
|
47
|
+
#sleep 10
|
48
|
+
#ussd_send('*100#')
|
49
|
+
#sms_scan
|
50
|
+
#@huawei_sms.each{|k,v| puts "#{k}: #{v.inspect}"}
|
51
|
+
#sms_scan
|
52
|
+
#sms_delete( 0 )
|
53
|
+
#sms_scan
|
54
|
+
#sleep 10
|
55
|
+
#puts SerialModem::send_modem('atz')
|
56
|
+
#sleep 10
|
57
|
+
end
|
58
|
+
|
59
|
+
main
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: SerialModem
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Linus Gasser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: serialport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.1
|
55
|
+
description: This can interface a lot of different usb-modems
|
56
|
+
email:
|
57
|
+
- ineiti@linusetviviane.ch
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".idea/encodings.xml"
|
64
|
+
- ".idea/misc.xml"
|
65
|
+
- ".idea/modules.xml"
|
66
|
+
- ".idea/scopes/scope_settings.xml"
|
67
|
+
- ".idea/vcs.xml"
|
68
|
+
- ".idea/workspace.xml"
|
69
|
+
- Gemfile
|
70
|
+
- LICENSE.txt
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- commit
|
74
|
+
- lib/serialmodem.rb
|
75
|
+
- serialmodem.gemspec
|
76
|
+
- test/run_test
|
77
|
+
- test/test_hw.rb
|
78
|
+
homepage: https://github.com/ineiti/SerialModem
|
79
|
+
licenses:
|
80
|
+
- GPLv3
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.2.2
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Interface to serial-usb-modems
|
102
|
+
test_files:
|
103
|
+
- test/run_test
|
104
|
+
- test/test_hw.rb
|