nRF24-ruby 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/bin/nRF24_udp.rb ADDED
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: UTF-8
3
+
4
+
5
+ require "pp"
6
+ require 'socket'
7
+ require 'json'
8
+ require 'uri'
9
+ require 'ipaddr'
10
+ require 'time'
11
+ require 'thread'
12
+
13
+
14
+ if File.file? './lib/nRF24-ruby.rb'
15
+ require './lib/nRF24-ruby.rb'
16
+ puts "using local lib"
17
+ else
18
+ require 'nRF24-ruby'
19
+ end
20
+
21
+ puts "\nPure Ruby nRF24 <-> UDP Bridge Starting..."
22
+
23
+ http=true
24
+ #http=false
25
+
26
+ if http
27
+ puts "Loading Http-server.. hold on.."
28
+ require 'minimal-http-ruby'
29
+ minimal_http_server http_port: 8088, http_path: "./http/"
30
+ puts "\n"
31
+ end
32
+
33
+ def open_port uri_s
34
+ begin
35
+ uri = URI.parse(uri_s)
36
+ if uri.scheme== 'udp'
37
+ return [UDPSocket.new,uri.host,uri.port]
38
+ else
39
+ raise "Error: Cannot open socket for '#{uri_s}', unsupported scheme: '#{uri.scheme}'"
40
+ end
41
+ rescue => e
42
+ pp e.backtrace
43
+ raise "Error: Cannot open socket for '#{uri_s}': #{e}"
44
+ end
45
+ end
46
+
47
+ def poll_packet socket
48
+ begin
49
+ r,stuff=socket.recvfrom_nonblock(200) #get_packet --high level func!
50
+ client_ip=stuff[2]
51
+ client_port=stuff[1]
52
+ return [r,client_ip,client_port]
53
+ rescue IO::WaitReadable
54
+ sleep 0.1
55
+ rescue => e
56
+ puts "Error: receive thread died: #{e}"
57
+ pp e.backtrace
58
+ end
59
+ return nil
60
+ end
61
+
62
+ def poll_packet_block socket
63
+ #decide how to get data -- UDP-socket or FM-radio
64
+ r,stuff=socket.recvfrom(200) #get_packet --high level func!
65
+ client_ip=stuff[2]
66
+ client_port=stuff[1]
67
+ return [r,client_ip,client_port]
68
+ end
69
+
70
+ def send_raw_packet msg,socket,server,port
71
+ if socket
72
+ if socket.class.name=="UDPSocket"
73
+ socket.send(msg, 0, server, port)
74
+ else
75
+ a=msg.unpack('c*')
76
+ socket.send_q << {msg: a, to: server, socket: port,ack:false}
77
+ end
78
+ #MqttSN::hexdump msg
79
+ else
80
+ puts "Error: no socket at send_raw_packet"
81
+ end
82
+ end
83
+
84
+
85
+ r0=NRF24.new id: :eka, ce: 22,cs: 27, irq: 17, chan:4, ack: false, mac: "A7:A7",mac_header: true
86
+ r1=NRF24.new id: :toka, ce: 24,cs: 23, irq: 22, chan: 4, ack: false, mac: "A5:A5",mac_header: true
87
+
88
+ s0,s0_host,s0_port=open_port("udp://20.20.20.21:1882") # our port for forwarder/broker connection
89
+ s1,s1_host,s1_port=open_port("udp://20.20.20.21:1882")
90
+ s1.bind("0.0.0.0",5555) # our port for clients
91
+ pp s0
92
+ pp s1
93
+ puts "Main Loop Starts:"
94
+
95
+ loopc=0;
96
+ sc=0;
97
+
98
+ def poll_packet_radio r
99
+ if not r.recv_q.empty? #get packets from broker's radio and send them to udp broker/forwader
100
+ msg=r.recv_q.pop
101
+ pac=msg[:msg].pack("c*")
102
+ len=msg[:msg][0]
103
+ if len<1 or len>30
104
+ puts "crap #{msg}"
105
+ return nil
106
+ end
107
+ if msg[:checksum]!=msg[:check]
108
+ puts "checksum error #{msg}"
109
+ return nil
110
+ end
111
+ pac=pac[0...len]
112
+ #puts "got #{msg}, '#{pac}'"
113
+ return [pac,msg[:from],msg[:socket] ]
114
+ end
115
+ return nil
116
+ end
117
+
118
+ # client s1 <-> r0
119
+
120
+ # forwarder s0 <-> r1
121
+
122
+ loop do
123
+ begin
124
+ if pac=poll_packet(s1) #get packets from client's via udp (s1) and send them to forwarder's radio
125
+ r,@client_ip,@client_port=pac
126
+ puts "UDP1(#{@client_ip}:#{@client_port})->RAD0(#{r1.mac}:#{4}): #{pac}"
127
+ #r0.send_q << {msg: msg, to: r1.mac, socket: 3,ack:false}
128
+ send_raw_packet r,r0,r1.mac,4
129
+ end
130
+
131
+ if pac=poll_packet_radio(r1) #this is forwarder receiving the packet from client -- and sendig it to broker at s0
132
+ r,client_ip,client_port=pac
133
+ puts "RAD1(#{client_ip}:#{client_port})->UDP0(#{s0_host}:#{s0_port}): #{pac}"
134
+ send_raw_packet r,s0,s0_host,s0_port
135
+ end
136
+
137
+
138
+ if pac=poll_packet(s0) #get packets from broker ... send to client via radio
139
+ r,client_ip,client_port=pac
140
+ puts "UDP0(#{client_ip}:#{client_port})->RAD1(#{r0.mac}:#{3}): #{pac}"
141
+ send_raw_packet r,r1,r0.mac,3
142
+ end
143
+
144
+ if pac=poll_packet_radio(r0) #this is client listening to radio r0 and getting the packet (via s1)
145
+ r,client_ip,client_port=pac
146
+ puts "RAD0(#{client_ip}:#{client_port})->UDP1(#{@client_ip}:#{@client_port}): #{pac}"
147
+ send_raw_packet r,s1,@client_ip,@client_port
148
+ end
149
+
150
+ rescue => e
151
+ puts "Error: receive thread died: #{e}"
152
+ pp e.backtrace
153
+ end
154
+ sleep 0.01
155
+ end
156
+
@@ -11,6 +11,7 @@ end
11
11
  puts "\nPure Ruby nRF24L01 Driver Starting..."
