diff options
author | Ekaitz Zarraga <ekaitz@elenq.tech> | 2024-12-16 19:48:07 +0100 |
---|---|---|
committer | Ekaitz Zarraga <ekaitz@elenq.tech> | 2024-12-16 19:48:07 +0100 |
commit | c08b9e84b072ad070052184b3849239cbb922033 (patch) | |
tree | b0cf034ed220de335a75cbda46a1bb96aeb0154b /simulation.scm | |
parent | 8bbd598025d52fe66613dedec5e1a990a88953b8 (diff) |
simulation: downlink acks work
Diffstat (limited to 'simulation.scm')
-rw-r--r-- | simulation.scm | 125 |
1 files changed, 86 insertions, 39 deletions
diff --git a/simulation.scm b/simulation.scm index ca30041..6661b32 100644 --- a/simulation.scm +++ b/simulation.scm @@ -6,10 +6,19 @@ #:use-module (ice-9 match) #:use-module (fibers) #:use-module (fibers channels) - #:use-module (fibers conditions) - #:use-module (fibers operations) #:use-module (fibers timers)) +(define RX1 1) ; s (has to be between 1-15s) +(define RX2 (1+ RX1)) ; s +(define RECEIVE_DELAY1 1) ; s +(define RECEIVE_DELAY2 (1+ RECEIVE_DELAY1)) ; s +;; From RP002 (Regional Parameters): +;; MAC commands exist in the LoRaWAN® specification to change the value of +;; RECEIVE_DELAY1 (using RXTimingSetupReq, RXTimingSetupAns) as well as +;; ADR_ACK_LIMIT and ADR_ACK_DELAY (using ADRParamSetupReq, ADRParamSetupAns). +;; Also, RXTimingSettings are transmitted to the end device along with the +;; JOIN_ACCEPT message in OTAA mode. + ;; TODO: put a time limit as a parameter (define-syntax-rule (forever exp ...) (let loop () @@ -20,19 +29,26 @@ (let ((now (gettimeofday))) (format #t "~a~a - ~?~%" (car now) (cdr now) f data))) +;; type can be: +;; 'start +;; 'end (define-record-type <event> (make-event type data) event? (type event-type) (data event-data)) +;; body can be: +;; 'unconfirmed-data (uplink) +;; 'confirmed-data (uplink) +;; 'ack (downlink) (define-record-type <message> (make-message id device-id channel-n uplink? body) message? (id message-id) (device-id message-device-id) (channel-n message-channel-n) - (uplink? message-uplink?) + (uplink? message-uplink?) ;; TODO: we could check this (body message-body)) (define-record-type <device> @@ -42,58 +58,84 @@ (thunk device-thunk)) (define (rand-time) - (random 20)) + (random 2)) (define (make-class-a id initial-channel upstream-chn downstream-chn) ;; Make all atomic (define channel initial-channel) - (define listening? (make-atomic-box #f)) ;; TODO: Unhardcode me - (define time-on-air 1) - (define rx1 1) - (define rx2 (+ 1 rx1)) - (define receive-delay-1 1) - (define receive-delay-2 2) - ;(define sent-to-confirm (make-vector)) + (define time-on-air 0.01) + (define to-confirm (make-atomic-box #f)) + + ;; Handle the receive windows + (define listening? (make-atomic-box #f)) + (define (start-listening!) + (ll "Device ~a started listening" id) + (atomic-box-set! listening? #t)) + (define (stop-listening!) + (ll "Device ~a stopped listening" id) + (atomic-box-set! listening? #f)) + (define (im-listening?) + (atomic-box-ref listening?)) + + (define (confirm message-id) + (when (eq? message-id (atomic-box-compare-and-swap! to-confirm message-id #f)) + (spawn-fiber + (lambda () "confirm confirmation message")))) (define (upstream) (define current-message 0) (forever - (sleep (rand-time)) - (let ((message (make-message current-message id channel #t 'data))) + (when (eq? #f (atomic-box-ref to-confirm)) + (ll "Device ~a waiting for data" id) + (sleep (rand-time))) ;; wait for more data + (let* ((confirmed? #t) ;; random? + (message (make-message + current-message + id + channel + #t + (if confirmed? 'confirmed-data 'unconfirmed-data)))) + (when confirmed? + (atomic-box-compare-and-swap! to-confirm #f current-message)) (put-message upstream-chn (make-event 'start message)) (sleep time-on-air) (put-message upstream-chn (make-event 'end message))) (set! current-message (1+ current-message)) - (sleep receive-delay-1) - (atomic-box-set! listening? #t) - ;; TODO: maybe synchronization doesn't work because we do too many things - (sleep rx1) - (atomic-box-set! listening? #f) - ;; (when not-answered ...) - (sleep (- receive-delay-2 receive-delay-1)) - (atomic-box-set! listening? #t) - (sleep rx2) - (atomic-box-set! listening? #f))) + (sleep RECEIVE_DELAY1) + (start-listening!) + (sleep RX1) + (stop-listening!) + (when (atomic-box-ref to-confirm) + (sleep (- RECEIVE_DELAY2 RECEIVE_DELAY1)) + (start-listening!) + (sleep RX2) + (stop-listening!)))) (define (downstream) (forever (let ((msg (get-message downstream-chn))) - (when (atomic-box-ref listening?) - (ll "Device: ~a Received: ~a" id msg) - #;(match (message-body msg) - (('ack) (confirm X))))))) + (when (im-listening?) + (match (message-body msg) + ('ack (confirm (message-id msg)))))))) (lambda () (spawn-fiber upstream) (spawn-fiber downstream))) (define (make-gateway id upstream downstream) - #;(define (ack-confirmed-data to channel seq-number) + (define time-on-air 0.01) ;s (TODO) + + (define (ack-confirmed-data to channel seq-number) (spawn-fiber - (sleep RX1) - (put-message downstream (make-message to channel 'ack seq-number)))) + ;; TODO: answer in the second window?? + (lambda () + (sleep RECEIVE_DELAY1) + (let ((message (make-message seq-number to channel #f 'ack))) + (put-message downstream (make-event 'start message)) + (sleep time-on-air) ;; TODO: size / data-rate + (put-message downstream (make-event 'end message)))))) ;; Upstream: listen, and answer in new fibers (lambda () @@ -102,17 +144,22 @@ (ll "Gateway ~a: Data #~a got from ~a" id (message-id msg) - (message-device-id msg)))))) + (message-device-id msg)) + (match (message-body msg) + ('confirmed-data + (ack-confirmed-data (message-device-id msg) + (message-channel-n msg) ;; TODO: not right + (message-id msg))) + ('unconfirmed-data #f)))))) (define (make-radio in end-devices gateways) - ;(define devices (hash-map ...)) ;; it needs a device-id <-> channel mapping - ;; in: listen from devices: check collisions and power transmission - ;; capabilities: we could check distance to other devices for this! - ;; (define started '()) + ;; TODO: this is broken, only accounts for the interference of the packet + ;; that was already being sent, and not from the new one that produced the + ;; interference => both should be affected. (define (interference? msg started-messages) (any (lambda (x) (= (message-channel-n msg) (message-channel-n x))) started-messages)) @@ -136,14 +183,14 @@ (remove! (lambda (x) (and (= (message-id msg) (message-id x)) (= (message-device-id msg) (message-device-id x)))) started)) - (if (interference? msg started) + (if (interference? msg started) ;; TODO: interferences are broken (ll "Interference!!!!!!") (if (message-uplink? msg) (hash-table-walk gateways (lambda (k gateway) (put-message (device-channel gateway) msg))) (put-message - (device-channel (hash-ref end-devices (message-device-id msg))) + (device-channel (hash-table-ref end-devices (message-device-id msg))) msg))))))))) @@ -160,7 +207,7 @@ (hash-table-set! end-devices id (make-device chn (make-class-a id 1 radio-chn chn))))) - (iota 6)) + (iota 1)) (for-each (lambda (id) @@ -168,7 +215,7 @@ (hash-table-set! gateways id (make-device chn (make-gateway id chn radio-chn))))) - (iota 6 10)) + (iota 1 2)) (spawn-fiber (make-radio radio-chn end-devices gateways)) (hash-table-walk end-devices |