Chapter 7. Bonescript

image with no caption

As a programming language, JavaScript has come a long way since its debut as a tool for adding client-side interactivity to websites. It’s still responsible for much of the roll-over graphics, form validation, and asynchronous communication with the server (when you send data to or receive it from a website without leaving the page). Chances are, most of the sites you visit use JavaScript in some way or another.

These days, it’s used for much more than just as a language for client-side (in-browser) scripting. With a framework like Node.js, JavaScript can act as the engine of a web server, which affords web application developers many of the advantages of the event-driven nature of the language. Instead of executing one line of code and waiting for it to finish before executing the next, much of Node.js’s functions are non-blocking, meaning they can handle other things while waiting for a task to complete.

The strengths of JavaScript can also help out in the realm of hardware projects. BoneScript is a Node.js library that brings a lot of the pin control functionality into JavaScript and it will look familiar to anyone with Arduino experience because it has functions like digitalRead, digitalWrite, analogRead, analogWrite, and a few others. However, these functions were designed to take advantage of the event-driven nature of JavaScript.

To explain, when you coded with Python and Adafruit’s BeagleBone IO Python Library in Chapter 5, the Python interpreter executed a single line and waited for it to complete before moving on to the next line. The JavaScript engine, on the other hand, won’t always wait for a line of code to complete before moving onto the next. That’s why many functions have callback methods which tells a function to call another function when it’s done its work.

The Cloud9 IDE

If you’ve worked with the Arduino before, you’re probably familiar with the Arduino IDE, or integrated development environment. It’s the application on your computer where you write the code, compile it, and upload it to the board. BeagleBone hosts its own web-based IDE called Cloud9 for writing applications in BoneScript (see Figure 7-1). To get to the IDE, you’ll have to use a web browser to connect to port 3000 of your BeagleBone. So if you haven’t changed the hostname from beaglebone, you’ll connect to http://beaglebone.local:3000/ (one some networks you may need to use http://beaglebone.home:3000/). See Changing the Hostname for more information. It may take a few moments after booting your BeagleBone for the Cloud9 server to respond.

Under the Project Files panel on the left side, you’ll notice a directory named cloud9. Within that directory you’ll see a few subdirectories. If you want to explore on your own, there are a few BoneScript examples in the demo directory. All of these files are located within the directory /var/lib/cloud9 on your BeagleBone, in case you prefer to use your own IDE or text editor to explore the examples.

Cloud9, a web-based IDE which is great for writing applications with BoneScript
Figure 7-1. Cloud9, a web-based IDE which is great for writing applications with BoneScript

Beginning BoneScript

Because JavaScript is an entirely different language than Python, keep an eye on the differences in syntax. Unlike Python, JavaScript doesn’t care about how you use indentation. You can even put all your code on a single line if you wanted to. (But I wouldn’t recommend it!) JavaScript does however expect a semicolon after each statement.

The best way to learn the language is by example, so let’s jump right in.

Blinking an LED

Double click on the file blinkled.js within the demo directory and you’ll see the code from Example 7-1 appear in the editor pane. If you’d like to see an external LED blink, wire up an LED to pin 14 on header P9 (similar to what you did in Connect an LED but to pin 14 on P9 instead of pin 12 on P8). The code will toggle that pin and it will also toggle the on-board LED labeled USR3, which is right next to the Ethernet port (so if you don’t wire up the LED, you can still see the onboard LED blink).

Example 7-1. BoneScript demo file blinkled.js
var b = require('bonescript'); 1

var leds = ["USR0", "USR1", "USR2", "USR3", "P9_14"]; 2

for(var i in leds) {
    b.pinMode(leds[i], b.OUTPUT); 3
}

var state = b.LOW; 4
for(var i in leds) {
    b.digitalWrite(leds[i], state); 5
}

setInterval(toggle, 1000); 6

function toggle() { 7
    if(state == b.LOW) state = b.HIGH; 8
    else state = b.LOW; 9
    for(var i in leds) { 10
        b.digitalWrite(leds[i], state);
    }
}
1

Load the BoneScript module, which you’ll refer to as b throughout the code.

2

Create an array called leds containing strings referring to several LEDs, including “P9_14” (GPIO pin 14 on header P9). The others are the on-board LEDs labeled USR0 through USR3.

3

Set each LED pin as an output.

4

Create a new variable called state and store the value LOW in it.

5

Write the value from state (LOW) to each LED.

6

Execute the toggle function every 1000 milliseconds (1 second).

7

Declare a new function called toggle, which consists of the code between the following curly braces.

8

If the variable state contains the value LOW, set it to HIGH.

9

Otherwise, set the value of state to LOW.

10

Write the value of state to each LED.

Hover the mouse over the tiny bug icon to the left of the word Runner, in the lower-right corner of the window. If the icon is green and if the hover text says “Run in Debug Mode” (Figure 7-2), click the icon to turn off running in debug mode. This will ensure that when you run something in Cloud9 that it won’t immediately pause in the debugger and that any output text will be displayed at the bottom of Cloud9 every time you click Run.

Turning off debug mode in Cloud9
Figure 7-2. Turning off debug mode in Cloud9