12
12
 
13
13
  http=true
14
+ #http=false
14
15
 
15
16
  if http
16
17
  puts "Loading Http-server.. hold on.."
@@ -19,39 +20,40 @@ if http
19
20
  puts "\n"
20
21
  end
21
22
 
22
- bmac="B2:B2:B3"
23
+ bmac="C7:C7:C7"
23
24
  NRF24::set_bmac bmac
24
- r0=NRF24.new id: :eka, ce: 22,cs: 27, irq: 17, chan:3, ack: false, mac: "00:A7:A7"
25
- r1=NRF24.new id: :toka, ce: 24,cs: 23, irq: 22, chan: 3, ack: false, mac: "00:A5:A5"
25
+ r0=NRF24.new id: :eka, ce: 22,cs: 27, irq: 17, chan:4, ack: false, mac: "A7:A7",mac_header: true
26
+ r1=NRF24.new id: :toka, ce: 24,cs: 23, irq: 22, chan: 4, ack: false, mac: "A5:A5",mac_header: true
26
27
 
27
28
  puts "Main Loop Starts: bmac: #{NRF24::get_bmac}"
28
29
 
29
30
  loopc=0;
30
31
  sc=0;
31
-
32
+ lista=[]
32
33
  loop do
33
34
  if (loopc%4)==0
34
35
  msg=[]
35
- str=sprintf "testing %5.5d -- testing?",sc%10000
36
+ str=sprintf "%5.5d",sc
37
+ lista<<sc
36
38
  sc+=1
37
39
  str.each_byte do |b|
38
40
  msg<<b
39
41
  end
40
42
  if sc&2==0
41
43
  if sc&1==0
42
- r0.send_q << {msg: msg, tx_mac: bmac}
44
+ r0.send_q << {msg: msg, socket: :broadcast}
43
45
  else
