summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md2
-rw-r--r--simulation.scm152
2 files changed, 108 insertions, 46 deletions
diff --git a/TODO.md b/TODO.md
index d825e6f..2b88087 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,7 +1,5 @@
# TODO
-- Two communications with different SF in the same channel are not an
- interference
- Control the ACK of the ACK (End device confirming an ACK): This requires
something acting as a Network Server <<--
- Time-on-air
diff --git a/simulation.scm b/simulation.scm
index 6af1357..a2d8283 100644
--- a/simulation.scm
+++ b/simulation.scm
@@ -67,17 +67,69 @@
(define (seconds->time-unit s)
(* internal-time-units-per-second s))
+;; Virtual channel is a combination of radio frequency and data-rate/sf
+;; Radio communication that happens in the same radio channel (same freq) but
+;; with different spreading factor does not trigger an interference
+(define-record-type <vchannel>
+ (make-vchannel freq dr)
+ vchannel?
+ (freq vchannel-freq) ; kHz
+ (dr vchannel-dr))
+
+;; Window channel and DR parameters:
+;; These are default values. `RXParamSetupReq` MAC command can be used to
+;; change them
+(define RX2-vchannel-EU863-870 (make-vchannel 869525 0))
+(define RX2-vchannel-US902-928 (make-vchannel 923300 8))
+(define RX1DROffset 0)
+
+(define (upstream-vchannel->RX1-vchannel-EU863-870 vchan RX1DROffset)
+ (define (upstream-dr->downstream-dr dr)
+ (match dr
+ ((? (lambda (x) (< x 8)))
+ (if (> RX1DROffset dr) 0 (- dr RX1DROffset)))
+ ((or 8 10)
+ (if (= RX1DROffset 0) 1 0))
+ ((or 9 11)
+ (match RX1DROffset (0 2) (1 1) (_ 0)))))
+ (make-vchannel (vchannel-freq vchan)
+ (upstream-dr->downstream-dr (vchannel-dr vchan))))
+
+(define (upstream-vchannel->RX1-vchannel-US903-928 vchan RX1DROffset)
+ (define (upstream-dr->downstream-dr dr)
+ (match dr
+ ((or 0 5) (if (= 3 RX1DROffset) 8 (- 10 RX1DROffset)))
+ ((or 1 2 3) (- (+ 10 dr) RX1DROffset))
+ (6 (- 11 RX1DROffset))
+ (4 (if (= 0 RX1DROffset) 13 (- 13 RX1DROffset)))))
+ (make-vchannel (vchannel-freq vchan)
+ (upstream-dr->downstream-dr (vchannel-dr vchan))))
+
+(define (product f l1 l2)
+ (concatenate (map (lambda (x) (map (lambda (y) (f x y)) l2)) l1)))
+
+;; Minimum set of vchannels for EU
+(define initial-vchannels-EU863-870
+ (product make-vchannel (list 868100 868300 868500) (iota 6)))
+
+;; All the defined vchannels for the US
+(define vchannels-US903-928-uplink
+ (append (product make-vchannel (iota 64 902300 200) (iota 4))
+ (map make-vchannel (iota 8 903000 1600) (iota 8 4 0))))
+(define vchannels-US903-928-downlink
+ (product make-vchannel (iota 8 923300 600) (iota (- 13 7) 8)))
+
;; For End-Device <--> Radio <--> Gateway
;; type can be:
;; '[up/down]link-start
;; '[up/down]link-end
;; 'interference
(define-record-type <radio-event>
- (make-radio-event type id channel-n frame)
+ (make-radio-event type id vchannel frame)
radio-event?
(type radio-event-type)
(id radio-event-id) ;; Match the start-interference-end events
- (channel-n radio-event-channel-n)
+ (vchannel radio-event-vchannel)
(frame radio-event-frame))
;; For Gateway <--> Network Server
@@ -111,13 +163,13 @@
(define (rand-time)
(random 2.))
-(define (make-class-a id initial-channel upstream-chn downstream-chn)
+(define (make-class-a id initial-vchannel upstream-chn downstream-chn)
(define window (make-channel))
;; Activates/deactivates the message sink to avoid blocking on messages we
;; don't need
(define internal-com (make-channel))
;; Make all atomic
- (define channel initial-channel)
+ (define vchannel initial-vchannel)
;; TODO: Unhardcode me
(define time-on-air 0.01)
@@ -134,15 +186,15 @@
'()
(if confirmed? 'confirmed-data 'unconfirmed-data))))
(put-message upstream-chn
- (make-radio-event 'uplink-start event-id channel frame))
+ (make-radio-event 'uplink-start event-id vchannel frame))
(sleep time-on-air)
(put-message upstream-chn
- (make-radio-event 'uplink-end event-id channel frame))))
+ (make-radio-event 'uplink-end event-id vchannel frame))))
- (define (receive-window channel time)
- (define (listening-to? chn)
- (= channel chn))
+ (define (receive-window vchannel time)
+ (define (listening-to? vchn)
+ (equal? vchannel vchn))
(define (detect-preamble)
(let wait-for-downlink-start ()
@@ -200,10 +252,10 @@
(RX1-start (+ now (seconds->time-unit RECEIVE_DELAY1)))
(RX2-start (+ now (seconds->time-unit RECEIVE_DELAY2)))
(downlink (or (begin (wait-until RX1-start)
- (receive-window channel RX1))
+ (receive-window vchannel RX1))
(if (< (get-internal-real-time) RX2-start)
(begin (wait-until RX2-start)
- (receive-window channel RX2))
+ (receive-window vchannel RX2))
#f))))
(when downlink (process-downlink! downlink)))))
@@ -232,13 +284,14 @@
(spawn-fiber
(lambda ()
;; TODO: choose channel properly
- (let ((event-id (new-id)))
+ (let ((event-id (new-id))
+ (vchannel (make-vchannel 50000000 0))) ;; TODO: hehe invented!
(ll "Gateway ~a sending downlink ~a" id frame)
(put-message radio
- (make-radio-event 'downlink-start event-id 1 frame))
+ (make-radio-event 'downlink-start event-id vchannel frame))
(sleep time-on-air)
(put-message radio
- (make-radio-event 'downlink-end event-id 1 frame))))))
+ (make-radio-event 'downlink-end event-id vchannel frame))))))
(define (send-to-network-server x)
(ll "Gateway ~a forwarding ~a" id x)
@@ -251,10 +304,10 @@
(match ev
(($ <network-event> id frame)
(send-to-device frame))
- (($ <radio-event> 'uplink-start event-id channel-n frame) #f)
- (($ <radio-event> 'interference event-id channel-n frame)
+ (($ <radio-event> 'uplink-start event-id vchannel frame) #f)
+ (($ <radio-event> 'interference event-id vchannel frame)
(set! pending-interferences (cons ev pending-interferences)))
- (($ <radio-event> 'uplink-end event-id channel-n frame)
+ (($ <radio-event> 'uplink-end event-id vchannel frame)
(let-values (((mine not-mine)
(partition (lambda (x) (eq? (radio-event-id x)
(radio-event-id ev)))
@@ -268,17 +321,17 @@
"Fiber for radio resource allocation/control."
;; We can access it only from one fiber! Careful!
- (define lorawan-channels (make-hash-table))
+ (define lorawan-vchannels (make-hash-table))
(define (interferences ev chn)
- (let ((res (hash-table-ref/default lorawan-channels chn '())))
+ (let ((res (hash-table-ref/default lorawan-vchannels chn '())))
(if (equal? res (list ev)) '() res)))
- (define (use-lorawan-channel! chn start-event)
- (hash-table-update!/default lorawan-channels chn
+ (define (use-vchannel! chn start-event)
+ (hash-table-update!/default lorawan-vchannels chn
(lambda (event-list)
(cons start-event event-list))
'()))
- (define (release-lorawan-channel! chn end-event)
- (hash-table-update! lorawan-channels chn
+ (define (release-vchannel! chn end-event)
+ (hash-table-update! lorawan-vchannels chn
(lambda (event-list)
(remove! (lambda (x) (eq? (radio-event-id x)
(radio-event-id end-event)))
@@ -286,20 +339,21 @@
(define (radio-event->interference ev)
"Make a new radio-event of type 'interference from another radio-event"
(match ev
- (($ <radio-event> type id channel-n frame)
- (make-radio-event 'interference id channel-n frame))))
+ (($ <radio-event> type id vchannel frame)
+ (make-radio-event 'interference id vchannel frame))))
(lambda ()
(forever
(let ((ev (get-message in)))
(match ev
- (($ <radio-event> 'uplink-start event-id channel-n frame)
- (ll "Device ~a started uplink-frame #~a on channel ~a"
+ (($ <radio-event> 'uplink-start event-id vchannel frame)
+ (ll "Device ~a started uplink-frame #~a on freq ~a DR ~a"
(frame-DeviceAddr frame)
(frame-FCnt frame)
- channel-n)
- (use-lorawan-channel! channel-n ev)
- (let ((ints (interferences ev channel-n)))
+ (vchannel-freq vchannel)
+ (vchannel-dr vchannel))
+ (use-vchannel! vchannel ev)
+ (let ((ints (interferences ev vchannel)))
(hash-table-walk gateways
(lambda (k gateway)
(spawn-fiber
@@ -312,15 +366,16 @@
(radio-event->interference ev)))
ints)))))))
- (($ <radio-event> 'downlink-start event-id channel-n frame)
- (ll "Device ~a started downlink-frame #~a on channel ~a"
+ (($ <radio-event> 'downlink-start event-id vchannel frame)
+ (ll "Device ~a started downlink-frame #~a on freq ~a DR ~a"
(frame-DeviceAddr frame)
(frame-FCnt frame)
- channel-n)
- (use-lorawan-channel! channel-n ev)
+ (vchannel-freq vchannel)
+ (vchannel-dr vchannel))
+ (use-vchannel! vchannel ev)
(let ((chan (device-channel
(hash-table-ref end-devices (frame-DeviceAddr frame))))
- (ints (interferences ev channel-n)))
+ (ints (interferences ev vchannel)))
(put-message chan ev)
(for-each
(lambda (ev)
@@ -328,24 +383,26 @@
(put-message chan (radio-event->interference ev)))
ints)))
- (($ <radio-event> 'uplink-end event-id channel-n frame)
- (ll "Device ~a ended uplink-frame #~a on channel ~a"
+ (($ <radio-event> 'uplink-end event-id vchannel frame)
+ (ll "Device ~a ended uplink-frame #~a on freq ~a DR ~a"
(frame-DeviceAddr frame)
(frame-FCnt frame)
- channel-n)
- (release-lorawan-channel! channel-n ev)
+ (vchannel-freq vchannel)
+ (vchannel-dr vchannel))
+ (release-vchannel! vchannel ev)
(hash-table-walk gateways
(lambda (k gateway)
(spawn-fiber
(lambda ()
(put-message (device-channel gateway) ev))))))
- (($ <radio-event> 'downlink-end event-id channel-n frame)
- (ll "Device ~a ended downlink-frame #~a on channel ~a"
+ (($ <radio-event> 'downlink-end event-id vchannel frame)
+ (ll "Device ~a ended downlink-frame #~a on freq ~a DR ~a"
(frame-DeviceAddr frame)
(frame-FCnt frame)
- channel-n)
- (release-lorawan-channel! channel-n ev)
+ (vchannel-freq vchannel)
+ (vchannel-dr vchannel))
+ (release-vchannel! vchannel ev)
(put-message
(device-channel (hash-table-ref end-devices
(frame-DeviceAddr frame)))
@@ -389,7 +446,14 @@
(let ((chn (make-channel)))
(hash-table-set!
end-devices id
- (make-device chn (make-class-a id (modulo id 3) radio-chn chn)))))
+ (make-device chn
+ (make-class-a
+ id
+ ;; TODO: generalize for the US too?
+ (list-ref initial-vchannels-EU863-870
+ (modulo id (length initial-vchannels-EU863-870)))
+ radio-chn
+ chn)))))
(iota end-device-count gateway-count))
(for-each