diff options
-rw-r--r-- | TODO.md | 2 | ||||
-rw-r--r-- | simulation.scm | 152 |
2 files changed, 108 insertions, 46 deletions
@@ -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 |