44
- r1.send_q << {msg: msg, tx_mac: bmac}
46
+ r1.send_q << {msg: msg, socket: :broadcast}
45
47
  end
46
48
  else
47
49
  if sc&1==0
48
50
  #r0.send_q << {msg: msg, tx_mac: r1.mac,ack:true}
49
- r0.send_q << {msg: msg, tx_mac: "FF:A5:A5",ack:true}
51
+ r0.send_q << {msg: msg, to: r1.mac, socket: 3,ack:true}
50
52
  else
51
- r1.send_q << {msg: msg, tx_mac: r0.mac,ack:true}
53
+ r1.send_q << {msg: msg, to: r0.mac, socket: 4,ack:true}
52
54
  end
53
55
  end
54
- NRF24::note "sent '#{str}' to #{sc&1}"
56
+ NRF24::note "lista:#{lista.size}"
55
57
  end
56
58
  loopc+=1
57
59
  while not r1.recv_q.empty?
@@ -59,25 +61,37 @@ loop do
59
61
  #puts "got 1 #{got}"
60
62
  msg=""
61
63
  len=0
62
- got.each_with_index do |b,i|
63
- msg[i]=b.chr
64
+ got[:msg].each_with_index do |b,i|
65
+ break if b==0x00
66
+ msg[i]=b.chr
64
67
  end
65
- NRF24::note "got #{msg} from 1!"
68
+ got[:msg]=msg
69
+ s=got[:msg].to_i
70
+ lista-=[s]
71
+ NRF24::note "i #{got}"
66
72
  end
67
73
  while not r0.recv_q.empty?
68
74
  got=r0.recv_q.pop
69
75
  #puts "got 0 #{got}"
70
76
  msg=""
71
77
  len=0
72
- got.each_with_index do |b,i|
73
- msg[i]=b.chr
78
+ got[:msg].each_with_index do |b,i|
79
+ msg[i]=b.chr if b!=0x00
74
80
  end
75
- NRF24::note "got #{msg} from 0!"
81
+ got[:msg]=msg
82
+ s=got[:msg].to_i
83
+ lista-=[s]
84
+ NRF24::note "i #{got}"
76
85
  end
77
86
  if not http
78
- pp r0.json
79
- pp r1.json
87
+ if NRF24::get_log.size>0
88
+ e=NRF24::get_log[0]
89
+ if e[:text][/lista/]
90
+ puts e
91
+ end
92
+ NRF24::get_log.shift
93
+ end
80
94
  end
81
- sleep 0.1
95
+ sleep 0.05
82
96
  end
83
97
 
data/http/json/action.rb CHANGED
@@ -20,7 +20,7 @@ def json_action request,args,session,event
20
20
  d.get_regs true
21
21
  else
22
22
  puts "initing #{d}"
23
- d.hw_init chan: chan, ack: aa, rf_dr: args['rf_dr'], rf_pwr: args['rf_pwr'], lna_hcurr: args['lna_hcurr']
23
+ d.hw_init chan: chan, ack: aa, rf_dr: args['rf_dr'], rf_pwr: args['rf_pwr'], lna_hcurr: args['lna_hcurr'],mac_header: true
24
24
  d.get_regs true
25
25
  end
26
26
  end
data/lib/nRF24-ruby.rb CHANGED
@@ -3,14 +3,16 @@
3
3
 
4
4
  require 'pp'
5
5
  require 'thread'
6
+ require 'time'
6
7
  require 'pi_piper'
8
+ require 'zlib'
7
9
  include PiPiper
8
10
 
9
11
  class NRF24
10
12
  @@all=[]
11
13
  @@PAYLOAD_SIZE=32
12
14
  @@SPI_CLOCK=250000
13
-
15
+
14
16
  @@regs={
15
17
  CONFIG: {address: 0x00,len:7},
16
18
  EN_AA: {address: 0x01,len:6},
@@ -36,7 +38,7 @@ class NRF24
36
38
  RX_PW_P4: {address: 0x15, format: :dec,hide: true},
37
39
  RX_PW_P5: {address: 0x16, format: :dec,hide: true},
38
40
  FIFO_STATUS: {address: 0x17, poll: 1, len:7},
39
- DYNPD: {address: 0x1C,len:6},
41
+ DYNPD: {address: 0x1C,len:6},
40
42
  FEATURE: {address: 0x1D,len:3},
41
43
  }
