i2c-bus-0.1.0: tests/GHCI.hs
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -ddump-splices #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}
{-# OPTIONS_GHC -Wno-missing-export-lists #-}
module GHCI where
import Relude
import Relude.Extra.Newtype
import I2C
import I2C.Register
import I2C.Raw
import Data.Default
import Text.Show qualified
import Numeric
import Data.Bits
import Data.Char (toUpper)
import Text.Printf
import Control.Concurrent
import Foreign
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Lib
--------------------------------------------------------------------------------
--
-- * load ghci:
--
-- $ stack ghci
--
-- then load this file:
--
-- ghci> :l tests/GHCI.hs
--
-- if you get link errors, run `stack build` first which will build the FFI parts,
-- and those symbols should then be available in GHCi
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- test data
$(chip "MYCHIP")
$(setShowBinary)
$(register8 ''MYCHIP 0x22 "MY8" 0x83)
$(field ''MY8 "A_FIELD" "0000***0")
$(field ''MY8 "A_BIT" "00*00000")
-- 'MY64' types will be shown as a 64 character binary string
-- because of the imperative call '$(setShowBinary)' above.
$(register64BE ''MYCHIP 0x22 "MY64" 0x83)
$(setShowHex)
$(register16LE ''MYCHIP 0x44 "MY16" 0x1122)
$(field ''MY16 "B_FIELD" "00000000000****0")
$(field ''MY16 "B_BIT" "00*0000000000000")
my8 :: MY8
my8 = MY8 0b00000110
my16 :: MY16
my16 = MY16 0b0000111100011000
my64 :: MY64
my64 = MY64 0x0123456789ABCDEF
--------------------------------------------------------------------------------
-- PCF8575
--
-- this is a GPIO expander chip with 2 bytes => 16 pins.
-- no registers, only write and read 2 bytes.
--
-- * https://www.ti.com/lit/ds/symlink/pcf8575.pdf
--
$(chip "PCF8575")
testPCF8575 :: IO ()
testPCF8575 = do
chip <- openChip @PCF8575 "/dev/i2c-1" 0x20
forM_ [0..0x00FF] $ \ix -> do
rawwrite @Word16LE chip ix
threadDelay 400000
--------------------------------------------------------------------------------
-- MPU6050
--
-- this is a accelerometer and gyroscope chip with registers
--
-- * https://randomnerdtutorials.com/arduino-mpu-6050-accelerometer-gyroscope/
-- * https://github.com/adafruit/Adafruit_MPU6050/blob/master/Adafruit_MPU6050.cpp
-- * https://www.invensense.tdk.com/en-us/download-resource/ps-mpu-6000a-00-mpu-6000-and-mpu-6050-datasheet
-- * https://www.invensense.tdk.com/download-resource/rm-mpu-6000a-00-mpu-6000-and-mpu-6050-register-map-and-descriptions
--
$(chip "MPU6050")
data TemperatureC = TemperatureC Double
instance Show TemperatureC where
show (TemperatureC n) = printf "%+ 3.1f °C" n
-- Temperature in degrees C = (TemperatureC Register Value as a signed quantity)/340 + 36.53
-- this Storable instance is relative to the MPU6050's hardware
instance Storable TemperatureC where
sizeOf a = 2
alignment a = 1
peek ptr = do
n <- peek @Int16BE $ castPtr ptr
pure $ TemperatureC $ (fromIntegral n) / 340.0 + 36.53
poke ptr (TemperatureC a) = do
poke @Int16BE (castPtr ptr) $ truncate $ (a - 36.53) * 340.0
$(register ''MPU6050 0x41 "TEMP_OUT" ''TemperatureC)
$(register8 ''MPU6050 0x6A "USER_CTRL" 0x00)
$(field ''USER_CTRL "FIFO_RESET" "00000*00")
$(field ''USER_CTRL "I2C_MST_RESET" "000000*0")
$(field ''USER_CTRL "SIG_COND_RESET" "0000000*")
$(register8 ''MPU6050 0x6B "PWR_MGMT_1" 0x40)
$(field ''PWR_MGMT_1 "CLKSEL" "00000***")
-- this adds INLINE pragma to functions generated by '$(field)' below; see splice output.
-- (nothing special about the PWR_MGMT_1, this is just for demonstration)
$(setFieldInline True)
$(field ''PWR_MGMT_1 "SLEEP" "0*000000")
testMPU6050 :: IO ()
testMPU6050 = do
chip <- openChip "/dev/i2c-1" 0x68
regwrite chip regUSER_CTRL $ def & bitsetFIFO_RESET
& bitsetI2C_MST_RESET
& bitsetSIG_COND_RESET
regwrite chip regPWR_MGMT_1 $ def & setCLKSEL 2
& bitclearSLEEP
forever $ do
t <- regread chip regTEMP_OUT
print t
--a <- regread' @TemperatureC chip 0x41
--print a
threadDelay 400000