[plt-scheme] Need low-level help: blocking on reading from serial port in Windows

From: Nadeem Abdul Hamid (nadeem at acm.org)
Date: Fri Oct 23 21:35:08 EDT 2009

OK, so thanks to YC, here's an isolated version of the problem with a
simulated port using make-pipe, along with tests... It still hangs for
an unreasonable amount of time if there is any delay in data getting
sent to the port, so it must be something wrong with the way I'm
writing the raw-read function(s)? (I haven't tried this on OS X to see
if it only happens on Windows or not.) Can anyone see what could be
wrong?? I really appreciate it...

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#lang scheme

;; raw-read : number input-port -> (listof byte)
(define (raw-read-1 n in)
  ;(printf " raw-read")
  (local [(define bstr (make-bytes n))

          ;; read-aux : number port -> number
          (define (read-aux start-pos tries)
            (cond [(>= start-pos n) start-pos]  ; should never be > really
                  [else
                   (let [(r (read-bytes-avail!* bstr
(sync/enable-break in) start-pos))]
                     (cond [(number? r) (read-aux (+ r start-pos) 0)]
                           [else (read-aux start-pos (add1 tries))]
                           ))]))
          ]
    (read-aux 0 0)
    (bytes->list bstr)
    ))


;; raw-read : number input-port -> (listof byte)
(define (raw-read-2 n in)
  ;(printf " raw-read")
  (local [(define bstr (make-bytes n))

          ;; read-aux : number port -> number
          (define (read-aux start-pos tries)
            (when (= 0 (remainder tries 10000000)) (sleep 0))  ; (printf "."))
            (cond [(>= start-pos n) start-pos]  ; should never be > really
                  [else
                   (let [(r (read-bytes-avail!* bstr in start-pos))]
                     (cond [(number? r) (read-aux (+ r start-pos) 0)]
                           [else (read-aux start-pos (add1 tries))] ; ???
                           ))]))
          ]
    (read-aux 0 0)
    (bytes->list bstr)
    ))


(define (timed-write-to-port o bytes-string interval)
  (thread (lambda ()
            (let loop ((bytes (bytes->list bytes-string)))
              (unless (null? bytes)
                (write-byte (car bytes) o)
                (flush-output o)
                (sleep interval)
                (loop (cdr bytes)))))))


(define (test-raw-read read-func bytes-string interval)
  (let-values ([(in out) (make-pipe)])
    (timed-write-to-port out bytes-string interval)
    (read-func (bytes-length bytes-string) in)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Welcome to DrScheme, version 4.2.2 [3m].
Language: Module; memory limit: 128 megabytes.
> (test-raw-read raw-read-1 #"abcdefg" 0)
(97 98 99 100 101 102 103)
> (test-raw-read raw-read-2 #"abcdefg" 0)
(97 98 99 100 101 102 103)
> (test-raw-read raw-read-1 #"abcdefg" 1)
. . user break
>

The delay causes the code to "hang" for about 5 to 10 seconds before
it the read comes through. An interval of 5 causes a much longer
"hang". And as YC suggested, the CPU usage is max-ed out during that
period...

--- nadeem






On Fri, Oct 23, 2009 at 5:52 PM, YC <yinso.chen at gmail.com> wrote:
>
> On Fri, Oct 23, 2009 at 2:30 PM, Nadeem Abdul Hamid <nadeem at acm.org> wrote:
>>
>> That makes sense, but I would expect that using functions like "sync",
>> for example, should not cause the cpu to max out, but rather suspend
>> until there is data available on the port? Anyway, so do you mean I
>> should try something like making a simulated pair of ports using
>> "make-input/output-port" and see what happens? Thanks for the
>> suggestions,
>
> Yes that is what I mean.
>
> I agree that using sync should avoid CPU max out issue, so I also suspect
> that there might be some lower level device driver issues with the port
> itself, but that couldn't be verified until you can isolate the problem, so
> that's why I suggest simulating the ports.
>
> Here's a possible port simulation routine:
>
> (define (timed-write-to-port o bytes-string interval)
>   (thread (lambda ()
>             (let loop ((bytes (bytes->list bytes-string)))
>               (unless (null? bytes)
>                 (write-byte (car bytes) o)
>                 (sleep interval)
>                 (loop (cdr bytes)))))))
>
> You can then use make-pipe to create a pair of ports - then you pass the
> output port to timed-write-to-port & input-port to your read routine.  If
> that works your read-routine is likely safe and problems lie elsewhere.
>
> HTH.
> yc
>
>


Posted on the users mailing list.