42
44
 
@@ -53,13 +55,12 @@ class NRF24
53
55
  ACTIVATE2: 0x73,
54
56
  }
55
57
 
56
- @@sem=Mutex.new
58
+ @@sem=Mutex.new
57
59
  @@log=[]
58
60
  @@bmac="45:45:45:45:45"
59
61
 
60
62
  def self.set_bmac mac
61
63
  @@bmac=mac
62
- puts "set bmac to #{mac}"
63
64
  end
64
65
 
65
66
  def self.note str,*args
@@ -72,7 +73,7 @@ class NRF24
72
73
  puts "note dies: #{e} '#{str}'"
73
74
  end
74
75
  end
75
-
76
+
76
77
  def get_ccode c
77
78
  ccode=@@cmds[c]
78
79
  if not ccode
@@ -95,8 +96,8 @@ class NRF24
95
96
  status=0
96
97
  cc=get_ccode(c)
97
98
  @@sem.synchronize do
98
- @cs.off
99
- PiPiper::Spi.begin do
99
+ @cs.off
100
+ PiPiper::Spi.begin do
100
101
  clock(@@SPI_CLOCK)
101
102
  status=write cc
102
103
  data.each do |byte|
@@ -116,14 +117,14 @@ class NRF24
116
117
  cc=get_ccode(:R_REGISTER) +i
117
118
  @@sem.synchronize do
118
119
  @cs.off
119
- PiPiper::Spi.begin do
120
+ PiPiper::Spi.begin do
120
121
  clock(@@SPI_CLOCK)
121
122
  status=write cc
122
123
  if bytes==1
123
124
  data=write(0xff)
124
125
  else
125
126
  data=[]
126
- bytes.times do
127
+ bytes.times do
127
128
  data << write(0xff)
128
129
  end
129
130
  end
@@ -157,6 +158,16 @@ class NRF24
157
158
  [@s[:status]]
158
159
  end
159
160
 
161
+ def calc_crc str
162
+ checksum=0
163
+ str.unpack("c*").each do |c|
164
+ checksum+=c.ord
165
+ end
166
+ checksum&=0xff
167
+ #puts "cc calc: '#{str}'' -> #{checksum}"
168
+ return checksum
169
+ end
170
+
160
171
  def send packet,hash={}
161
172
  pac=Array.new(@@PAYLOAD_SIZE, 0)
162
173
  packet.each_with_index do |byte,i|
@@ -164,12 +175,16 @@ class NRF24
164
175
  end
165
176
  @ce.off
166
177
  wreg :CONFIG,0x0a
178
+ #prepend our mac?
179
+ if @s[:params][:mac_header]
180
+ checksum= calc_crc(pac.pack("c*"))
181
+ pac= NRF24::mac2a(@mac, short:true)+[checksum]+pac
182
+ pac=pac[0...32]
183
+ end
167
184
  if hash[:ack] and @s[:params][:ack]
168
185
  cmd :W_TX_PAYLOAD,pac
169
- #puts "with ack"
170
186
  else
171
187
  cmd :W_TX_PAYLOAD_NOACK,pac
172
- #puts "with NOack"
173
188
  end
174
189
  @ce.on
175
190
  sleep 0.001
@@ -178,13 +193,6 @@ class NRF24
178
193
  @ce.on
179
194
  end
180
195
 
181
- def recv
182
- fifo_status,_=rreg :FIFO_STATUS
183
- if (fifo_status & 0x01) == 0x01
184
- puts "on dataa"
185
- end
186
- end
187
-
188
196
  def get_regs all
189
197
  @@regs.each do |k,r|
190
198
  next if not r[:poll] and not all
@@ -198,34 +206,48 @@ class NRF24
198
206
  begin
199
207
  loop do
200
208
  donesome=false
201
-
209
+ cflag=0
202
210
  s,d,b=rreg :FIFO_STATUS
203
211
  if (s&0x40) == 0x40
