HPi 0.2.0 → 0.3.0
raw patch · 2 files changed
+33/−30 lines, 2 files
Files
- HPi.cabal +7/−3
- System/RaspberryPi/GPIO.hs +26/−27
HPi.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/ name: HPi -version: 0.2.0 +version: 0.3.0 synopsis: GPIO and I2C functions for the Raspberry Pi. description: This package is a FFI wrapper around the bcm2835 library by Mike McCauley, it also includes a few utility functions for easier use of the imported functions. homepage: https://github.com/WJWH/HPi @@ -10,7 +10,7 @@ license-file: LICENSE author: Wander Hillen maintainer: wjw.hillen@gmail.com --- copyright: +copyright: (c) 2013 Wander Hillen category: System build-type: Simple cabal-version: >=1.8 @@ -18,4 +18,8 @@ library exposed-modules: System.RaspberryPi.GPIO -- other-modules: - build-depends: base ==4.5.*, bytestring ==0.9.*+ build-depends: base ==4.5.*, bytestring ==0.9.* + +source-repository head + type: git + location: git://github.com/WJWH/HPi.git
System/RaspberryPi/GPIO.hs view
@@ -34,7 +34,7 @@ import Foreign.C import Foreign.C.String import qualified Data.ByteString as BS -import qualified Data.ByteString.Char8 as BSC +-- import qualified Data.ByteString.Char8 as BSC import GHC.IO.Exception ------------------------------------------------------------------------------------------------------------------------------------ @@ -93,7 +93,7 @@ -- writes some bytes to the bus foreign import ccall unsafe "bcm2835.h bcm2835_i2c_write" c_writeI2C :: CString -> CUInt -> IO CUChar --read some bytes from the bus -foreign import ccall unsafe "bcm2835.h bcm2835_i2c_read" c_readI2c :: CString -> CUShort -> IO CUChar +foreign import ccall unsafe "bcm2835.h bcm2835_i2c_read" c_readI2C :: CString -> CUShort -> IO CUChar --reads a certain register with the repeated start method foreign import ccall unsafe "bcm2835.h bcm2835_i2c_read_register_rs" c_writeReadI2C :: CString -> CString -> CUShort -> IO CUChar @@ -112,13 +112,22 @@ -- |Any IO computation that uses the I2C bus using this library should be wrapped with this function; ie @withI2C $ do foo@. -- It prepares the relevant pins for use with the I2C protocol and makes sure everything is safely returned to normal if an exception --- occurs. WARNING: after this function returns, the I2C pins will be set to Input, so use 'setPinFunction' if you want to use them --- for output. +-- occurs. If you only use the GPIO pins for I2C, you can do @withGPIO . withI2C $ do foo@ and it will work as expected. WARNING: +-- after this function returns, the I2C pins will be set to Input, so use 'setPinFunction' if you want to use them for output. withI2C :: IO a -> IO a withI2C f = bracket_ initI2C stopI2C f +-- +actOnResult :: CUChar -> CString -> IO BS.ByteString +actOnResult rr buf = case rr of + 0x01 -> throwIO $ IOError Nothing IllegalOperation "I2C: " "Received an unexpected NACK." Nothing Nothing + 0x02 -> throwIO $ IOError Nothing IllegalOperation "I2C: " "Received Clock Stretch Timeout." Nothing Nothing + 0x04 -> throwIO $ IOError Nothing IllegalOperation "I2C: " "Not all data was read." Nothing Nothing + 0x00 -> BS.packCString buf --convert C buffer to a bytestring + + -- Mapping raspberry pi pin number to internal bmc2835 pin number, ugly solution, but meh. Also, the existence of mutiple versions -- of the pin layout makes this the most elegant solution without resorting to state monads (which I don't want to do because that -- would hamper the simplicity of having writePin and readPin be simple IO actions). As this function isn't exported anyway, the @@ -192,39 +201,29 @@ setI2cBaudRate :: Word32 -> IO () setI2cBaudRate a = c_setBaudRateI2C $ fromIntegral a --- |Writes the data in the 'ByteString' to the specified adress. -writeI2C :: Address -> BS.ByteString -> IO (Either BSC.ByteString ()) --writes a bytestring to the specified address +-- |Writes the data in the 'ByteString' to the specified adress. Throws an IOException if an error occurs. +writeI2C :: Address -> BS.ByteString -> IO () --writes a bytestring to the specified address writeI2C address by = BS.useAsCString by $ \bs -> do setI2cAddress address readresult <- c_writeI2C bs (fromIntegral $ BS.length by) case readresult of - 0x01 -> return (Left "Received a NACK.") - 0x02 -> return (Left "Received Clock Stretch Timeout.") - 0x04 -> return (Left "Not all data was read.") - 0x00 -> return (Right ()) + 0x01 -> throwIO $ IOError Nothing IllegalOperation "I2C: " "Received an unexpected NACK." Nothing Nothing + 0x02 -> throwIO $ IOError Nothing IllegalOperation "I2C: " "Received Clock Stretch Timeout." Nothing Nothing + 0x04 -> throwIO $ IOError Nothing IllegalOperation "I2C: " "Not all data was read." Nothing Nothing + 0x00 -> return () --- |Reads num bytes from the specified address. -readI2C :: Address -> Int -> IO (Either BSC.ByteString BS.ByteString) --reads num bytes from the specified address +-- |Reads num bytes from the specified address. Throws an IOException if an error occurs. +readI2C :: Address -> Int -> IO BS.ByteString --reads num bytes from the specified address readI2C address num = allocaBytes (num+1) $ \buf -> do --is the +1 necessary?? setI2cAddress address - readresult <- c_readI2c buf (fromIntegral num) - case readresult of - 0x01 -> return (Left "Received a NACK.") - 0x02 -> return (Left "Received Clock Stretch Timeout.") - 0x04 -> return (Left "Not all data was read.") - 0x00 -> do bs <- BS.packCString buf --convert C buffer to a bytestring - return (Right bs) + readresult <- c_readI2C buf (fromIntegral num) + actOnResult readresult buf -- |Writes a 'ByteString' containing a register address to the specified address, then reads num bytes from --- it, using the \"repeated start\" I2C method -writeReadI2C :: Address -> BS.ByteString -> Int -> IO (Either BSC.ByteString BS.ByteString) +-- it, using the \"repeated start\" I2C method. Throws an IOException if an error occurs. +writeReadI2C :: Address -> BS.ByteString -> Int -> IO BS.ByteString writeReadI2C address by num = BS.useAsCString by $ \bs -> do --marshall the register-containing bytestring allocaBytes (num+1) $ \buf -> do --allocate a buffer for the response setI2cAddress address readresult <- c_writeReadI2C bs buf (fromIntegral num) - case readresult of - 0x01 -> return (Left "Received a NACK.") - 0x02 -> return (Left "Received Clock Stretch Timeout.") - 0x04 -> return (Left "Not all data was read.") - 0x00 -> do bs <- BS.packCString buf --convert C buffer to a bytestring - return (Right bs)+ actOnResult readresult buf