summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simulation.scm125
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