204
- NRF24::note "got RX_DR --received something"
205
- wreg :STATUS,0x40
212
+ #NRF24::note "got RX_DR --received something"
213
+ cflag|=0x40
206
214
  end
207
215
  if (s&0x20) == 0x20
208
- NRF24::note "got TX_DS --sent something"
216
+ #NRF24::note "got TX_DS --sent something"
209
217
  wreg :STATUS,0x20
218
+ cflag|=0x20
210
219
  end
211
220
  if (s&0x10) == 0x10
212
221
  NRF24::note "****************** got MAX_RT --send fails..."
213
- wreg :STATUS,0x10
222
+ cflag|=0x10
214
223
  @s[:sfail]+=1
215
224
  end
216
- if (d&0x01)==0x00
225
+ wreg(:STATUS,cflag) if cflag>0
226
+ while (d&0x01)==0x00
227
+ @s[:rfull]+=1 if (d&0x02)==0x02
217
228
  pipe=(s>>1)&0x05
218
- NRF24::note "pipe: #{pipe}"
219
- ret=cmd :R_RX_PAYLOAD,Array.new(@@PAYLOAD_SIZE, 0xff)
220
- @recv_q<<ret
221
- @s[:rcnt]+=1
222
- donesome=true
223
- end
224
- if (d&0x02)==0x02
229
+ if pipe==0
230
+ socket=:broadcast
231
+ else
232
+ socket=pipe-1
233
+ end
225
234
  ret=cmd :R_RX_PAYLOAD,Array.new(@@PAYLOAD_SIZE, 0xff)
226
- @recv_q<<ret
235
+ if @s[:params][:mac_header]
236
+ sender=NRF24::a2mac(ret[0..1])
237
+ checksum=ret[2]
238
+ ret.shift(3)
239
+ check= calc_crc(ret.pack("c*"))
240
+ if check!=checksum
241
+ puts "Error: Checksum error! Message Ignored!"
242
+ s,d,b=rreg :FIFO_STATUS
243
+ next
244
+ end
245
+ end
246
+ msg={msg:ret,socket:socket,from:sender,to:@mac,dir: :in,checksum:checksum,check:check}
247
+ @recv_q << msg
248
+ NRF24::note "i #{msg}"
227
249
  @s[:rcnt]+=1
228
- @s[:rfull]+=1
250
+ s,d,b=rreg :FIFO_STATUS
229
251
  donesome=true
230
252
  end
231
253
 
@@ -233,7 +255,6 @@ class NRF24
233
255
  if not @send_q.empty?
234
256
  if (d&0x20)==0x00
235
257
 
236
-
237
258
  s,d,b=rreg :OBSERVE_TX
238
259
  if (d&0x0f)!=0x00
239
260
  NRF24::note "got ARC_CNT:#{d&0x0f}******************"
@@ -241,9 +262,18 @@ class NRF24
241
262
  end
242
263
 
243
264
  msg=@send_q.pop
244
- wreg :TX_ADDR,NRF24::mac2a(msg[:tx_mac])
245
- #puts "send mac: #{msg[:tx_mac]}"
265
+ #puts "msg:#{msg}"
266
+ if msg[:socket]==:broadcast
267
+ to=NRF24::mac2a(NRF24::get_bmac)
268
+ else
269
+ to=NRF24::mac2a(msg[:to],socket: msg[:socket])
270
+ end
271
+ wreg :TX_ADDR, to
272
+ msg[:from]=@mac
273
+ msg[:dir]=:out
246
274
  send msg[:msg], ack:msg[:ack]
275
+ #msg[:msg]=msg[:msg].pack("c*")
276
+ NRF24::note "o #{msg}"
247
277
  @s[:scnt]+=1
248
278
  end
249
279
  end
@@ -299,19 +329,30 @@ class NRF24
299
329
  @@regs
300
330
  end
301
331
 
302
- def json
332
+ def json
303
333
  @s
304
334
  end
305
335
 
306
- def self.get_log
336
+ def self.get_log
307
337
  @@log
308
338
  end
309
339
 
