;;;; -*- Scheme -*-
;;
;; td example for HLSIM
;;
;; David DeRoure Sep 14 1997
;; dder@martigny.ai.mit.edu
;;
;; This file should be compiled with (cps "td1") then 
;; (cbf "td1").  It uses definitions in club5d.scm.  
;; See td1s.scm for the simulation setup.  See the HLSIM 
;; documentation for further details.
;;
;; Each processor has a color between 0 and 6, which is initially set to
;; zero or chosen at random.  The processor repeatedly broadcasts its id 
;; and state, while maintaining a table of its neighbors and their states.  
;; Should a neighbor have the same state and a higher id then the current
;; processor changes state to a free color (NB this assumes that communication
;; is symmetrical).   The period between broadcasts is random to reduce 
;; repeated collisions. 

(declare (usual-integrations))

;; Every processor has an id (not the processor number, as that would
;; be cheating)

(define processor-id (random 1000000))

;; Each processor has a state from 0 to 6
;; If we start at state 0 we can see the algorithm working.
;; If we start at state (random 7) it settles down more quickly.

(define state 0) ; (random 7)

;; Each processor maintains a table of neighbors and their states.

(define neighbors (make-table))

;; The transmit loop runs while transmit? is true.  It is set to false 
;; by the receive loop when this processor has finished.

(define transmit? #T)

;; This variable is used to identify isolated processors.  If it
;; is still true after neighbor-timeout, the processor is assumed
;; to be isolated.

(define no-messages-received? #T)

(define collisions 0)

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

;; The update-table procedure processes a new message and
;; returns the state for this processor. 

(define (receive-loop)
  (select
    (global-timeout (set! transmit? #F))
    (primitive-message-event
     => (lambda (message)
          (event.clear! primitive-message-event)
	  (set! no-messages-received? #F)
          (if (eq? message 'collision)
	      (begin (set! collisions (1+ collisions))
		     (color-me "white")
		     (wait (make-timeout-event 100))
		     (color-me state))
	      (begin (set! state 
			   (update-table neighbors message processor-id state))
		     (color-me state)))
	  (receive-loop)))
    (neighbor-timeout
     (event.clear! neighbor-timeout)
     (if no-messages-received?
	 (begin (color-me "black")
		(set! transmit? #F))))))

(define (transmit-loop)
  (wait (make-timeout-event (* 100 (1+ (random 20)))))
  (broadcast (make-message processor-id state))
  (if transmit? (transmit-loop)))
  
;; Run the loops

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

(color-me state)

(parallel (transmit-loop) (receive-loop))

;; end of td1.scm
