Bitlash Users Guide
Bitlash Users Guide
THE OFFICIAL
User’s
Guide
Bitlash Code is made available under the MIT Open Source license.
The Bitlash documentation is made available under the Creative Commons Attribution 3.0
Unported License.
BUG v0.51
i
Chapter 1
About Bitlash
What is Bitlash?
Bitlash architecture
Section 1
What is Bitlash?
BITLASH IN A NUTSHELL Bitlash is an open source interpreted language shell and embedded programming
1. Interprets a C-like mini-language extended environment for the popular and useful Arduino.
for digital and analog IO
The Bitlash interpreter runs entirely on the Arduino and interprets commands that you
2. Recognizes most Arduino library functions type in a terminal window or send programmatically to the serial port:
3. Runs entirely on the Arduino with serial IO
bitlash here! v2.0 (c) 2012 Bill Roy -type HELP- 942 bytes free
for control and output
> print "Hello, world!", millis()
4. Saves functions defined from the command Hello, world! 11939
line in EEPROM; small applications are >
possible
It’s easy to extend Bitlash by naming a sequence of commands as a Bitlash
5. Mini-tasker runs functions periodically in
the background for system control
function, which is like a new word in the Bitlash language. A Bitlash application is a
set of such functions, and since they are stored in the EEPROM, Bitlash can start
6. API makes it extending Bitlash with your C
up your application automatically at boot time for standalone operation.
code easy
7. Open Source on Github (http://bitlash.net) In cases where you need native C code to get closer to the hardware, perhaps for
speed or to interface with a custom peripheral, it’s also easy to integrate your C
8. Extensive documentation and sample
applications code with Bitlash as a User Function. Bitlash ships with many examples of user
functions.
3
Section 2
BITLASH INTERPRETER The Bitlash embedded interpreter that runs in about 14k of memory on an Atmel AVR
processor. It works nicely with Arduino to make a development and prototyping tool for
1. Runs in under 16kB on the AVR ‘328
those situations where you need to bang some bits on the Arduino but writing a sketch in
2. Parses Bitlash code on the fly from RAM, C is premature. It’s very convenient for bringing up and debugging new hardware.
PROGMEM, EEPROM, or SD card
The Bitlash command language is very similar to Arduino C and includes a large reper-
3. Executes commands live from the
command line and runs background tasks toire of the familiar Arduino C functions so you can hack your hardware from the serial
command line or even over the internet via telnet.
You can store commands as functions in EEPROM, compile them into flash memory, or
put them on an SD card. A user-defined bitlash startup function is run automatically at
bootup, making the automation and maintenance of small applications very easy. Here is
the classic Blink13 program as a complete Bitlash application in two functions, toggle13
to toggle the led and startup to initialize and run it:
4
Section 3
Bitlash architecture
ARCHITECTURE BASICS Here is a diagram of the components of Bitlash and how they interoperate with the
1. Bitlash is an Arduino sketch, written in C Arduino software and the Arduino hardware with Atmel CPU.
5
Chapter 2
Get Bitlash
Download
Install
Hello, world!
Section 1
Get Bitlash
$ cd ~/Documents/Arduino/Libraries
7
$ mv bitlash/ bitlash-save/ • Select File / Examples / bitlash / bitlashdemo to open the
$ git clone https://github.com/billroy/bitlash.git demo sketch, then File / Upload to compile and upload it to your
Arduino.
Restart the Arduino IDE and you’re good to go.
When your upload is complete, you are ready to connect to Bitlash. Pro-
Install Bitlash
ceed to the next section on Connecting.
The Arduino Development Environment Guide specifies this procedure
for installing third party libraries: Connect With a Terminal Emulator
"To install these third-party libraries, create a direc- Connect to the serial port at 57600 baud using whatever terminal emu-
tory called libraries within your sketchbook directory. lator works for you. Here are some options:
Then unzip the library there."
• You can use the built-in Arduino Serial Monitor, but see the note
There is also a post on the Arduino weblog with further explanation. below
8
$ screen /dev/tty.usbserial-A7003pQ3 57600 d0, d1, d2, and so on. You can read a pin variable’s value and print it
bitlash 2.0 here! (c) 2012 Bill Roy -type HELP- 935 like this:
bytes free
> > print d12
Congratulations, you are up and running: Bitlash is listening for com- 0
mands, as signified by the ‘>’ prompt. …and assign it like this:
Here is the usual Hello World example you might run as your first Bit- > pinmode(13,1)
lash program:
So, returning to blink13, what we want is to toggle the pin periodically.
> print "Hello, world!" Let’s define a function named toggle13 to toggle the pin:
Hello, world!
> > function toggle13 {d13 = !d13;}
While you’re there you might check the arithmetic: A function named toggle13 containing the Bitlash code “d13=!d13;” is
defined and saved in EEPROM. When the function toggle13 runs, this
> print 2+2
program text sets pin d13 to the logical complement of its current
4
value: if it was zero, it becomes one, and vice versa.
First App: Blink13 Now all we need is to arrange for toggle13 to be run at the desired tog-
gle rate, let’s say every 1000 milliseconds; and let’s not forget to set pin
No discussion of “Hello, world!” for embedded systems would be com-
13 as an output. By using the special function name startup we desig-
plete without blinking an LED. This example shows how to build a com-
nate this function to be automagically run at boot time, completing our
plete Bitlash application using Bitlash functions and auto-start.
application:
First it is necessary to introduce the concept of pin variables: Bitlash
function startup {pinmode(13,1); run toggle13,1000;}
gives direct access to the digital IO pins via single-bit variables named
9
List our functions to make sure they’re right using the ls command:
> ls
function toggle13 {d13 = !d13;};
function startup {pinmode(13,1); run toggle13,1000;}
>
You can invoke the startup function from the command line to test:
> startup
(the LED on pin d13 is blinking)
> boot
bitlash here! v2.0...
(the LED on pin d13 is blinking)
10
Chapter 3
The Bitlash
Language
Execution Model
Commands
Functions
Background Functions
Section 1
Language Overview
5. Expressions support variables a-z, 32-bit When you say run toggle13,1000, it means “whatever else may be happening, please
integer constants, fully recursive function execute the toggle13 function about every 1000 milliseconds.”
calls with arguments, and C-style operators
12
Section 2
Numeric Constants
NUMERIC CONSTANTS Decimal signed numeric constants in the range of a 32-bit signed integer are supported
as you would expect.
1. Signed and unsigned 32-bit decimal
constants: 123, -123
Hex constants of the form 0xHHHHHHHH also work, as do single-quoted ascii character
2. Hex constants: 0x0d constants like ‘q’.
3. Char constants: ‘x’ Binary constants of the form 0b01010101 are also supported.
4. Binary constants: 0b10100101
13
Section 3
String Constants
STRING CONSTANTS String constants can be used as arguments and within the Print statement.
The rules for special characters in string constants are similar to C. The backslash charac-
ter specifies that an escape sequence is to follow. Here are the supported escapes:
\t 0x9 tab
\\ ‘\’ a backslash
\” “‘ a double quote
The hex form is especially useful in crafting escape sequences to print to peripheral de-
vices.
14
Section 4
Numeric Variables
NUMERIC VARIABLES Bitlash provides 26 built-in 32-bit signed integer variables named lowercase ‘a’ through
lowercase ‘z’ (though case is ignored).
1. 26 of them, named a through z
15
Section 5
Pin Variables
PIN VARIABLES Pin Variables: Names for the Arduino Pins [a0..a7] and [d0..d22]
1. Special variables named D0 through D22
You can refer to specific analog and digital pins using pin variables. Pin variables are of
and A0 through A7 provide direct access to
read and set IO pin values, e.g., D13=1 the form a0, a1, a2, … a7 and d0, d1, d2, … d22.
2. Shorthand for digitalRead/Write and analog When a pin variable is used in an expression it is a shorthand for digitalRead (for the
Read/Write d0.d22 pin variables) or analogRead (for a0..a7).
Assigning to a digital pin variable does as you would expect: it turns the output on or off,
just like digitalWrite.
Assigning to the a-pin variables is a little tricky. You might think from the name that it does
some sort of output to an analog pin. But, not so. Assigning to an analog pin variable
does analogWrite, which is PWM output to a DIGITAL PIN!!
16
Section 6
Operators
OPERATORS Here are the operators supported in Bitlash expressions, with meanings as in standard C;
higher precedence binds more tightly.
1. C arithmetic, relational, logical and bitwise
operators are supported with customary
precedence Symbol Name Precedence
17
Section 7
Commands
TYPING TIPS Here is an alphabetical reference list of Bitlash commands. (See also Bitlash functions.)
2. Control-U brings up the last line you typed; If you type a “naked expression” it will be evaluated, and any side effects like function
press Enter to re-execute it calls and function executions will happen, but nothing is printed unless you say so using
print. For example:
3. Control-B suspends/resumes background
functions > d13=1; delay(125); d13=0
>
Your code is executed (d13 goes high for 125 ms), but all you see on the console is the
command prompt after it’s done.
18
> rm blip
> ls peep: print a map of eeprom
>
Peep prints a map of eeprom usage. This can help you see how full
help: display some onboard help text your EEPROM is, and whether you have fragmented free space.
Help displays a short help message that can be helpful if you forget the
name of a command or function. It also displays a list of your functions
via ‘ls’.
ls
List all the functions stored in EEPROM. Note that the “E000” address is actually EEPROM address 0000. Sub-
> function blip {d13=!d13;} tract 0xe000 from the addresses shown.
> ls
function blip {d13=!d13}; print [#pin:] [expr][,](expr][,) – print
In its simplest form: print foo,bar will get you started. But print has a lot
of options, so please see the section on Printing for details.
19
> run t13 0: t13
> ps
0: t13 stop tasknum | stop | stop *
return [value]; -- return a value from a function call Stop a background task by number, stop the current task, or stop all
tasks.
The return statement allows you to return a value from anywhere within
a function. > run t13
> ps
A function that does not return via a return statement returns a value of 0: t13
zero. > stop 0
> ps
> function even {if (arg(1)&1) return 0; else return 1;} >
> print even(1), even(0)
0 1 switch (expr) {stmt0; stmt1; …; stmtN;}
rm: delete a function from eeprom The switch command selects one of N statements to execute based on
the value of a numeric expression. This provides a very easy way to
> function blip {d13=!d13;} build state machines, among other things.
> ls
function blip {d13=!d13;} Syntax:
> rm blip
> ls switch (selection-expression) { stmt0; stmt1; ...;
> stmtN;}
Use “rm *” to erase the whole EEPROM. The selection-expression is evaluated to produce an integer result,
which is used to select one of the supplied statements in curly braces.
run: run a function in the background The selected statement, and only the selected statement from
among those in curly braces, is executed, then execution continues af-
See the section on Background functions for details.
ter the switch statement.
> run t13,125
> ps
20
(Note: This construct is similar to but not strictly compatible with (light flickers)
the C switch statement, which has “case x:” tags to specify each Done
>
case.)
If the value of the selection expression is less than zero it is treated as Execution of the while loop is blocking. In other words, during the exe-
zero and therefore the first supplied statement is executed. If the value cution of a while command, no other functions can run, since Bitlash is
is greater than N, the last statement is executed. working as hard as it can to get to the end of that command line. The
combination of while 1 with delay() is particularly deadly, since it uses
Example: This switch statement in the elevator2.btl example calls the whole processor:
wating, goingup, or goingdown, depending on the value of s, the vari-
able that represents the state of the elevator system: > print "this works but NOTE it will hog the whole ardu-
ino"
switch s {waiting; goingup; goingdown;} > while 1 {print millis(); delay(1000);}
(no prompt again until you press ^C)
If the value of s is <= 0, the waiting function will be called.
Bitlash polls the serial port for Control-C during while loops, so you can
If the value of s is == 1, the goingup function will be called. break out.
For extra credit, let’s initialize the even ones on and the odd ones off:
22
Section 8
Built-in functions
BUILT-IN FUNCTIONS This is an alphabetical reference listing all the built-in functions provided in Bitlash.
1. Many functions call Arduino or avr-glibc Many Bitlash functions are straight pass-throughs from the Arduino functions of the same
functions directly (so the names should be
name. Therefore, the definitive reference for the behavior of the functions is the Arduino
familiar)
extended functions reference at http://arduino.cc/en/Reference/extended.
2. For functions of zero arguments you may
omit the empty parens, so millis and millis() Functions may be used in expressions in the normal way: abs(ar(3)–256) and so forth.
are both valid
Bear in mind that functions return 32-bit integer values (signed long or int32_t in C).
Whether the value is interpreted as signed or unsigned depends on the function.
For functions of zero arguments you may omit the empty parens ():
ar(apin): analogRead(apin)
23
Return a 10-bit analog-to-digital conversion value from the specified beep(pin, frequencyhz, durationms)
analog input pin. See Arduino:analogread at
http://arduino.cc/en/Reference/analogRead. Toggle the specified pin at the specified frequency for the specified du-
ration. Automatically sets pinMode to OUTPUT.
aw(dpin,value): analogWrite(dpin,value)
Beep is blocking: background execution is paused. Use caution for
Write a PWM value to a ** digital pwm output pin**. The pin must be long durations: there is no way to break out of a long beep (the longest
prepared for output beforehand via pinmode(pin,1). value is several days).
A simpler syntax if the pin is fixed is: a6=128 // make the beeper on pin 11 beep at 440Hz for 200ms
> beep(11,440,200)
See Arduino:analogwrite at http://arduino.cc/en/Reference/analogWrite.
br(val, bitnum): bitread
baud(pin,baud): set baud rate for printed output
Returns the value of the bitnum’th bit [0..31] in val.
By default, Arduino prints at 57600 on pin 0 and 9600 on any other pin.
If you wish to set a different rate use the baud function: See Arduino:bitread at http://arduino.cc/en/Reference/bitRead.
// set the default/hardware serial port to 9600 baud See Arduino:bitset at http://arduino.cc/en/Reference/bitSet.
> baud(0, 9600);
bw(val, bitnum, bitval): bitwrite
See printing.
Returns val with the bitnum’th bit [0..31] set to bitval [0|!0].
bc(val, bitnum): bitclear
See Arduino:bitwrite at http://arduino.cc/en/Reference/bitWrite.
Returns val with the bit indicated by bitnum [0..31] set to 0.
constrain(val,min,max)
See Arduino:bitclear at http://arduino.cc/en/Reference/bitClear.
Returns the closest value to val between min and max.
24
See Arduino:constrain at http://arduino.cc/en/Reference/constrain. er(addr): EEPROM.read(addr)
Pause execution for the specified number of milliseconds. ew(addr, value): EEPROM.write(addr, value)
Delay is blocking; nothing else happens while a delay() is being proc- Write one-byte value to EEPROM at addr.
essed. For this reason is it better to use background functions to do
things that span non-trivial time. More on Bitlash and EEPROM at Bitlash Functions.
dw(dpin,bval)
inb(reg)
digitalWrite: Set the designated pin to the given boolean value.
Return the 8-bit value of the specified AVR processor register.
See Arduino:digitalwrite at http://arduino.cc/en/Reference/digitalWrite.
25
The processor registers and their functions are the function of the ex- millis()
tensive ATmega328P Data Sheet at
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf. Returns the number of milliseconds since startup.
You will find a convenient cross reference chart of the registers starting
See Arduino:millis at http://arduino.cc/en/Reference/millis.
on page 425.
min(a,b)
You specify a register address (from the first column of the table on pp.
425 ff.) to tell the inb() and outb() which register to address. In the case Returns the lesser of a and b.
where the table has two addresses, use the right-hand one.
See Arduino:min at http://arduino.cc/en/Reference/min.
For example, to read the Timer0 count register TCNT0, find its entry on
page 470 and note its address is 0x46. Then, to read and print it in Bit- outb(reg,value)
lash:
Set the specified AVR processor register to the given value.
> print inb(0x46)
The processor registers and their functions are the function of the ex-
tensive ATmega328P Data Sheet at
map(val, fromlow, fromhigh, tolow, tohigh)
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf.
Constrains val to [fromlow..fromhigh] and then maps it linearly to You will find a convenient cross reference chart of the registers starting
[tolow..tohigh]. Got it? on page 425.
NOTE: The map() function is deprecated as of Bitlash version 1.1 and You specify a register address (from the first column of the table on pp.
is therefore not included in the build. 425 ff.) to tell the inb() and outb() which register to address. In the case
where the table has two addresses, use the right-hand one.
See Arduino:map at http://arduino.cc/en/Reference/map.
For example, to set the OCR0A register (0x47) to control timer 0 PWM,
max(a,b) you could say:
26
Set the pin to an output pin if outie is true. > run blink13 // only toggles every 100 ms
random(max)
Returns a random number between 0 and max–1.
sign(value)
Return –1 if value is negative, 0 if 0, or 1 if positive.
27
Section 9
WRITING FUNCTIONS IN BITLASH Bitlash allows you to store and manage Bitlash Functions in the Arduino’s EEPROM. By
defining new functions, you extend Bitlash to suit your application.
1. To define a function: function newfunc
{stmt;stmt;}
Think of a function as a stored command line. In Bitlash, that can be multiple statements.
2. Functions are saved in EEPROM; use peep And a statement within a function can call a function, so function execution can nest like
to see a map subroutine calls (up to a dozen levels deep or so). But the simplest use is simply to give a
3. To call a function: newfunc(22, 3, millis()) name to a sequence of commands.
28
Calling a function: foreground Using arguments in the called function
To invoke a function, you can type its name at the command line or re- You can call a function with any number of arguments. A function re-
fer to it in another function (for example in the definition of startup ceives the number of passed-in arguments in arg(0) and the arguments
above): themselves in arg(1)...arg(arg(0)).
29
Running a function: background If there is a function by the name “startup”, it is run automatically at
boot time. Make one like this:
To run a function in the background use the run command:
> function startup {print 1,2,3;}
> run toggle13 > boot
> ps \\ is anything running? bitlash v2.0 here!...
0: toggle13 \\ yes, there's our function running 1 2 3
> stop 0 \\ stop it >
> \\ now it's stopped
Don’t like it?
There is more detail on this topic in the Background Functions section.
\\ redefine the startup function
Listing functions in EEPROM > function startup {...new definition...}
To list all the functions stored in the EEPROM use the ls command: \\ delete the startup function
> rm startup
\\ list all the functions
> ls Tip: If it looks like it’s sitting there doing nothing, it’s probably running a
function toggle13 {d13=!d13;}
function. Press ^C to break out of a looping startup command.
function hello {print("Hello, world!";}
30
> function prompt {print millis,;print "$",;} This is a healthy map. The places marked ‘.’ are empty (==255). The
36244$ \\ press enter at this prompt name-value storage for toggle13 and bcn can be seen. As you add
36484$ \\ time advances
functions you will see them fill from low addresses up, always in pairs.
Inspecting and Formatting Function Storage in the An unhealthy map might have garbage in the supposedly unused part.
EEPROM Or there could be free space available but spread around in frag-
mented blocks (see Fragmentation below).
There may be debris in your EEPROM from another project. Or your
Bitlash program can blow chunks, or Bitlash can blow chunks. Anyway, You can erase and “reformat” the EEPROM using the “rm *” command;
the EEPROM can become “less than fresh”. This might first show up as see below. This will erase any functions you have typed into bitlash, as
funky results from the ls command, for example. well as the garbage. In other words:
You can inspect your EEPROM with the peep command, which prints a Note: RM *" WILL NUKE THE WHOLE EEPROM. There is no way to
map of EEPROM: recover it. Please use caution.
31
This version of Bitlash does not have a method to compact the free You can use the bitlash “peep” command to dump the EEPROM, which
space, but if you are highly motivated to squeeze out the last possible will include your space. Telling bitlash to “rm *” will delete all of your bit-
byte, here is a straightforward but unfortunately manual workaround: lash functions from EEPROM, but will leave your private space unmo-
lested.
• Use ‘ls’ to get the contents of all the functions. Copy to safe
place! It’s up to you to manage your private memory, including providing a
way to clear it, etc. One reasonable approach is to add a new bitlash C
• Use ‘rm *’ to nuke the eeprom. All your functions are gone! Hope
command or two to interact with and manipulate your private EEPROM
you copied them!
space.
• Paste the output you saved into your bitlash terminal emulator to
re-define the functions. Note that flashing your firmware from Arduino will NOT erase your re-
served EEPROM. (This is a feature, not a bug.)
Depending on many factors, (baud rate, clock speed, terminal pro-
gram, OS, …) it may be necessary to paste the definitions one at a
time.
Say you want to reserve 32 bytes at the high end of EEPROM (you’ll
be using EEPROM.read() and EEPROM.write to manipulate it), edit the
#define of ENDDB to be
32
Section 10
Background Functions
BACKGROUND FUNCTIONS Bitlash can run up to 10 functions in the background while you work in the foreground at
the command prompt.
1. You can start up to 10 tasks to be
periodically run in the background
The Run Command
2. Any function-of-no-arguments can be a
task The run command runs a function in the background:
3. To start a task: run beacon, 250 > run toggle13 // LED on D13 starts flashing
> // and you get the foreground prompt back
4. To list tasks: ps
5. To stop a task: stop 3 Think of the run X command as being a “while 1 X” that runs in the time between your key-
strokes.
6. To stop all tasks: stop * or Control+C
7. To pause all background tasks: Control+B In the above example, toggle13 will be called Very Frequently, perhaps as often as once
each time your loop() procedure calls runBitlash().
8. In a task, to schedule the next task time,
call snooze(time-in-ms) Bitlash stops all background functions when you press ^C. You can also stop a specific
one using ps (to discover its process id) and stop.
33
The “run” command has an optional snoozems argument to provide Use the startup function to do a run on your top-level function and your
control over how often each background task is run. This is convenient application can run in the background while you have control of the key-
for tasks that run on a fixed timer: many functions can dispense with board to poke at it:
the snoozing thing entirely if the runtime interval is known when the
> function startup {run myapp}
function is started.
> boot
bitlash here! v2.0...
For example, this will run the function t1 every 27 millis or so:
> ps
run t1,27 0:myapp
If the optional snoozems argument is not specified it is treated as zero: Don’t delay(); use snooze() instead
in other words, you must manage the snooze interval in your function’s
If your objective is to present the illusion of multitasking, you should
code; see below.
avoid using the delay() function in functions, since everything else
This change also has a small impact on semantics of the snooze() func- comes to a screeching halt while delay() is happening.
tion. Previously, snooze() would set the time-at-which-the-task-is-
Foreground keyboard entry may become sluggish if you have many
eligible to run immediately when called.
tasks with delay()s more than a few millis each.
The new behavior is subtly different: the scheduling takes place some-
Bitlash provides the snooze(ms) function to give your background func-
what later, when the function exits the current invocation, not at the
tion tasks a way to delay without hogging the CPU. Bitlash suspends a
time of some call to snooze(). Bitlash maintains a snoozems value for
task which calls snooze() until the specified number of millis has
each background task; by default it is zero, and the task is called as
passed.
fast as the round-robin gets back to it. If you specify a value in the run
command or by calling snooze, this value is saved and applied in the NOTE: Calling snooze() has no apparent immediate effect. Your func-
rescheduling calculation when the task exits. tion continues to execute, if there is further code after the snooze(). But
bitlash will not re-enter your task until the specified time has passed.
Run Your Application Automatically in the Back-
ground Here is an improved toggle13 that uses snooze() instead of delay():
34
>
35
Section 11
Printing
PRINTING TIPS
Printing Overview
1. For simple printing use the print command:
print “hello, world”, 1, 2, 3; There are two ways to print in Bitlash: the legacy print command, and the printf() func-
2. A C-like printf() function is also built-in: tion. The print command is handy for printing basic values without much formatting con-
printf(“%3d”, 7); trol; it was part of Bitlash 1.0 and is partly retained mainly for backwards compatibility.
The “:x” format specifier language will be deprecated in Bitlash 2.1, leaving only the print-
3. Print to any IO pin at your choice of baud
rate ing of basic values.
4. See the examples/ folder for code to The printf() function is new in Bitlash 2.0. It is more compatible with standard C and
customize the output handler much more capable. It will be the supported printing pathway going forward.
The values are printed under control of a format string, which must contain a specifier for
each value to be printed.
36
Example: printf("%03d", 7) ! prints "007" Special Characters
Example: printf("%s","Hello") prints "Hello"
Example: printf("%%") ! prints "%" The percent sign signals a format specifier in the string. To print a per-
cent sign, you must double it:
\” “‘ a double quote
37
Specifying the baud rate in this way has the same effect as calling
Padding baud(4,4800): the pin will remain at the indicated baud rate until it is
changed again.
Normally, numeric values and strings are pre-padded with blanks to fill
out the specified field width. You can pre-pad numeric values with ze- ACCESSING SECONDARY UARTS WITH PRINTF
roes instead by adding a zero before the width character: If you are using an Arduino Mega 1280 or Mega 2560 with Bitlash and
you print to pin 18 then Bitlash will automatically use the Serial1 UART
printf("%03d", 7) prints "007"
rather than software serial for I/O. (There is currently no support in Bit-
lash for accessing Serial2 or Serial3 from printf.)
The “*” character used as a width
If the special character ‘*’ is used in place of a width specifier, the next Likewise if you are using a Sanguino with the AVR ATmega 644P proc-
value in the passed-in value list is used as the width: essor, I/O to pin 11 will use the second UART of the Sanguino rather
than software serial.
printf("%*d", 3, 7) prints " 7" - padded to 3 char-
acters with ' '
The Print Comand
Printing to Alternate Serial Pins This section documents the legacy Print command and its options.
You can redirect output to a non-standard serial pin using the ‘#’ speci-
The print command will be retained in Bitlash going forward, but the “:x”
fier, which picks up the pin number to use from the next value in the
sublanguage will be deprecated in a future version. Users are advised
value list:
to migrate to the printf() function with all due haste.
// prints "7" to pin 4 at the default 9600 baud
printf("%#%d", 4, 7) Basic Printing: a list of items
The simplest form of the print command causes bitlash to print out a
It’s a kludge, but the width specifier can be used to override the default
bunch of numeric values separated by spaces, followed by a newline:
9600 baud sending speed:
> print 1, 2+2, 1<<3
// prints "7" to pin 4 at 4800 baud
1 4 8
printf("%4800#%d", 4, 7)
>
38
The print command can print string constants as well as numeric ex-
pressions, as you may recall from the Hello World example: Here is a table mapping the Arduino equivalents for hex, binary, and
raw byte output:
> print "Hello, world!", 123
Hello, world! 123
To suppress the blank and automatic end of line, print a single value to print use :code example prints
followed by the comma, like this:
hex :x print 32:x 20
> print "Time:", // Prints Time: with no trailing
ascii byte :y print 32:y ascii space
blank or newline
binary :b print 32:b 10000
Printing special characters
bars :* print 3:* ***
The rules for special characters are similar to C. See Language for de-
tails on constructing string constants with arbitrary ascii characters.
Printing Bars
Hex, binary, and raw byte output
You can print a bar of N ’*’ characters using the : format specifier, as
You can specify a modifier to produce several different output types by shown in the example above. Any single-byte symbol will work (+-*/
appending “:spec” to any expression in a print statement. Perhaps an <>%:). Here’s a cheap, low-res oscilloscope on pin A3 with adjustable
example is quickest: temporal resolution:
> print 33, 33:x, 33:b, 33:y, 33:* > while 1: print map(a3,0,1024,10,50):*; delay(5)
33 21 100001 ! *********************************
Serial Output to Alternate Pins: print #n:…
Bitlash includes a software serial output capability which supports trans-
mitting on any available output pin at a user-specified baud rate. This
makes it straightforward to integrate additional serial devices with an
Arduino.
39
You send output to an alternate output pin using the “print #n:” con-
struct, where “n” is the Arduino pin number designator for the desired
the output pin:
By default bitlash will send output at 9600 baud. If you require a differ-
ent baud rate use the baud function:
Note: print #n: is blocking: background tasks will pause while output is
being printed.
40
Chapter 4
Extending
Bitlash
User Functions
User Functions
USER FUNCTIONS While Bitlash functions are a handy and straightforward way to extend Bitlash, there are
cases where you need native C code to get closer to the hardware, perhaps for speed or
1. Copy from an example! See the examples/
folder to interface with a custom peripheral.
2. addBitlashFunction() registers a new Bitlash provides an easy way to call C functions from Bitlash code, just like the Bitlash
function handler with Bitlash built-in functions. In effect, you add your functions to the Bitlash function library, and they
3. Your function must be declared as: numvar become callable from the Bitlash command line.
newfunc(void)
The work happens in a function named addBitlashFunction() that is exposed as part of
4. In your C fuction, the passed-in argument the Bitlash API. You call addBitlashFunction() in your sketch to register your C function
count is getarg(0) and the arguments are
with Bitlash and associate it with a function name. Then Bitlash calls your C function
getarg(1)..getarg(N)
when it is invoked from the command line (or a function…).
Bitlash 2 introduces a new variable-argument scheme, using the getarg() function to fetch
passed arguments from the interpreter core. Users of earlier versions will want to care-
fully review the section on fetching passed arguments below.
If you follow a few rules for setting up your function, you can wrap it in Bitlash without hav-
ing to write a line of parsing code. You get all the parsing, functions, printing, and the rest
of the runtime library for free.
Which is why it is worth reading the next section to learn how to set up your C function so
Bitlash can call it properly.
42
Bitlash exposes the C variable type named numvar representing (in You call addBitlashFunction() from your C startup code to register
the Arduino version) the “signed long” integer data types. All internal your function with Bitlash.
calculations are done using fixed-point arithmetic in this precision.
addBitlashFunction() takes two arguments: * a name for the new func-
So the first rule is that your function must return a value of type num- tion * the function handler to call with “(bitlash_function)” cast before it
var.
While you can call addBitlashFunction() any time, one would normally
Here is a simple example to walk through the plumbing. This example call it from setup(), like this, to complete the code for the example:
code is in the examples folder supplied with Bitlash, so you can open it
void setup(void) {
in the Arduino IDE by selecting File -> Examples -> bitlash -> userfunc-
initBitlash(57600); // must be first to initial-
tions if you’d like to follow along.
ize serial port
Suppose for some reason we need to be able to grab the count value
// Register the extension function with Bitlash
from the AVR’s internal Timer1 timer and use it in Bitlash. // "timer1" is the Bitlash name for the func-
tion
In the Arduino sketch, we declare a user function named “timer1”, tak-
// (bitlash_function) timer1 tells Bitlash
ing no arguments, returning a numeric Bitlash value containing the where our handler lives
timer count register value we’re after: //
addBitlashFunction("timer1", (bitlash_function)
numvar timer1(void) { timer1);
return TCNT1; // return the value of Timer 1 }
}
...void setup(void)... void loop(void) {
runBitlash();
This completes the definition of the user function. What remains is to }
call addBitlashFunction() to register this new handler.
The setup() function initializes Bitlash and then calls addBitlashFunc-
Registering a Function With addBit- tion() to install timer1(). The loop() function runs Bitlash as usual.
43
> print timer1(), timer1(), timer1() The function argument to addBitlashFunction() provides Bitlash with
22 194 67 the name of the C function handler you wrote to handle your user func-
tion. A small syntactic complexity: It is required to cast your function to
The Function Name the type “(bitlash_function)” to pass it to Bitlash, which is why the man-
tatory text “(bitlash_function)” appears before the function name in the
A function name is a string constant of up to IDLEN (11) characters,
example:
like “timer1”. It must start with a letter, and may contain letters, num-
bers, and the underscore ‘_’ and period ‘.’ characters. ...
addBitlashFunction("timer1", (bitlash_function) timer1);
Overriding the built-in function names is not supported; the user func-
...
tions are searched last so if you use a built-in name your function will
never be called. If you omit the cast the compiler will complain about function type mis-
matches.
Fetching Passed Arguments with getarg()
Your bitlash_function is declared (void). How does it get argument val-
NOTE: Maximum Number of User Functions
ues from Bitlash? Bitlash ships with MAX_USER_FUNCTIONS set to 10 and will throw
an exception if you try to install more.
Starting with Bitlash 2.0, a function does not need to accept any particu-
lar number of arguments. The arguments being passed to your macro If you need more functions, adjust the definition of MAX_USER_FUNC-
are available to your code as via the Bitlash function API point getarg(). TIONS in bitlash-functions.c.
44
Bitlash background functions don’t (well, can’t) run while your function Printing From User Functions: Console Redirection
is running, since they get time on a poll from loop(). This may affect
your design. Printing from a user function using the Arduino Serial.print() function
works as usual: it goes to the console as you would expect.
Calling Internal Bitlash Functions
You can also print through Bitlash using the Bitlash printing primitives:
Generally it’s fair game to call any internal Bitlash functions you want sp(), spb(), and speol(), about which you will find more in
from your user function; you’re inside the interpreter, after all. But there bitlash-serial.c. If you use the Bitlash printing primitives, you will gain
are things you should be cautious about in addition to the CPU time is- the benefit that any serial output redirection that is in effect when your
sue discussed above. function is called will be applied to your printed output. In other words,
your function can automatically print to whatever pin Bitlash has se-
The interpreter is not re-entrant, and is halfway through parsing and
lected as the output pin.
executing a command line when it encounters your function reference.
Don’t re-enter Bitlash by calling doCommand or runBitlash from your Here’s an example to clarify. Suppose we have these two user func-
user function. tions wired up as sayhi1 and sayhi2:
Avoid recursion and stack-local storage where possible in user func- void sayhi1(void) { Serial.print("Hello"); }
tions. Bear in mind that your function is executing inside the parser and void sayhi2(void) { sp("Hi"); }
is competing with the parser for stack space. Deeply nested recursion Consider this bitlash code:
from a user function can cause a stack overflow, and local variables in
print #3: sayhi1()
your function only make this happen faster. print #3: sayhi2()
print #4: sayhi2()
You can call the get_free_memory() function (which handles the Bitlash
free() function) to see how much stack space is available when your The first line will print “Hello” to the serial console. Serial.print() output
function runs. always goes there.
Unfortunately, it is very difficult to provide hard and fast rules about The second Bitlash command will print “Hi” to the device on pin 3,
how much stack will be required for your application; experimentation is since “redirection to pin 3” is in effect when the function is called.
the best way to be sure. Personally, I get uncomfortable when free()
goes below 200 but I have seen applications that require much more.
45
Likewise, the third command will print “Hi” on pin 4; thus a single user
function can drive multiple output streams without needing special
code.
Examples
See the examples folder in the Bitlash distribution for more. You can
load examples in the Arduino IDE using the File -> Examples -> bitlash
menu.
46
Section 2
THE BITLASH API Your Arduino C program can interact with Bitlash using the functions documented here.
Of course, in the tiny and open world of Arduino most everything is visible globally. So
1. In setup(): initBitlash(baudrate);
feel free to dive in and call what you need. The entry points documented here are in-
2. in loop(): runBitlash(); tended to be reasonably well hardened for third party use.
3. It’s C. Call anything you like. See src/
bitlash.h initBitlash(baudrate);
4. A few useful API entry points are You must call this first, normally from setup(), to initialize Bitlash and set the serial port
documented in this section baud rate.
runBitlash();
You must call runBitlash() from your loop() function to make Bitlash go. The more fre-
quently you call runBitlash(), the more smoothly foreground and background activity will
run. If you don’t call runBitlash(), nothing will happen.
This is the minimum possible integration, and in fact it is the bones of the code that you
will see at the bottom of bitlashdemo.pde:
void setup(void) {
initBitlash(57600);
}
void loop(void) {
runBitlash();
47
// YourOtherCodeHere(); Bitlash will buffer and echo each character until you send a carriage re-
} turn ‘\r’ or linefeed, whereupon it will execute the line, the same way it
works from the console.
doCommand(char *command);
See the examples/bitlashtelnet2.pde telnet server for a sample integra-
A simple way to control Bitlash is to use the doCommand() function to tion using doCharacter().
execute commands from your code. Your code can call doCommand()
to make Bitlash “do stuff” – anything you can type, actually, up to the Console redirection with setOutputHandler()
buffer size limit. Here’s a dumb example that leads up to our next big
You can arrange to capture all the output that Bitlash would normally
case study: this code spends a lot of energy looking for the precise milli-
send to the console serial port, and redirect it to suit your application.
second to beep at the top of the hour:
Use the setOutputHandler() api to direct Bitlash to route its output to
void setup(void) { your character-handling function, which should be defined as taking a
initBitlash(57600); single byte and returning a void, as in:
}
setup() {
void loop(void) { ...
runBitlash(); setOutputHandler(&serialHandler);
// beep at the top of the elapsed hour }
if (millis() % (60*60*1000) == 0) {
! ! doCommand("beep(11,440,1000)"); void serialHandler(byte b) {
! } ...
} }
Lots of ways to do this better (read on for one example), but the takea- There are four examples in the Bitlash distribution that show how this
way point is that your C code can drive Bitlash. works:
48
See examples/bitlashtelnet.pde for an example implementing both in- assignVar(char var, long value);
put injection and output capture. examples/bitlashtelnet2.pde is similar
but uses the doCharacter() api instead of doCommand(). Assigns the (signed long 32-bit integer) value to the indicated Bitlash
variable.
And of course the Bitlash web server, BitlashWebServer, uses this con-
assignVar(0,42); ! // a=42
sole redirection capability. See examples/BitlashWebServer.pde
You refer to a variable using an integer index in the range [0..25] corre-
sponding to ‘a’..‘z’. For example, here is how your code could use the
getVar command to read out the value of the bitlash variable ‘t’ and put
it into the signed long C variable named ‘temperature’:
void loop(void) {
...
long temperature = getVar('t'-'a');
...
Here are the three API functions for Bitlash variable manipulation. Ex-
amples of their use are shown below in the clock application.
49