310
- def self.mac2a mac
340
+ def self.a2mac a,hash={}
341
+ mac=""
342
+ a.each do |e|
343
+ mac+=":" if mac!=""
344
+ mac+=sprintf "%02X",e
345
+ end
346
+ mac
347
+ end
348
+
349
+ def self.mac2a mac,hash={}
311
350
  a=[]
312
351
  mac.split(":").each do |b|
313
352
  a<<b.hex
314
353
  end
354
+ a.unshift hash[:socket]||0 if a.size==2 and not hash[:short]
355
+ #pp a
315
356
  a
316
357
  end
317
358
 
@@ -326,7 +367,7 @@ class NRF24
326
367
  scnt: 0,
327
368
  sarc: 0,
328
369
  sfail: 0,
329
- }
370
+ }
330
371
  @id=hash[:id]
331
372
  wreg :CONFIG,0x0b
332
373
  rf_dr=(hash[:rf_dr]||1).to_i&0x01
@@ -354,37 +395,27 @@ class NRF24
354
395
  wreg :RX_PW_P5,@@PAYLOAD_SIZE
355
396
  wreg :TX_ADDR,NRF24::mac2a(@@bmac)
356
397
  wreg :RX_ADDR_P0,NRF24::mac2a(@@bmac)
357
- wreg :RX_ADDR_P2,0xfc
358
- wreg :RX_ADDR_P3,0xfd
359
- wreg :RX_ADDR_P4,0xfe
360
- wreg :RX_ADDR_P5,0xff
398
+
361
399
  if hash[:mac] #keep old if not defined
362
- wreg :RX_ADDR_P1,NRF24::mac2a(hash[:mac])
400
+ wreg :RX_ADDR_P1,NRF24::mac2a(hash[:mac])
363
401
  @mac=hash[:mac]
364
402
  else
365
- s,d,bytes,code =rreg :RX_ADDR_P1
366
- mac=""
367
- d.each do |b|
368
- mac+=":" if mac!=""
369
- mac+=sprintf "%02X",b
370
- end
371
- @mac=mac
372
- end
373
403
 
374
- # if hash[:ack]
375
- # cmd :ACTIVATE,[ 0]
376
- # else
377
- cmd :ACTIVATE,[ get_ccode(:ACTIVATE2)]
378
- # end
404
+ end
405
+ wreg :RX_ADDR_P2,1
406
+ wreg :RX_ADDR_P3,2
407
+ wreg :RX_ADDR_P4,3
408
+ wreg :RX_ADDR_P5,4
409
+ cmd :ACTIVATE,[ get_ccode(:ACTIVATE2)]
379
410
 
380
411
  cmd :FLUSH_TX
381
412
  cmd :FLUSH_RX
382
413
  end
383
414
 
384
415
  def initialize(hash={})
385
- @semh=Mutex.new
416
+ @semh=Mutex.new
417
+
386
418
 
387
-
388
419
  @ce=PiPiper::Pin.new(:pin => hash[:ce], :direction => :out)
389
420
  @cs=PiPiper::Pin.new(:pin => hash[:cs], :direction => :out)
390
421
 
@@ -397,7 +428,8 @@ class NRF24
397
428
 
398
429
  hw_init hash
399
430
 
400
- @server_t=rf_server
431
+ @server_t=rf_server
432
+ @server_t.priority=100
401
433
  @monitor_t=do_monitor
402
434
  end
403
435
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nRF24-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-28 00:00:00.000000000 Z
12
+ date: 2014-11-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minimal-http-ruby
@@ -46,12 +46,14 @@ dependencies:
46
46
  description: ! 'Pure Ruby Driver and Utilitity with Http-server for the Ultra Cheap
47
47
  Radio Chip nRF24 '
48
48
  email: jalopuuverstas@gmail.com
49
- executables: []
49
+ executables:
50
+ - nRF24_udp.rb
50
51
  extensions: []
51
52
  extra_rdoc_files: []
52
53
  files:
53
54
  - lib/nRF24-ruby.rb
54
55
  - examples/nRF24-demo.rb
56
+ - bin/nRF24_udp.rb
55
57
  - http/json/logger.rb
56
58
  - http/json/nRF24.rb
57
59
  - http/json/action.rb