
Recently, I received as gift medical instruments designed by one of my father former students. There is a description of these instruments on my web page. Here is the address:
http://www.discenda.org/med/
By the way, I am not that guy that appears in a picture wearing emg sensors. That said, the instruments and everything else are programmed in Clean. Then I have a new opportunity of translating Clean programs to Haskell and test them in a real application application. Of course, I simplified the programs to see how they work.
The medical instruments have on-board computers, that record signals (electromyograms, electroencephalograms, electrocardiograms, end-tydal CO2 partial pressure and temperature), pre-process them and send them to the main computer. The main-computer recognizes patterns in the signals, and use the result to drive a wheelchair, or to call a doctor. On my page you wil find more complete explanations and pictures of the instruments. For ready reference, here is my address:
http://www.discenda.org/med/
I decided start my translation work from the most simple programs, the graphical interface and the communication protocol. After substituting a Haskell program for the Clean original, I discovered that the system did not work anymore if I exited the Haskell program. In few words, after leaving the Haskell program without turning off the computer or the sensors, and entering the Haskell program again, Haskell failed to communicate with the sensors. I did what I always do in such a situation: I simplified the program until I reduced it to a few lines. I discovered that Haskell failed to close the serial port. There is a serial to UART-0 driver that allows me to plug the serial cable to a USB port, that both feeds the sensors, and permit communication.
I fixed the bug by passing a useless integer argument to the function used to close the port. Since I don't like this kind of patch (useless arguments), I would like to know why the original program does not work, and also I would appreciate if someone could suggest a way to get rid of the argument whose sole job is force Haskell to close the port. The GUI is based on the Small JAPI biding, fixed and incremented with text processing components. Here is the fixed Haskell program:
import Gui.Binding
import Gui.Types
import Gui.Constants
import SER.IAL
import Control.Monad
import Data.Char
main = do rv <- j_start
frame <- j_frame "Sensors"
exit_button <- j_button frame "Exit"
j_setpos exit_button 50 50
j_setsize exit_button 80 30
fld <- j_textfield frame 30
j_setpos fld 50 100
j_show frame
opencport(4)
waitForFrameAction frame fld exit_button
let r = closecport 7 {- without the argument, closecport does not work -}
print r
return j_quit
waitForFrameAction :: Frame -> Object -> Object -> IO Bool
waitForFrameAction frame f b =
do obj <- j_nextaction
again <- if obj == event b
then return False
else
do {- nm <- j_gettext f 200 -}
tx <- sendMessage 1 "t"
let tp= filter (> ' ') tx
rx <- sendMessage 1 "x"
let rd= filter (> ' ') rx
let x = hex2dec rd
let tt= (fromIntegral x)*209.0/1024 - 67.5
j_settext f ((show tt)++" ==> "++tp)
return True
if not again
then return True
else waitForFrameAction frame f b
hex2dec :: String -> Int
hex2dec h= sum (zipWith (*)
(map (16^) [3,2,1,0])
[digitToInt c | c <- h])
convert d r s0= (fromIntegral (hex2dec d))*r/1024.0- s0
As I told before, let r = closecport 7 did not work until I gave it an argument. Here is the interface between the C-side, and the Haskell-side of the program:
{-# LANGUAGE ForeignFunctionInterface #-}
module SER.IAL where
import Control.Monad
import Foreign
import Foreign.C.Types
import Foreign.C
foreign import ccall "rs232.h opencport" opencport :: CInt -> IO ()
foreign import ccall "rs232.h closecport" closecport :: CInt -> CInt
foreign import ccall "rs232.h rdrs232" c_sendmsg :: CInt -> CString -> CString
sendMessage :: Int -> String -> IO String
sendMessage n msg =
withCString msg $
\str -> peekCString (c_sendmsg (fromIntegral n) str)
Originally, I had the following line (that did not work properly):
foreign import ccall "rs232.h closecport" closecport :: IO ()
You will find below the C-program. The original program (that did not work) had the following definition for closecport:
int closecport() {
CloseComport();
return 3; }
This deffinition (that did not work) was replaced by the following one:
int closecport(int n) {
CloseComport();
return n; }
Here is the complete C program:
#include "serial.h"
#include