Note

If you don’t see any output text appear at the bottom of Cloud9, or if it scrolls off too quickly, drag with the mouse to increase the size of the lower pane.

When you click the Run button, you’ll see all four USR LEDs blinking on the board and if you hooked up an LED to pin 14 on header P9, you should also see that flash in sync with the on-board LEDs. Press “Stop” to end the process.

What’s interesting about Example 7-1 is that it creates a new function called toggle and then uses setInterval to execute it once every second. Using this method, you can set up multiple functions to run independently and concurrently, but able to access the same variables and data if you wish.

Reading a Digital Input

To learn about reading a digital input with BoneScript, create a new file called inputPrint.js with the contents of Example 7-2. In Cloud9, it’s as easy as clicking the File menu and selecting New File. When you’re done inputting the code, save it (File→Save) and you will be prompted for a name (inputprint.js) and location.

Just like you did in Input, wire up a button or switch to pin 11 on header P8.

Example 7-2. Source code for inputPrint.js
var b = require('bonescript');

var inputPin = "P8_11"; 1

b.pinMode(inputPin, b.INPUT); 2
b.digitalRead(inputPin, printStatus); 3

function printStatus(x) { 4
    if (x.value == b.HIGH) { 5
        console.log("The pin is HIGH");
    }
    else { 6
        console.log("The pin is LOW");
    }
}
1

Create a variable called inputPin containing the string “P8_11” to refer to the GPIO pin 11 on header P8.

2

Set inputPin as an input.

3

Read the state of inputPin and pass that to the function printStatus.

4

Create a function called printStatus that takes in a parameter that will be referred to as x.

5

If the value of the pin is high, write “The pin is HIGH” to the console.

6

Otherwise, write “The pin is LOW” to the console.

When you run the script, the code will be executed once and will display the state of the button or switch in the Output tab at the bottom of Cloud9. Try changing the state of the button or switch and running the script again. If you’re using a momentary switch, be sure to hold the button down (or keep it released) while you run it.

Example 7-2 also demonstrates the callback functionality of the BoneScript library. The digitalRead function can take two parameters (or inputs):

digitalRead(pin, callback)

pin
The pin number that you want to read
callback (optional)
The name of the function to execute when reading the pin has completed. digitalRead will pass the state of the pin to this function.

The function printStatus created in Example 7-2 will accept a single parameter, or input, designated by the x in parentheses next to the function’s name. Within the function, that input will be referred to as x. When digitalRead executes printStatus, it will pass x.value or x.error so that printStatus can take action based on the state of the pin (or any errors that may have occurred).

Interrupts

It’s also possible to attach an interrupt to an input pin, which will allow you to monitor the pin for changes and execute a function if a particular change is detected. You can specify if you want the code to be executed when the pin is rising (it goes from low to high), falling (it goes from high to low), or both. Attaching an interrupt will allow your code to do other things without constantly needing to poll the state of the pin for changes.

The code in Example 7-3 combines code from both Example 7-1 and Example 7-2 and is meant to show that you can have the LED blink and handle changes from the input pin at the same time. This is one of the big advantages to the event-driven nature of JavaScript.

Example 7-3. Source code for interrupt.js
var b = require('bonescript');

var ledPin = "USR3";
var inputPin = "P8_11";

b.pinMode(ledPin, b.OUTPUT);
b.pinMode(inputPin, b.INPUT);

b.attachInterrupt(inputPin, true, b.CHANGE, printStatus); 1

var state = b.LOW;
b.digitalWrite(ledPin, state);

setInterval(toggle, 1000);

function toggle() {
    if(state == b.LOW) state = b.HIGH;
    else state = b.LOW;
    b.digitalWrite(ledPin, state);
}

function printStatus(x) {
    if (x.value == b.HIGH) {
        console.log("The pin is HIGH");
    }
    else {
        console.log("The pin is LOW");
    }
}
1

Execute the printStatus function when any change is detected from inputPin.

When you run the code, you’ll see that the USR3 led will be blinking and every time you change the state of the button or switch, a message will be printed to the console at the bottom of Cloud9.

The attachInterrupt function can take four parameters:

attachInterrupt(pin, handler, mode, callback)

pin
The pin that you want to listen to.
handler
If set as true, it will always execute the callback function when a state change is detected. Otherwise, you can conditionally execute the callback function.
mode
What types of state changes to monitor for. This can be RISING (low to high), FALLING (high to low), or CHANGE (any state change).
callback (optional)
The name of the function to execute when a state change is detected.

Analog Input

If you connect a potentiometer or other analog sensor to the analog input pin 32 on header P9 as instructed in Connecting a Potentiometer, you can also get readings from it in BoneScript. Example 7-4 shows how to take analog readings from sensors and write their values to the console.

Example 7-4. Source code for analogInput.js
#!/usr/bin/node

var b = require('bonescript');

var inputPin = "P9_32";

loop(); 1

function loop() { 2
    b.analogRead(inputPin, printValue); 3
    setTimeout(loop, 1000); 4
}

function printValue(x) { 5
    console.log(x.value); 6
}
1

Execute the function loop for the first time.

2

Define a function called loop.

3

