#lang racket
(provide is-pin-set?
is-arduino-pin-set?
set-pin!
clear-pin!
set-pin-mode!
report-analog-pin!
report-digital-port!
set-arduino-pin!
clear-arduino-pin!
read-analog-pin
request-version
open-firmata
close-firmata
on-button-pressed
INPUT_MODE
OUTPUT_MODE
ANALOG_MODE
PWM_MODE
SERVO_MODE
ON
OFF)
(require file/sha1)
(require racket/system)
(require rnrs/bytevectors-6)
(define DIGITAL-MESSAGE #x90) (define ANALOG-MESSAGE #xE0) (define REPORT-ANALOG #xC0) (define REPORT-DIGITAL #xD0) (define SET-PIN-MODE #xF4) (define REPORT-VERSION #xF9) (define SYSTEM-RESET #xFF) (define START-SYSEX #xF0) (define END-SYSEX #xF7)
(define INPUT_MODE 0)
(define OUTPUT_MODE 1)
(define ANALOG_MODE 2)
(define PWM_MODE 3)
(define SERVO_MODE 4)
(define ON 1)
(define OFF 0)
(define BAUDRATE 57600)
(define ANALOG-PINS 16) (define DIGITAL-PORTS 16)
(define in null)
(define out null)
(define read-thread null)
(define registrations '())
(define ANALOG-IO-PINS (make-vector ANALOG-PINS))
(define DIGITAL-IO-PINS (make-bytevector DIGITAL-PORTS))
(define (update-analog-pin! pin value)
(vector-set! ANALOG-IO-PINS pin value))
(define (read-analog-pin pin)
(vector-ref ANALOG-IO-PINS pin))
(define (update-digital-port! port value)
(when (<= value 255)
(for-each (lambda (p)
(let ((pin (car p))
(f (cdr p)))
(when (and
(= port (quotient pin 8))
(not (is-arduino-pin-set? pin))
(is-bit-set? (remainder pin 8) value))
(f))))
registrations)
(bytevector-u8-set! DIGITAL-IO-PINS port value)))
(define (is-bit-set? bit value)
(> (bitwise-and
value
(bitwise-and
(arithmetic-shift 1 bit)
#xFF)) 0))
(define (is-pin-set? port pin)
(is-bit-set? pin (bytevector-u8-ref DIGITAL-IO-PINS port)))
(define (read-loop)
(process-input (read-byte in))
(read-loop))
(define (process-input data)
(cond
((= (bitwise-and data #xF0) ANALOG-MESSAGE)
(let ((lsb (read-byte in))
(msb (read-byte in))
(analog-pin (bitwise-and data #xF)))
(update-analog-pin! analog-pin (bitwise-ior (arithmetic-shift msb 8) lsb))))
((= (bitwise-and data #xF0) DIGITAL-MESSAGE)
(let ((lsb (read-byte in))
(msb (read-byte in))
(port (bitwise-and data #xF)))
(update-digital-port! port (bitwise-ior (arithmetic-shift msb 8) lsb))))
((= data REPORT-VERSION)
(let ((major (read-byte in))
(minor (read-byte in)))
(printf "FIRMATA VERSION DETECTED ~a.~a" major minor)))))
(define (close-firmata)
(when (not (null? read-thread))
(kill-thread read-thread)
(set! read-thread null)
(close-input-port in)
(close-output-port out)
(set! in null)
(set! out null)
(printf "DrRacket-Firmata closed .... \n")))
(define (open-firmata port-name)
(set! out (open-output-file port-name #:mode 'binary #:exists 'append))
(set! in (open-input-file port-name #:mode 'binary))
(sleep 3)
(if (system (string-append "stty -f " port-name " 57600 cs8 cread clocal"))
(begin
(set! read-thread (thread (lambda () (read-loop))))
#t)
(error "Failed to open the connection with " port-name " verify if your microcontroller is plugged in correctly")))
(define (set-pin! port pin)
(let* ((old-value (bytevector-u8-ref DIGITAL-IO-PINS port))
(new-value (bitwise-ior old-value (arithmetic-shift 1 pin))))
(write-byte (bitwise-ior DIGITAL-MESSAGE port) out)
(write-byte (bitwise-and new-value #x3F) out)
(write-byte (arithmetic-shift new-value -7) out)
(flush-output out)))
(define (clear-pin! port pin)
(let* ((old-value (bytevector-u8-ref DIGITAL-IO-PINS port))
(new-value (bitwise-and old-value (bitwise-not (arithmetic-shift 1 pin)))))
(write-byte (bitwise-ior DIGITAL-MESSAGE port) out)
(write-byte (bitwise-and new-value #x3F) out)
(write-byte (arithmetic-shift new-value -7) out)
(flush-output out)))
(define (set-pin-mode! pin mode)
(write-byte 244 out)
(write-byte pin out)
(write-byte mode out)
(flush-output out))
(define (report-analog-pin! pin-number mode)
(write-byte (bitwise-ior REPORT-ANALOG pin-number) out)
(write-byte mode out)
(flush-output out))
(define (report-digital-port! port-number mode)
(write-byte (bitwise-ior REPORT-DIGITAL port-number) out)
(write-byte mode out)
(flush-output out))
(define (request-version)
(write-byte REPORT-VERSION out)
(flush-output out))
(define (set-arduino-pin! pin)
(set-pin! (quotient pin 8) (remainder pin 8)))
(define (clear-arduino-pin! pin)
(clear-pin! (quotient pin 8) (remainder pin 8)))
(define (is-arduino-pin-set? pin)
(is-pin-set? (quotient pin 8) (remainder pin 8)))
(define (on-button-pressed pin lambda)
(set! registrations (append registrations (list (cons pin lambda))))
(display registrations))