Thought for Today
Just one thing:
MERGING IS HARD.
That is all.
Just one thing:
MERGING IS HARD.
That is all.
I just ordered my own an Arduino Duemilanove! I’ve been borrowing Job’s Arduino up until now (thanks Job). I’ve got some plans for a few more interesting posts using Atom on the Arduino when this thing arrives.
Hi everyone.
I moved this blog from http://angryhosting.com/ to a VPS hosted with http://linode.com/. I know a bunch of links now target this site, so I’ve done my best to maintain all the old links and files, etc.
If any one notices problems with the old posts (broken links or otherwise), let me know.
Thanks.
The maintainer of HsOpenSSL accepted a patch Job Vranish and I put together that moves to a simple build type rather than the configure step. This has the nice side effect that, with the right libraries installed, we can get HsOpenSSL to install happily in windows without the need for Cygwin to build it.
Here’s how:
cabal update to make sure we have the most recent package.
cabal install --reinstall HsOpenSSL --extra-include-dirs=C:\OpenSSL\include --extra-lib-dirs=C:\OpenSSL\lib\MinGW
Note that I included --reinstall just to make sure we don’t terminate prematurely because of an older version.
Everything should be installed now. Lets test it. Save this into a file somewhere:
module Main where import OpenSSL.RSA main :: IO () main = do key <- generateRSAKey' 2048 65537 print key
And lets build it…
ghc --make test.hs
…and run it…
>test.exe
RSAKeyPair {rsaN = [ZOMG BIG NUMBER], rsaE = 65537, rsaD = [ZOMG ANOTHER ONE], rsaP = [THIS ONE WASN'T AS LARGE], rsaQ = [SAME HERE, BUT STILL PRETTY HUGE] }
If you got some output that wasn’t an error from test.exe, you’ve successfully installed HsOpenSSL in Windows.
Hope this helps someone!
I seem to come across the (false) idea that Data.Binary isn’t able to handle encoding/decoding things of non-network byte order. So, for all those of you who are trying to get Data.Binary to use little endian instead of big endian, consider this a guide.
Lets build a small module that encodes and decodes a simple data.
Module and imports first!
module Main where import Text.Printf import Data.Binary import Data.Binary.Get import Data.Binary.Put import Data.ByteString.Lazy hiding (concatMap, putStrLn)
Lets describe the type we’re going to encode/decode.
data Foo = Foo { w16 :: Word16, w32 :: Word32, w64 :: Word64 } deriving (Read,Show)
I’d like to be able to represent this as both big endian and little endian, so I’m making two newtype wrappers:
-- Foo, Little Endian newtype FooLE = FooLE { unFooLE :: Foo } deriving (Read,Show) -- Foo, Big Endian newtype FooBE = FooBE { unFooBE :: Foo } deriving (Read,Show)
Now for the instances! Lets do little endian first (since it seems to be the most problematic):
instance Binary FooLE where get = do w16le <- getWord16le w32le <- getWord32le w64le <- getWord64le return $ FooLE $ Foo { w16 = w16le, w32 = w32le, w64 = w64le } put fle = do let f = unFooLE fle putWord16le $ w16 f putWord32le $ w32 f putWord64le $ w64 f
Note that putWordXXle and getWordXXle are found in Data.Binary.{Get,Put}–they aren’t exposed by Data.Binary (perhaps they should be?).
What’s going on here? In the get instance, we simple pull bytes off using the little endian functions, make a Foo, and wrap it in a FooLE!
The put instance unwraps Foo and uses the record selectors of Foo to hand stuff to the put* functions.
The big endian version is nearly identical:
instance Binary FooBE where get = do w16be <- getWord16be w32be <- getWord32be w64be <- getWord64be return $ FooBE $ Foo { w16 = w16be, w32 = w32be, w64 = w64be } put fbe = do let f = unFooBE fbe putWord16be $ w16 f putWord32be $ w32 f putWord64be $ w64 f
Again, we look for the put* and get* functions in Data.Binary.{Put,Get}.
Now we just need to create some test data, make a function to print the hex string (so that we know that we output the bytes in the right order), and encode/decode/print the test data to ensure things come back the right way.
td :: Foo td = Foo { w16 = 0x0011, w32 = 0x00112233, w64 = 0x0011223344556677 } tdBE :: FooBE tdBE = FooBE td tdLE :: FooLE tdLE = FooLE td printHex :: ByteString -> String printHex b = concatMap (printf "%02x") $ unpack b main :: IO () main = do let le = encode $ tdLE be = encode $ tdBE le' = decode $ le :: FooLE be' = decode $ be :: FooBE putStrLn $ "le:" ++ (printHex le) print le' putStrLn $ "be:" ++ (printHex be) print be'
What’s the output?
le:1100332211007766554433221100
FooLE {unFooLE = Foo {w16 = 17, w32 = 1122867, w64 = 4822678189205111}}
be:0011001122330011223344556677
FooBE {unFooBE = Foo {w16 = 17, w32 = 1122867, w64 = 4822678189205111}}Now, lets try and get over the idea that you can’t easily use Data.Binary to play with byte order. It’s rather trivial.
Last time we talked about a few changes I made to Atom. This time we’re going to start writing some programs. Our first one will be pretty simple.
First, we need a short C file (this is the only C code, besides the #include’s and the prototype we use in blink.h, we need to write our selves):
#include "blink.h" /* PORTB corresponds some how to Pin 13. We get * a blinking LED on the board. We can also plug * an LED into Pin 13 and the GND pins. */ void setLED(uint8_t value) { PORTB = 0xFF * !!value; } /* main only needs to continously call blink_atom(). */ int main(int argc, char * argv[]) { while(1) { blink_atom(); } }
Next, lets make Main in our Haskell file, pull in some modules, and define the AtomConfig:
module Main where import Language.Atom import Data.Word -- Override some default values cfg = AtomConfig { -- This pulls some stuff in we use below. cIncludes = Just ["blink.h"], -- The (u)intXX_t types are defined in -- stdint.h--which we include from blink.h cTyper = Just $ \t -> case t of Bool -> "uint8_t" Int8 -> "int8_t" Int16 -> "int16_t" Int32 -> "int32_t" Int64 -> "int64_t" Word8 -> "uint8_t" Word16 -> "uint16_t" Word32 -> "uint32_t" Word64 -> "uint64_t" Float -> "float" Double -> "double" }
We reference the C include file blink.h. This is here to pull in some utility AVR chip utility functions and “stdint.h” (which defines uint8_t and friends). We also prototype the blink_atom function Atom will eventually define. We’ll go over what to do with this in just a bit.
Next we define main:
-- Main just has to compile the Atom expression main :: IO () main = compile "blink_atom" (Just cfg) blink
Remember that the version of compile used here is not the version included with atom-0.0.2. This is the altered version we discussed earlier.
The first argument tells Atom what to name the top level function–in this case, blink_atom. You’ll notice that this was the function prototyped in blink.h. Secondly, we pass the config we just defined. If one does not wish to define any include files or override the default C types, it’s perfectly fine to pass Nothing here instead–the defaults will be used.
The last argument, blink, is the name of the Atom ()–the type used to describe our system–we’re about to define.
Lets take a look at that:
-- Simple Atom to toggle an LED blink :: Atom () blink = do -- Is the LED currently on? (Assume it starts False/off) isOn <- bool "isOn" False -- Does the toggle counter need a reset? (Assume it starts False/no) doReset <- bool "doReset" False -- Initialize the toggle counter to delayCycles toggle <- word16 "toggle" delayCycles -- Decrements the toggle counter when it -- is greater than 0. period 1 $ atom "decrement" $ do cond $ value toggle >. 0 toggle <== value toggle - 1 -- Checks if we need to perform a toggle -- reset, and performs it when we need one. period 2 $ atom "reset" $ do cond $ value doReset doReset <== Const False toggle <== Const delayCycles -- Checks if the toggle counter has expired. -- Toggles the LED if it has, then requests -- a reset. period 2 $ atom "flip" $ do cond $ value toggle <=. 0 setLED isOn isOn <== (not_ $ value isOn) doReset <== Const True
cond acts as a guard. It ensures that the boolean statement passed to it is true before allowing the rest of the atom to execute. <== is the assignment operator. We'll discuss period in more depth later, but for now, you just need to know that something with a period of 2 will run every other tick1 through the system whereas something with a period of 3 will run every third tick.
delayCycles refers to the number of cycles through the main loop we want to wait before toggling the state of the LED. Since this particular CPU is running at about 16Mhz, we define this as some relatively large number:
-- How many cycles do we want to delay before -- we flip the LED? delayCycles :: Word16 delayCycles = 30000
setLED describes how to call the corresponding setLED C function we defined in blink.c. Lets look at the type signature of action:
action :: ([String] -> String) -> [UE] -> Atom ()
So, it expects, for its first argument, a function which takes a list of Strings and returns a String. Its second is a list of "untyped expressions", and it produces an Atom.
Atom takes the list of UE's, converts them into the C symbols (often times something like "e1" or "e2"), and then passes them to the provided function for inclusion in some C statment. We can see this at work in the code snippet below:
-- An action (basically raw C code) to set the value -- of the LED. setLED() is defined in blink.c. setLED :: V Bool -> Atom () setLED v = action (\[x] -> "setLED(" ++ x ++ ")") [v'] where v' = ue . value $ v
Here, we take a Bool, and we pass it to the setLED function, which, presumably, turns the LED on when True, and turns it off when False.
This has been a brief discussion of the Haskell code needed to generate the C code for the Arduino board. Next time, we'll investigate the C code that was generated (along with some other artifacts) and how they correspond to the Haskell we have written.
Here are links to the files we've dicussed today:
blink_atom which is the top level Atom function. ↩When Tom Hawkins released the Atom package, I stole my friend’s Arduino Diecimila to see if I could get some Atom-generated code to work. Turns out it wasn’t that hard! I’ll be detailing this in the next few posts. I’m going to use this first post to point out two things I changed in atom-0.0.2.
Int32 is always defined as signed int. Unfortunately, the ATmega168 CPU and the avr-gcc compiler define a signed int as an Int16. I needed a way to customize these types.action can refer to an external function, I wasn’t able to see a nice way to have Atom plop a #include in the generated code. I added this ability as well.My changes only end up affecting two exposed functions. To facilitate the include files and the C types, I added an AtomConfig data type (this can be found in Language.Atom.Code).
data AtomConfig = AtomConfig { cIncludes :: Maybe [String], cTyper :: Maybe (Type -> String) }
I also changed the type signature of writeC. It now reads as:
writeC :: Name -> Maybe AtomConfig -> [[[Rule]]] -> [UV] -> IO ()
Now, we don’t actually have to call writeC our selves 1, but it does get called by compile from Language.Atom.Compile. The compile function now has this type signature:
compile :: Name -> Maybe AtomConfig -> Atom () -> IO ()
Other than the example in Language.Atom.Example, this is the only visible code that I changed.
Here’s how you use the AtomConfig type:
cType :: Type -> String cType t = case t of Bool -> "uint8_t" Int8 -> "int8_t" Int16 -> "int16_t" Int32 -> "int32_t" Int64 -> "int64_t" Word8 -> "uint8_t" Word16 -> "uint16_t" Word32 -> "uint32_t" Word64 -> "uint64_t" Float -> "float" Double -> "double" cfg = AtomConfig { cIncludes = Just ["blink.h"], cTyper = Just cType }
First, we define a function that takes a Type and produces a string representing the C type. We build the config with an optional list of include files 2 and an optional typing function. If Nothing is passed to both fields, then Atom will not use any include files and will use the built in type converter.
In the next post, we’ll start building a simple program: blink an LED hooked up to some I/O pins on the Arduino.
I’ve posted a diff of my changes to atom-0.0.2. Any criticisms are welcome.
I’m making this public so that I will be hounded if fail to complete these tasks or find some one to do these for me (hint hint):
There, I said it, and now it’s public. Some one hold me to this please!
“Right,” said Om. “Now…listen. Do you know how gods get power?”
“By people believing in them,” said Brutha. “Millions of people believe in you.”
Om hesitated.
All right, all right. We are here and it is now. Sooner or later he’ll find out for himself…
“They don’t believe,” said Om.
“But-”
“It’s happened before,” said the tortoise. “Dozens of times. D’you know Abraxas found the lost city of Ee? Very strange carvings, he says. Belief, he says. Belief shifts. People start out believing in the god and end up believing in the structure.”
“I don’t understand,” said Brutha.
“Let me put it another way,” said the tortoise. “I am your God, right?”
“Yes.”
“And you’ll obey me.”
“Yes.”
“Good. Now take a rock and go and kill Vorbis.”
Brutha didn’t move.
“I’m sure you heard me,” said Om.
“But he’ll…he’s…the Quisition would-”
“Now you know what I mean,” said the tortoise. “You’re more afraid of him than you are of me, now. Abraxas says here: `Around the Godde there forms a Shelle of prayers and Ceremonies and Buildings and Priestes and Authority, until at Last the Godde Dies. Ande this maye notte be noticed.’ “
$ while true; do date +%s; sleep 1; done
1234567883
1234567884
1234567885
1234567886
1234567887
1234567888
1234567889
1234567890