#lang racket (require racket/tcp) (require json) (define serial-port-device "/dev/ttyUSB0") (define port 4444) (define hostname "127.0.0.1") ; Return a list of pizzas from the local file (define (get-pizzas-list) (let ((file (open-input-file "pizza_list.json"))) (read-json file))) ; Send the pizza list as a JSON, prepending it with 4 bytes that contain the list length (define (send-pizzas-list output) (let ((pizzas-list (get-pizzas-list))) (write-bytes (integer->integer-bytes (bytes-length (jsexpr->bytes pizzas-list)) 4 #f) output) (write-json pizzas-list output))) ; Print the to-print string on the printer ; TODO add synchronization to avoid race conditions (define (printer-print to-print) (let ((file (open-output-file serial-port-device #:exists 'append))) (display (string-replace to-print "\n" "\n\n") file) ; always add an extra newline because the printer is a little messed up (close-output-port file))) ; Format the pizzas array from the JSON in a human-readable way (define (format-pizza pizzas-list) (let ((str "")) (for-each (lambda (pizza-hashmap) (set! str (string-append str (format "~a : ~s\n" (hash-ref pizza-hashmap 'quantity) (hash-ref pizza-hashmap 'name))))) pizzas-list) str)) ; Parse the commands given in the JSON (define (parse-json message output) (let ((parsed-json (with-input-from-string message (lambda () (read-json))))) ; parse the JSON (case (hash-ref parsed-json 'command) (("print") (printer-print (hash-ref parsed-json 'text))) (("pizza") (printer-print (format-pizza (hash-ref parsed-json 'pizzas)))) (("get-pizzas") (send-pizzas-list output)) (else (displayln "Unknown command"))))) ; Parse the JSON and execute the command specified in it ; ; Each message starts with the length of the JSON object, put into the first 4 bytes (define (execute-commands input output) ; read the first 4 bytes, little-endian, unsigned (let ((message-length (integer-bytes->integer (read-bytes 4 input) #f))) (parse-json (bytes->string/utf-8 (read-bytes message-length input)) output) (close-input-port input) (close-output-port output))) ; Wait on a port and spawn new threads on each connection (define (wait-for-connection) (let ((listener (tcp-listen port 4 #t hostname))) (let infinite-loop () (let-values (((input output) (tcp-accept listener))) (thread (lambda () (execute-commands input output))) (infinite-loop))))) (wait-for-connection)