Kaustubh Bhalerao
Kaustubh Bhalerao

Reputation: 71

Mysterious serial port behavior

I'm trying to write a command line utility in Haskell (first serious program in Haskell) to query a sensor connected to an arduino over a serial port. The relevant portion of the code is as follows:

-- Read a single reading from the serial port
recursiveread :: SerialPort -> B.ByteString -> IO B.ByteString
recursiveread s acc sent = do 
    recd <- recv s 1000
    if ((B.pack "Done\r\n") `B.isSuffixOf` acc)
        then return acc 
        else recursiveread s $ B.append acc recd

-- Read a single reading from the serial port
getSingleRead :: FilePath -> IO [String]
getSingleRead path = do
    s <- openSerial path defaultSerialSettings 
    send s $ B.pack "1"
    acc <- recursiveread s B.empty
    closeSerial s
    return $ (lines . B.unpack) acc


-- Checks if the filepath exists, and prints a single reading
readspr :: [FilePath] -> IO ()
readspr [path] = do 
    exists <- doesFileExist path 
    case exists of  
        False -> putStrLn "No device found"
        True -> getSingleRead path >>= (mapM_ putStrLn) 

The dispatch function (not shown) calls readspr and uses a "/dev/cu.modem1421" as a parameter. The problem I'm having I suspect has to do with order of evaluation. The expected behavior is to receive a frame of data like this, which I check for "Done" as the terminator:

T: 33697
Data
0:3.2967772483
1:3.2967772483
2:3.2967772483
...
126:3.2967772483
127:3.2967772483
Done

Here is the problem:

1) When I run this code by itself after compiling, from Bash - the program computes for a second and hangs - no output. 2) However when I go into ghci and open a serial port with the openSerial :: FilePath -> SerialPort command, and then run the program in Bash I do see the expected output. (Shouldn't I get resource busy here or something? If I open the connection using screen I do get that error)

This behavior is repeatable - I can closeSerial in ghci and go back to no output in Bash.

Prior research / additional background:

I'm using the System.Hardware.SerialPort library (serialport-0.4.7: Cross platform serial port library in cabal) on an OS X machine. There is an issue pertaining to the blocking / non-blocking nature of the serial port on OS X that is at odds with the UNIX standard - Issue 13 on Github for serialport-0.4.7. However, I'm unable to make much sense of it. Any help on making sense of this problem is highly appreciated. Is this an issue with my misreading of Haskell's laziness, or am I missing something on the order of evaluation, where the port is being closed before I can read it fully, or with the library? (in which case I should post it on the Github page?)

Further research: (case solved)

Here's the problem - Arduino resets when a serial connection is opened (can be disabled). When I opened a connection with the program - it would receive the communication from the host before it booted up. I noticed this when observing the LEDs on the Arduino in the two separate cases - opening (and holding) the port in ghc allowed for enough time to elapse between the second open-and-read.

The solution was to add a delay of a couple seconds after opening the port - now "it just works"!

Upvotes: 3

Views: 341

Answers (1)

Kaustubh Bhalerao
Kaustubh Bhalerao

Reputation: 71

Answer updated for posterity: Further research: (case solved)

Here's the problem - Arduino resets when a serial connection is opened (can be disabled). When I opened a connection with the program - it would receive the communication from the host before it booted up. I noticed this when observing the LEDs on the Arduino in the two separate cases - opening (and holding) the port in ghc allowed for enough time to elapse between the second open-and-read.

The solution was to add a delay of a couple seconds after opening the port - now "it just works"!

Upvotes: 2

Related Questions