Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Renamed files in NXT library. Added NXT utility programs: `upload` an…

…d `shutdown`.
  • Loading branch information...
commit ee55678b273101fcb8d6e0e1750afbe9f37e7d9e 1 parent 99ae6c1
@mitar authored
View
6 lib/BluetoothUtils.hs
@@ -1,14 +1,14 @@
{-# LANGUAGE ForeignFunctionInterface #-}
-module BluetoothUtils (bluetoothRSSI, bluetoothLinkQuality, bluetoothAddress) where
+module NXT.BluetoothUtils (bluetoothRSSI, bluetoothLinkQuality, bluetoothAddress) where
import Control.Monad.State
import Foreign
import Foreign.C.String
import Foreign.C.Types
-import NXT
-import NXTTypes
+import NXT.NXT
+import NXT.Types
-- Foreign function call for C function which returns RSSI Bluetooth value of a connection to a given Bluetooth address
foreign import ccall unsafe "blue.h" rssi :: CString -> IO CInt
View
6 lib/NXTCompass.hs → lib/Compass.hs
@@ -1,11 +1,11 @@
-module NXT.NXTCompass where
+module NXT.Compass where
import Control.Monad
import Data.Word
import NXT.NXT
-import NXT.NXTData
-import NXT.NXTTypes
+import NXT.Data
+import NXT.Types
-- Described in CMPS-Nx-V20-User-Guide.pdf at www.mindsensors.com
View
6 lib/NXTData.hs → lib/Data.hs
@@ -1,4 +1,4 @@
-module NXT.NXTData where
+module NXT.Data where
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as C
@@ -94,3 +94,7 @@ stringToData = B.unpack . C.pack
-- Converts a name to a null-terminated list of bytes
nameToData :: String -> [Word8]
nameToData = stringToData0 . take 19 . flip (++) (repeat '\0')
+
+-- Converts a message to a null-terminated list of bytes
+messageToData :: String -> [Word8]
+messageToData = stringToData0 . take 58
View
4 lib/NXTErrors.hs → lib/Errors.hs
@@ -1,4 +1,4 @@
-module NXT.NXTErrors where
+module NXT.Errors where
import Data.Word
@@ -22,7 +22,7 @@ failNXT msg 0x89 = fail $ msg ++ ": No linear space"
failNXT msg 0x8A = fail $ msg ++ ": Undefined error"
failNXT msg 0x8B = fail $ msg ++ ": File is busy"
failNXT msg 0x8C = fail $ msg ++ ": No write buffers"
-failNXT msg 0x8D = fail $ msg ++ ": Append not possible"
+failNXT msg 0x8D = fail $ msg ++ ": Append not possible"
failNXT msg 0x8E = fail $ msg ++ ": File is full"
failNXT msg 0x8F = fail $ msg ++ ": File exists"
failNXT msg 0x90 = fail $ msg ++ ": Module not found"
View
134 lib/NXT.hs
@@ -20,9 +20,9 @@ import System.Posix.Signals
import System.Posix.Types
import Text.Printf
-import NXT.NXTData
-import NXT.NXTErrors
-import NXT.NXTTypes
+import NXT.Data
+import NXT.Errors
+import NXT.Types
-- Described in Lego Mindstorms NXT Bluetooth Developer Kit:
-- Appendix 1 - Communication protocol
@@ -171,6 +171,29 @@ stopProgram' confirm = do
then 0x00
else 0x80
+-- Plays a sound file
+playSoundFile :: Bool -> FileName -> NXT ()
+playSoundFile = playSoundFile' False
+
+-- Plays a sound file, but also gets the confirmation
+playSoundFileConfirm :: Bool -> FileName -> NXT ()
+playSoundFileConfirm = playSoundFile' True
+
+playSoundFile' :: Bool -> Bool -> FileName -> NXT ()
+playSoundFile' confirm loop filename = do
+ when debug $ io . hPutStrLn stderr $ "playsoundfile"
+ let send = [request, 0x02, fromIntegral . fromEnum $ loop] ++ (nameToData filename)
+ sendData send
+ when confirm $ do
+ receive <- receiveData
+ case receive of
+ [0x02, 0x02, 0x00] -> return ()
+ [_, _, e] -> failNXT "playSoundFile" e
+ _ -> fail "playSoundFile"
+ where request = if confirm
+ then 0x00
+ else 0x80
+
-- Plays a tone with given frequency (in Hz) for given duration (in s)
playTone :: Frequency -> Duration -> NXT ()
playTone frequency duration = do
@@ -180,18 +203,6 @@ playTone frequency duration = do
where toMilliseconds :: Duration -> Integer -- duration is in seconds, but NXT requires milliseconds
toMilliseconds d = floor (d * 1000)
--- Gets battery level (in mV)
-getBatteryLevel :: NXT Voltage
-getBatteryLevel = do
- when debug $ io . hPutStrLn stderr $ "getbatterylevel"
- let send = [0x00, 0x0B]
- sendData send
- receive <- receiveData
- case receive of
- [0x02, 0x0B, 0x00, v1, v2] -> return $ fromUWord [v1, v2]
- _:_:e:_ -> failNXT "getBatteryLevel" e
- _ -> fail "getBatteryLevel"
-
-- Sets output (motor) state
setOutputState :: OutputPort -> OutputPower -> [OutputMode] -> RegulationMode -> TurnRatio -> RunState -> TachoLimit -> NXT ()
setOutputState = setOutputState' False
@@ -378,6 +389,33 @@ resetInputScaledValue input = do
let send = [0x80, 0x08, fromIntegral . fromEnum $ input]
sendData send
+-- Writes a message
+-- Message length is limited to 58 bytes per command
+messageWrite :: Inbox -> String -> NXT ()
+messageWrite = messageWrite' False
+
+-- Writes a message, but also gets the confirmation
+messageWriteConfirm :: Inbox -> String -> NXT ()
+messageWriteConfirm = messageWrite' True
+
+messageWrite' :: Bool -> Inbox -> String -> NXT ()
+messageWrite' confirm inbox message
+ | length message <= 58 = do
+ when debug $ io . hPutStrLn stderr $ "messagewrite"
+ let message' = messageToData message
+ send = [request, 0x09, fromIntegral . fromEnum $ inbox] ++ (toUByte . length $ message') ++ message'
+ sendData send
+ when confirm $ do
+ receive <- receiveData
+ case receive of
+ [0x02, 0x09, 0x00] -> return ()
+ [_, _, e] -> failNXT "messageWrite" e
+ _ -> fail "messageWrite"
+ | otherwise = throw $ PatternMatchFail "messageWrite"
+ where request = if confirm
+ then 0x00
+ else 0x80
+
-- Resets motor position
resetMotorPosition :: OutputPort -> MotorReset -> NXT ()
resetMotorPosition output reset = do
@@ -390,6 +428,41 @@ resetMotorPosition output reset = do
let send = [0x80, 0x0A, fromIntegral . fromEnum $ output, fromIntegral . fromEnum $ reset]
sendData send
+-- Gets battery level (in mV)
+getBatteryLevel :: NXT Voltage
+getBatteryLevel = do
+ when debug $ io . hPutStrLn stderr $ "getbatterylevel"
+ let send = [0x00, 0x0B]
+ sendData send
+ receive <- receiveData
+ case receive of
+ [0x02, 0x0B, 0x00, v1, v2] -> return $ fromUWord [v1, v2]
+ _:_:e:_ -> failNXT "getBatteryLevel" e
+ _ -> fail "getBatteryLevel"
+
+-- Stops sound playback
+stopSoundPlayback :: NXT ()
+stopSoundPlayback = stopSoundPlayback' False
+
+--Stops sound playback, but also gets the confirmation
+stopSoundPlaybackConfirm :: NXT ()
+stopSoundPlaybackConfirm = stopSoundPlayback' True
+
+stopSoundPlayback' :: Bool -> NXT ()
+stopSoundPlayback' confirm = do
+ when debug $ io . hPutStrLn stderr $ "stopsoundplayback"
+ let send = [request, 0x0C]
+ sendData send
+ when confirm $ do
+ receive <- receiveData
+ case receive of
+ [0x02, 0x0C, 0x00] -> return ()
+ [_, _, e] -> failNXT "stopSoundPlayback" e
+ _ -> fail "stopSoundPlayback"
+ where request = if confirm
+ then 0x00
+ else 0x80
+
-- Sends a keep alive (turned on) packet
keepAlive :: NXT ()
keepAlive = do
@@ -474,6 +547,32 @@ lowspeedRead input = do
_:_:e:_ -> failNXT "lowSpeedRead" e
_ -> fail "lowSpeedRead"
+-- Gets current program name
+getCurrentProgramName :: NXT String
+getCurrentProgramName = do
+ when debug $ io . hPutStrLn stderr $ "getcurrentprogramname"
+ let send = [0x00, 0x11]
+ sendData send
+ receive <- receiveData
+ case receive of
+ 0x02:0x11:0x00:filename | length filename == 20 -> return $ dataToString0 filename
+ _:_:e:_ -> failNXT "getCurrentProgramName" e
+ _ -> fail "getCurrentProgramName"
+
+-- Reads a message
+messageRead :: RemoteInbox -> Bool -> NXT String
+messageRead inbox remove = do
+ when debug $ io . hPutStrLn stderr $ "messageRead"
+ let inbox' = fromIntegral . fromEnum $ inbox
+ send = [0x00, 0x13, inbox', fromIntegral . fromEnum $ Inbox0, fromIntegral . fromEnum $ remove] -- local inbox number does not matter for PC, it is used only when master NXT reads from slave NXT
+ sendData send
+ receive <- receiveData
+ case receive of
+ 0x02:0x13:0x00:inbox'':size:message
+ | inbox'' == inbox' && length message == 59 && size <= 59 -> return $ dataToString0 message
+ _:_:e:_ -> failNXT "messageRead" e
+ _ -> fail "messageRead"
+
-- Stops all NXT activities: stops motors and disables sensors
stopEverything :: NXT ()
stopEverything = do
@@ -482,6 +581,11 @@ stopEverything = do
where stopMotor x = setOutputState x 0 [] RegulationModeIdle 0 MotorRunStateIdle 0
stopSensor x = setInputMode x NoSensor RawMode
+shutdown :: NXT ()
+shutdown = do
+ mid <- getModuleID "IOCtrl.mod"
+ writeIOMap (fromJust mid) 0 [0x00, 0x5a]
+
-- Opens a file for writing a linked list of flash sectors
openWrite :: FileName -> FileSize -> NXT FileHandle
openWrite filename filesize = do
View
5 lib/NXTTypes.hs → lib/Types.hs
@@ -1,4 +1,4 @@
-module NXT.NXTTypes where
+module NXT.Types where
import Control.Monad.State
import Data.Int
@@ -37,6 +37,9 @@ type Voltage = Int -- in mV
data OutputPort = A | B | C deriving (Bounded, Enum, Eq, Ord, Read, Show)
data InputPort = One | Two | Three | Four deriving (Bounded, Enum, Eq, Ord, Read, Show)
+data Inbox = Inbox0 | Inbox1 | Inbox2 | Inbox3 | Inbox4 | Inbox5 | Inbox6 | Inbox7 | Inbox8 | Inbox9 deriving (Bounded, Enum, Eq, Ord, Read, Show)
+data RemoteInbox = RemoteInbox0 | RemoteInbox1 | RemoteInbox2 | RemoteInbox3 | RemoteInbox4 | RemoteInbox5 | RemoteInbox6 | RemoteInbox7 | RemoteInbox8 | RemoteInbox9 | RemoteInbox10 | RemoteInbox11 | RemoteInbox12 | RemoteInbox13 | RemoteInbox14 | RemoteInbox15 | RemoteInbox16 | RemoteInbox17 | RemoteInbox18 | RemoteInbox19 deriving (Bounded, Enum, Eq, Ord, Read, Show)
+
type OutputPower = Int -- power and direction, in [-100, 100] range
data OutputMode =
MotorOn -- enables PWM power according to speed
View
4 lib/NXTUltrasonicSensor.hs → lib/UltrasonicSensor.hs
@@ -5,8 +5,8 @@ import Control.Monad
import Data.Word
import NXT.NXT
-import NXT.NXTData
-import NXT.NXTTypes
+import NXT.Data
+import NXT.Types
-- I2C communication with ultrasonics sensor is described in Lego Mindstorms NXT Hardware Developer Kit:
-- Appendix 7 - Ultrasonic sensor I2C communication protocol
View
9 src/Shutdown.hs
@@ -0,0 +1,9 @@
+module Shutdown where
+
+import Control.Exception
+import Control.Monad.State
+
+import qualified NXT.NXT as NXT
+
+shutdown :: IO ()
+shutdown = bracket NXT.initialize NXT.terminate (evalStateT NXT.shutdown)
View
30 src/UploadFile.hs
@@ -0,0 +1,30 @@
+module UploadFile where
+
+import Control.Exception
+import Control.Monad.State
+import System.Environment
+import System.IO
+import System.FilePath
+
+import NXT.NXT
+import NXT.Data
+import NXT.Types
+
+upload :: IO ()
+upload = do
+ args <- getArgs
+ bracket initialize terminate (evalStateT (uploadFiles args))
+
+uploadFiles :: [String] -> NXT ()
+uploadFiles args = mapM_ uploadFile args
+ where uploadFile file = do
+ io $ putStrLn $ "Uploading " ++ file
+ h <- io $ openBinaryFile file ReadMode
+ size <- io $ hFileSize h
+ content <- io $ hGetContents h
+ h' <- openWrite (takeFileName file) (fromIntegral size)
+ mapM_ (write h' . stringToData) $ chunk 61 content
+ close h'
+ chunk _ [] = [[]]
+ chunk n xs = y1 : chunk n y2
+ where (y1, y2) = splitAt n xs
Please sign in to comment.
Something went wrong with that request. Please try again.