Reputation: 71
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
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