;;;; -*- Scheme -*-
;;
;; neighbors example for HLSIM
;;
;; David DeRoure Sep 17 1997
;; dder@martigny.ai.mit.edu
;;
;; This file should be compiled with (cps "commcheck1") then 
;; (cbf "commcheck1").  It uses definitions in club5d.scm.  
;; See neighbor1s.scm for the simulation setup.  See the HLSIM 
;; documentation for further details.
;;
;; This is not a real Gunk program - it is designed to test the 
;; simulator.  Each processor starts with a list of all its neighbors,
;; obtained from the simulation structure.  It repeatedly broadcasts 
;; its processor number, and when it receives messages from neighbors
;; it removes their number from the list.  The color of the processor
;; indicates the number of neighbors left in the list, i.e. the
;; number of undiscovered neighbors.
;; 
;; This is useful for experimenting with different delays before
;; broadcasts.

(declare (usual-integrations))

(define processor-id (processor-number))

;; Set neighbors to the full neighbor ("neighbour") list
;; according to the simulation

(define neighbors 
  (vector->list (vector-ref (simulation.neighbours (the-simulation))
			    (processor-number))))

;; These variables are set during the simulation for analysis later

(define collisions 0)    ; the number of collisions received
(define receives 0)      ; the number of messages received (exc. collisions)
(define end-time #F)     ; set to simulation time when all neighbors are found

(define primitive-message-event (make-event))

(define (event-loop)
  (select
    (global-timeout 'done)
    (transmit-timeout (broadcast processor-id) 
		      (reset-transmit-timer!)
		      (event-loop))
    (primitive-message-event
     => (lambda (message)
          (event.clear! primitive-message-event)
	  (reset-transmit-timer!) ; reset transmit timer on collision/receive
	  (if (eq? message 'collision)
	      (set! collisions (1+ collisions))
	      (begin (set! receives (1+ receives))
		     (if (memv message neighbors)
			 (begin (set! neighbors (delv message neighbors))
				(color-me (length neighbors))
				(if (null? neighbors) 
				    (set! end-time (clock)))))))
	  (event-loop)))))

;; The transmit delay after a comms event (receive, transmit, collision).
;; Can use collision count here to implement backoff, e.g. try quadratic.

(define (reset-transmit-timer!)
  (set! transmit-timeout (make-timeout-event (+ 100 (random 5000)))))

;; The delay before the first broadcast (which could be prolonged if
;; a the timer is reset during this period)

(define transmit-timeout (make-timeout-event (random 1000)))

;; The global timeout - this needs to be long  

(define global-timeout (make-timeout-event 100000))

;; Initial code

(color-me (length neighbors))

(event-loop)

;; end of commcheck1.scm