Take the analog reading from inputPin and then pass it to the function printValue.

4

Execute loop again in 1,000 miliseconds (1 second).

5

Define a function called printValue that takes an input which will be referred to as x within the function.

6

Print the input’s value to the terminal.

This example also demonstrates another way to set up a loop that executes repeatedly, but the effect is slightly different than in Example 7-1. The loop function in Example 7-4 includes the code to schedule itself to run again one second after the code before it has been executed, rather than just executing the loop once per second (no matter how long it takes to execute the code in the loop).

It would be a good idea to use the looping method in Example 7-4 if you think the code in the loop function may take longer than the interval to execute.

The analogWrite function can take two parameters:

analogWrite(pin, callback)

pin
The pin that you want to read
callback (optional)
The name of the function to execute when reading the pin has completed. analogWrite will pass the analog value of the pin to this function.

PWM

As discussed in Analog Output (PWM), only certain pins can be used for analogWrite functions. Be sure to review Table 5-1 when choosing what pins to use for PWM. Example 7-5 uses pin 13 on header P8.

Example 7-5. Source code for analogWrite.js
var b = require('bonescript');

var ledPin = "P8_13";

b.pinMode(ledPin, b.OUTPUT);

b.analogWrite(ledPin, 0.05); 1
1

Set the duty cycle of ledPin to 5%

The analogWrite function can take four parameters:

analogWrite(pin, value, frequency, callback)

pin
The pin that you want to use for PWM
value
The duty cycle of the pin, between 0 (always off) and 1 (always on)
frequency (optional)
The frequency of the PWM cycle in Hz (cycles per second)
callback (optional)
The name of the function to execute the PWM value is successfully written

Playing with PWM: “Breathing” LED

If you want to play around with that LED a little and give it a “breathing” effect, check out Example 7-6. It uses setInterval to run a function repeatedly to determine how to change the LED’s PWM duty cycle. That function then executes BoneScript’s analogWrite function to set the LED’s level accordingly.

Example 7-6. Source code for breathingLED.js
var b = require('bonescript');

var ledPin = "P8_13";
var fadingUp = true; 1
var level = 0.0; 2

b.pinMode(ledPin, b.OUTPUT);

b.analogWrite(ledPin, level);

changeLevel(); 3

function changeLevel() { 4
    if (level > 1.0) {
        fadingUp = false; 5
    }
    if (level < 0) {
        fadingUp = true; 6
    }

    if (fadingUp) {
        level = level + 0.01; 7
    }
    else {
        level = level - 0.01; 8
    }
    b.analogWrite(ledPin, level); 9

    setTimeout(changeLevel, 10); 10
}
1

Create a variable to indicate that it’ll start by fading up (when set to false, it will indicate it’s fading down).

2

Create a variable called level to store the PWM duty cycle and start it at 0.0.

3

Run the changeLevel function (defined next).

4

Create a new function called changeLevel.

5

If level has exceeded 1.0, set fadingUp to false.

6

If level has gone below 0, set fadingUp to true.

7

If fadingUp is true, add .01 to level.

8

If fadingUp is false, subtract .01 from level.

9

Set the PWM level of ledPin to level.

10

Execute the changeLevel function again in 10 milliseconds.

When you run the code, should see the LED you connected to pin 13 fading up and down! Try changing the interval for different effects.

Running JavaScript Files from the Command Line

If you’d like to execute your JavaScript code from the command line, you’ll use the command node followed by the name of the file. For example, here’s how to run the blinkled.js example in the BoneScript demo folder:

root@beaglebone:~# cd /var/lib/cloud9/demo/
root@beaglebone:/var/lib/cloud9/demo# node blinkled.js

To end the process, type Control-C.

Knowing how to execute the file from the command line will come in handy for setting your code up as a cron job (see A Crash Course in Cron) or as a system service (see Appendix B).

Setting Scripts as Executable

If you’d like to execute a script by simply typing its name, put the following on the first line of your script. This will instruct the system to look for the Node interpreter when executing the file.

#!/usr/bin/node

You can then set the file as executable:

root@beaglebone:~# chmod +x myScript.js

When you’re in the directory with the file, you can now execute the file just by typing its name after ./:

root@beaglebone:~# ./myScript.js

If you’d like to be able to execute the file no matter what directory you’re in, see Executable Scripts.

Setting JavaScript Files to Run Automatically

You can also have your code start up automatically by adding it to the autorun directory within the cloud9 directory. A system service continually scans this directory for any JavaScript files and will run them. So as soon as you drop a file with the .js extension, it will use node to execute it and ensure that it is executed whenever you boot your BeagleBone.

Removing the file from the autorun directory will terminate the process.

BoneScript Reference

The full reference for BoneScript (see Figure 7-3) can always be accessed by going to http://beaglebone.local/Support/BoneScript/ in your web browser (if necessary, replace beaglebone with your board’s hostname). Not only does it contain reference information for each BoneScript function, but it also lets you modify and execute the code samples directly from the web page. Reference information can also be found on BeagleBoard.org’s site.

BoneScript’s interactive reference pages
Figure 7-3. BoneScript’s interactive reference pages
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.170.63