Programming the Photon - Getting Started with Spark Core and Photon (2015)

Getting Started with Spark Core and Photon (2015)

Chapter 3. Programming the Photon

Chapter 2 gave you your first taste of programming the Photon/Core, this chapter will take you deeper into the world of programming, and, if you are new to coding, teach you some of the basics of the C language that these devices use.

If you are a seasoned programmer, you can skip big chunks of this chapter.

The Web IDE

In chapter 2, you touched on using the Web IDE.

Apart from typing in the code and clicking on a couple of the buttons, there are large uncharted areas of the Web IDE to explore.

You have already used the Flash button at the top of the button panel. The Verify button will check a program and make sure the code is legal without actually sending it to the Photon. Since the Flash button also verifies the program and will not send it unless its legal, you may find the Verify button to be of limited use.

The Save button will save whatever app is currently showing in the editor window to the right. The <> Code button toggles the side panel that contains your list of apps and the buttons that allows you to remove an app or create a new app, as you did in Chapter 2.

Underneath the Code button, the Libraries button allows you access to a huge body of community-contributed libraries of code that you can make use of in your apps. Many of these libraries are concerned with interfacing specific types of hardware such as sensors and displays.

The Docs button opens up the web page for the documentation for the Photon.

The Photons button allows you to manage your Photons and Cores. When you click on it a side panel slides out, listing all the devices associated with your account so that you can manage them in various ways.

Figure 3-2. Figure 3-2. Managing Your Photons

The list will show all the Photons and older Cores you have that are associated with your account. The gold star next to the device indicates that this is the currently selected device, so if you clicked on the flash button, it is that device that would be programmed.

The blue dot to the right of the device name indicates that the device is active and connected to the cloud service.

Coding an App

Lets start by dissecting the app that you wrote in Project 2 that changed the color displayed on the Photon’s built-in LED between red, green and blue at two-second intervals. As a reminder, the code for this is listed below:

void setup() {

RGB.control(true);

}

void loop() {

RGB.color(255, 0, 0);

delay(2000);

RGB.color(0, 255, 0);

delay(2000);

RGB.color(0, 0, 255);

delay(2000);

}

A program (or “app” in Spark terminology) takes the form of a series of instructions that the computer (in this case Photon or Core) must execute one after the other. There is a little more to it than this, or the program above wouldn’t have strange { and } symbols as well as mystical words like void, setup and loop and a seemingly random assortment of punctuation.

As you can see, the code is in two sections. One section that starts with the words void setup and another that starts with void loop. Each of these sections of the program code are called a function. A function is a way of grouping together a set of instructions and giving them a name.

Looking at the first function, it begins with the word void. This might seem an unusual word to indicate the start of a function. In case you are interested, this is because every function has to specify a type (more on types later). Both the functions in this program have no type, so we have to indicate this fact using the word void. One thing that you will notice right away about programming languages is that they are really fussy. Computer scientists love things to be orderly and precise, hence we need to write void before our setup and loop functions.

After the word void comes the function name setup followed by (). Later on, you will see functions that have something inside the () called parameters. Again, the precise nature of the C language dictates that even if this function happens not to have any parameters, you must still include the parentheses.

Every app must include the functions setup and loop. That is why when you click on the button CREATE NEW APP the skeleton code for these two functions will appear as below, ready for you to add in your own instructions.

void setup() {

}

void loop() {

}

The program code that you add to a function needs to go between the { and }, with a ; after each instruction line. Over the years, programmers have developed conventions on how you should write your code to make it as easy as possible for another programmer to understand the code, or for you to understand it when you return to it after not looking at it for a while.

These conventions include indenting each of the lines inside the function, so that it is easy to see that they belong to it. You will hear such sections of indented code being referred to as a block of code. Unlike the Python language the C language used by the Photon and Core ignores all indentation. If you leave out the indentation, the program will still work just fine, its just a matter of convention to keep things neat.

The use of the two functions setup and loop is borrowed from Arduino and works in just the same way. When your device is first powered up, or after you press the Reset button, the lines of code inside the setup function will be “run” (executed) just once. They will not be run again until the Photon or Core is reset.

In the case of our example program, the setup function has just a single line of code in it:

RGB.control(true);

This command tells the Photon/Core that we want to take control the color of its RGB LED rather than let it do all its fancy blinking to tell us its status. Don’t worry, the device will revert to blinking its status colors when we upload a different app that does not take control of the RGB LED. We will still be able to send new apps the the Photon/Core, its just we will not know whether it is connected properly to the Internet or not with the app running.

The loop function is different to the setup function, because it will run over and over again. As soon as it has finished running the last of the commands within its curly braces, it will start running the first one again.

In this case, there are four lines of code that will be run each time around the loop. The first line is:

RGB.color(255, 0, 0);

Our setup function code gave us control of the RGB LED. Now we need to instruct it to change color. The first line of the loop code sets the color to be red. It does this because RGB.color is a function like setup and loop, but in this case, a function that is built-in to the Photon’s software which we can just make use of. Where the setup and loop functions had empty () after them, you can see that RGB.color has three parameters, separated by commas. These three parameters represent the brightness of the red, green and blue channels of the LED respectively. The number supplied for each parameter is between 0 and 255, where 0 means no light and 255 means full brightness. So, the values of 255, 0, 0 mean full brightness red, no green and no blue. If we were to use 255, 255, 255 the LED would shine all three colors at full brightness and appear white.

Once the color is set to red, we want the app to do nothing for a couple of seconds before we change the color to green. There is anther built-in function that we can use for that called delay. So we use this in the second instruction of the loop function:

delay(2000);

This causes the Photon/Core to twiddle its virtual fingers for 2000 milliseconds. A millisecond is 1/1000 of a second, so 2000 of them is the same as 2 seconds.

The first two lines of the loop function are repeated two more times, to change the LED color to green and then to blue.

void loop() {

RGB.color(255, 0, 0);

delay(2000);

RGB.color(0, 255, 0);

delay(2000);

RGB.color(0, 0, 255);

delay(2000);

}

You might be wondering if you need the final delay command inside loop. Try deleting it and then flashing the code to your Photon/Core again. The updated program will not turn the LED blue at all. In fact, what is happening here is that the LED is being set to blue, but then faster than the human eye, the app is back around to the first line of loop again and the LED will be set to red.

Each time around the loop, the Photon/Core will also do a quick check to see if the Cloud Service is trying to push it a new app. If there is a new app, then your app will be interrupted, and the Photon/Core will take control of the LED back and start flashing purple to indicate that the new app is being “flashed" onto the Photon/Core.

Comments

Project 1 was simply to blink the blue LED next to D7 using the example program provided by Spark. It’s actually a more complex program than that of Project 2, so let’s build on what you have seen in Project 2 and now work through Project 1. Along the way, you will encounter various programming ideas.

It will help to have the code for the example app “Blink an LED” open in the code editor of the Web IDE as the code is examined. Here’s the code. It actually gets pretty wide so the right-hand side of the text has been truncated in the listing below.

// Define the pins we're going to call pinMode on

int led = D0; // You'll need to wire an LED to this one to see it blink.

int led2 = D7; // This one is the built-in tiny one to the right of the USB jack

// This routine runs only once upon reset

void setup() {

// Initialize D0 + D7 pin as output

// It's important you do this here, inside the setup() function rather than outside it or in the loop function.

pinMode(led, OUTPUT);

pinMode(led2, OUTPUT);

}

// This routine gets called repeatedly, like once every 5-15 milliseconds.

// Spark firmware interleaves background CPU activity associated with WiFi + Cloud activity with your code.

// Make sure none of your code delays or blocks for too long (like more than 5 seconds), or weird things can happen.

void loop() {

digitalWrite(led, HIGH); // Turn ON the LED pins

digitalWrite(led2, HIGH);

delay(1000); // Wait for 1000mS = 1 second

digitalWrite(led, LOW); // Turn OFF the LED pins

digitalWrite(led2, LOW);

delay(1000); // Wait for 1 second in off mode

}

The first thing to notice is that the program has a whole load of lines that start with //. Starting a line with // indicates that the line is not actually program code at all, but a comment that tells the reader something about the code. The line below tells us pretty much all we need to know about what the next couple of lines are for.

// Define the pins we're going to call pinMode on

The two lines that follow are a mixture of real code and comment. The // word is used again, after the semi-colon to indicate that the rest of the line is also a comment.

int led = D0; // You'll need to wire an LED to this one to see it blink.

int led2 = D7; // This one is the built-in tiny one to the right of the USB jack

The commenting in this particular app is really quite excessive, and is deliberately very detailed to help the novice try and work out what on earth is going on with the program.

Variables

The two lines above define something called variables. Variables are an incredibly useful programming concept. They allow you to give something a meaningful name.

In the case of the first of the lines, there is a pin name D0. That’s fine. We know that this refers to one of the physical pins on the Photon/Core that can be used as an input or output, but it says absolutely nothing about what that pin is to be used for in the rest of the app. Actually, as the comment says, an LED is going to be attached to D0 (you will do this in chapter 4). Later in the code, when we want to turn than pin on and off, its nicer to refer to that pin as the LED pin rather than the actual pin number. The command below is said to assign the value D0 to the variable named led.

int led = D0;

Once variable has been assigned the value D0, from then on, we can refer to pin D0 as led rather than D0. The word int at the start specifies the type of the variable. The type int means a number, and while you might argue that D0 does not look like a number, actually, behind the scenes, D0 is a number used internally be the Photon/Core.

In a later section we will explore the concept of variable types.

Now that a variable called pin has been defined to refer to D0, you can use that variable both in the setup function, where we set the pinMode of the led pin and in the loop function where it is turned on and off to make it blink.

Using a variable like this has the great advantage that, if you decided to use pin D3 instead of D0, then you would only have to change the single line

int led = D0;

to

int led = D3;

Morse Code

Now, you might wonder why a book about the latest IoT hardware like the Photon would be talking about a 19th century invention called Morse Code. The answer lies in the fact that there are only so many things you can do with an LED, and flashing out Morse code signals is one of the more interesting ones.

Morse code represents letters and numbers as short (dot) or long (dash) beeps or flashes of light. For example the letter A is represented as .- (dot dash), one short pulse followed by one long pulse. Although there are a few variants of Morse code, we will use International Morse Code here.

If you were to convert the word PHOTON to Morse code, the resulting message would be: .--. .... --- - --- -. Morse code does not distinguish between upper and lowercase letters.

INTERNATIONAL MORSE CODE

The table below lists the International Morse code letters and digits.

A

.-

N

-.

0

-----

B

-…

O

---

1

.----

C

-.-.

P

.--.

2

..---

D

-..

Q

--.-

3

…--

E

.

R

.-.

4

….-

F

..-.

S

5

…..

G

--.

T

-

6

-….

H

….

U

..-

7

--…

I

..

V

…-

8

---..

J

.---

W

.--

9

----.

K

-.-

X

-..-

L

.-..

Y

-.--

M

--

Z

--..

Flashing SOS

SOS is ... --- ... in Morse code and is used by someone in distress, usually on the high seas and usually a hundred years ago, but lets keep up the pretense that Morse code is still somehow relevant.

We have already made an LED blink, so let’s look at how we can apply what we have learnt to flashing a distress signal (albeit, on the small RGB LED).

As a reminder, here is the code from Project 2.

void setup() {

RGB.control(true);

}

void loop() {

RGB.color(255, 0, 0);

delay(2000);

RGB.color(0, 255, 0);

delay(2000);

RGB.color(0, 0, 255);

delay(2000);

}

If you typed this code in and got it working in Chapter 2, then all is well and good. If not, then the easiest way to get this into the IDE and then onto your Photon/Core is to click on the Libraries button in the Web IDE and find the library called PHOTON_BOOK. You will find all the project programs used in this book as examples.

Select the file p_02_RGB_LED and then click the button USE THIS EXAMPLE. A copy of the program will open up in the editor and you can then flash it to your Photon/Core. Note that this will be your own copy of the original program, so you can modify it if you wish.

Flash the program onto your Photon/Core, just to remind yourself of the process and see what it does.

While multi-color Morse code could be useful, we should just start by doing some blinking in white light. Change the code of Project 2 to simply blink white (255, 255, 255) as shown below:

void setup() {

RGB.control(true);

}

void loop() {

RGB.color(255, 255, 255);

delay(500);

RGB.color(0, 0, 0);

delay(500);

}

You can also find this code in the examples library as ch_03_blink_white.

The sequence of instructions in loop is now:

1. set the RGB LED to white (red, green and blue all maximum brightness)

2. delay half a second

3. turn off the RGB LED

4. delay half a second

5. start again

Flash the app onto your Photon/Core and you should see the LED blink white once per second.

To flash SOS (... --- ...) we can just add some more lines to loop and vary the delays. A dash is three times as long as a delay and the gap between one dot or dash and the next should be the same as a dot. The gap between one letter and the next should be the same as a dash, so change the program so that it appears as below. Note that using copy and paste will save you some time.

void setup() {

RGB.control(true);

}

void loop() {

// flash S

// dot

RGB.color(255, 255, 255);

delay(200);

RGB.color(0, 0, 0);

delay(200);

// dot

RGB.color(255, 255, 255);

delay(200);

RGB.color(0, 0, 0);

delay(200);

// dot

RGB.color(255, 255, 255);

delay(200);

RGB.color(0, 0, 0);

delay(600);

// end of S

// flash O

// dash

RGB.color(255, 255, 255);

delay(600);

RGB.color(0, 0, 0);

delay(200);

// dash

RGB.color(255, 255, 255);

delay(600);

RGB.color(0, 0, 0);

delay(200);

// dash

RGB.color(255, 255, 255);

delay(600);

RGB.color(0, 0, 0);

delay(600);

// end of O

// flash S

// dot

RGB.color(255, 255, 255);

delay(200);

RGB.color(0, 0, 0);

delay(200);

// dot

RGB.color(255, 255, 255);

delay(200);

RGB.color(0, 0, 0);

delay(200);

// dot

RGB.color(255, 255, 255);

delay(200);

RGB.color(0, 0, 0);

delay(600);

// end of S

delay(2000); // delay before repeat

}

While this code works just fine, there is much more of it than there needs to be, as a lot of the code is repeated. In the next section you will use functions to shorten the code considerably.

Functions

We have been happily using some of the functions such as delay and RGB.color that are built in to the Spark.io system. You can also write your own functions to group together lines of code that you might want to use over and over again in your program.

For example, wouldn’t it be great if there was a function called flash, by which we could just pass as parameters the duration of the flash and how long to pause before any further flashing. Well, you can create such a function and then modify the SOS program to use it. The function looks like this:

void flash(int duration, int gap) {

RGB.color(255, 255, 255);

delay(duration);

RGB.color(0, 0, 0);

delay(gap);

}

The function starts with the word void, because this function does not return any value. Next we have the name of the function, and I have decided to call it flash. Inside the parentheses, two parameters are defined, duration and gap. Both need to have the type specified for them. Since they are a whole number of milliseconds the type int should be used.

The body of the function is just like a section of the long-winded code we had before, but now, instead of having fixed numbers like 200 or 600 inside the delay functions, we have what look like variable names of duration and gap. These values will be passed into the function when we use it in loop.

To see how this works, lets now look at the whole program, which you can find in ch_03_SOS_function.

void setup() {

RGB.control(true);

}

void loop() {

// flash S

flash(200, 200);

flash(200, 200);

flash(200, 600);

// flash O

flash(600, 200);

flash(600, 200);

flash(600, 600);

// flash S

flash(200, 200);

flash(200, 200);

flash(200, 600);

delay(2000); // delay before repeat

}

void flash(int duration, int gap) {

RGB.color(255, 255, 255);

delay(duration);

RGB.color(0, 0, 0);

delay(gap);

}

This is great, because the this program is just 27 lines long rather than the 59 lines of the previous version. Smaller programs are better, being easy to maintain. Programmers have an acronym that they use - DRY - “Don’t Repeat Yourself” and will talk of good code being DRY.

Now, to flash the letter S, you can just call flash three times in a row. On the last occasion, longer delay is used to allow a gap between letters.

We could take this program a step further and create two new functions called flashS and flashO that call flash. This would simplify the code in loop even more. The result of this can be found in the file ch_03_SOS_function2.

void setup() {

RGB.control(true);

}

void loop() {

flashS();

flashO();

flashS();

delay(2000); // delay before repeat

}

void flash(int duration, int gap) {

RGB.color(255, 255, 255);

delay(duration);

RGB.color(0, 0, 0);

delay(gap);

}

void flashS() {

flash(200, 200);

flash(200, 200);

flash(200, 600);

}

void flashO() {

flash(600, 200);

flash(600, 200);

flash(600, 600);

}

This hasn’t made the program any shorter, but an interesting thing has happened. Some of the comments in loop have become so obvious that they can now be removed. For example, there is little point in preceding the line:

flashS();

with a comment like:

// flash S

Generally, the fewer comments that are needed to “explain" the code the better. The code has become less obscure and is starting to be self-explanatory.

Incidentally, it does not matter where in the program you write the code for a function. However, the convention is to have the setup and loop functions at the top of the file, as these are the root of any later calls to other functions. In other words, setup and loop will always be the starting point for anyone reading through the program to work out what it does.

Types

The SOS program is now looking pretty neat. You can start at loop, and understand that loop is going to call flashS and flashO. You can then look at flashS and see that flashS calls flash. Its all quite easy to “read”. The program does, however, have one weakness: should you want to make it flash SOS faster or slower, you would have to go through and change all occurrences of 200 and 600 to something else. Its easy to fix this so that you only have to change one variable.

The modified version can be found in the file ch_03_sos_vars.

int dot = 200;

int dash = dot * 3;

void setup() {

RGB.control(true);

}

void loop() {

flashS();

flashO();

flashS();

delay(2000); // delay before repeat

}

void flash(int duration, int gap) {

RGB.color(255, 255, 255);

delay(duration);

RGB.color(0, 0, 0);

delay(gap);

}

void flashS() {

flash(dot, dot);

flash(dot, dot);

flash(dot, dash);

}

void flashO() {

flash(dash, dot);

flash(dash, dot);

flash(dash, dash);

}

At the top of the file, two new variables, dot and dash have been added. The variable dot is set to 100. This will be the duration of the delay for a dot flash. The variable dash is the duration of a dash and we could just set this directly to 600, but then if we wanted to make the SOS blinking faster or slower, we would have to change both variables. Since a dash is always three times as long as a dot, we can express that in our code like this:

int dash = dot * 3;

Here, you are defining a new variable called dash (of type int) and then assigning it a value of dot * 3. In the C language * means multiply.

As well as * for multiply, you can use + for add, - for subtract and / for divide.

Change dot to 100 and then flash it onto your Photon/Core. Notice how the blinking is now faster.

The int Type

We have established that the type int is used for whole number numbers. These numbers can be positive or negative or 0 but must be in the range -2,147,483,648 to +2,147,483,647.

Note that if you have come from the world of Arduino where the range of numbers in an int is much smaller, this will be a pleasant surprise for you. Although Spark C has other integer types like long (same range as int) as well as signed and unsigned versions of the types, there is little point in ever using anything other than int to represent whole numbers.

The float Type

Variables of type int are great for whole numbers, like pin numbers or counting, but, occasionally, you might want to use numbers with a decimal place in them. For example, if you are reading temperatures from a sensor, the nearest degree might not be precise enough and you might want to represent a value of say 68.3 degrees.

For these kind of numbers you cannot use int. You use a type called float. They are called floats, because they are “floating point" numbers. That is, the position of the decimal place could be anywhere in the number; they are not say fixed to two decimal places.

Here is an example of a float:

float temperature = 68.3;

Floats have a vast range, from -3.4028235E+38 to 3.4028235E+38. The notation E+38 means with 38 zeros on the end of the number. These numbers are as big as you could ever need. For the mathematically minded, floats here are 32 bits.

So, if floats have a much wider range, then why bother with restricted int values? Surely we could just use floats, and if they need to be whole numbers, just have .0 on the end.

The reason this is not done is that floats are deceptive. Although they have a wide range of possible values they do this by using an internal representation that effectively approximates the number. Although they represent numbers that can be 39 digits long, if you performed some arithmetic on two numbers that were that long, the result would not be exact and under some circumstances, you can get results equivalent to 2 + 2 = 3.9999999999999999999.

The likelihood of such errors can be reduced by using the type double which uses a 64 bit representation and is, therefore, a lot more precise.

Arithmetic in floats is also slower than with ints, and, if you use doubles, it takes up twice as much memory. So, avoid using floats or doubles unless you have a good reason for it, such as the temperature example.

Other Types

As this book progresses, you will meet other data types such as boolean, which represents the values true and false, as well as more complex types, like strings, which are used to represent text.

Arrays

The variables used so far have all been just single values. Sometimes you need to use a data structure that represents a list of values. For example a list of flash delays.

Open the app ch_03_SOS_Function in the Web IDE. This is taking a step backwards, but this version is quite suitable to modify to use an array of delay values.

The loop function of this program looks like this:

void loop() {

// flash S

flash(200, 200);

flash(200, 200);

flash(200, 600);

// flash O

flash(600, 200);

flash(600, 200);

flash(600, 600);

// flash S

flash(200, 200);

flash(200, 200);

flash(200, 600);

delay(2000); // delay before repeat

}

Looking at this code, if you removed the comments, you would have nine flash commands one after the other, each with a series of values both for duration and gap. We found one way to simplify this code using functions called flashS and flashO, but another way to simplify the code would be to use two arrays: one for the duration and one for the gap. We could then go through each position of these arrays in turn, calling flash with the values. That way, we could change the Morse Code message to anything we liked, just by changing the contents of the arrays.

This is how you define an array of ints:

int durations[] = {200, 200, 200, 600, 600, 600, 200, 200, 200};

Notice that the variable name now has [] after it to indicate that it is an array rather than a single value. The values separated by commas inside { and } are the values to be put into the array. In this case, that is each of the durations used in loop.

We could do the same for the gap parameters of the calls to flash like this:

int gaps[] = {200, 200, 600, 200, 200, 600, 200, 200, 600};

It’s almost like there are two tapes with the same numbers on them that are then going to be fed through a machine that will use one number for the flash duration and the other for the gap before the next position on the tape.

Loops

Now that we have the two arrays, we need a way to step over each of those values in turn and call flash using them.

This type of thing is called ‘looping’ or ‘iteration’ and there is a useful language command in C for doing this called for.

Here is the modified program that uses for to loop over each element of the arrays and flash them. If you want to try out the completed program its in ch_03_SOS_Array.

int durations[] = {200, 200, 200, 600, 600, 600, 200, 200, 200};

int gaps[] = {200, 200, 600, 200, 200, 600, 200, 200, 600};

void setup() {

RGB.control(true);

}

void loop() {

for (int i = 0; i < 9; i++) {

flash(durations[i], gaps[i]);

}

delay(2000); // delay before repeat

}

void flash(int duration, int gap) {

RGB.color(255, 255, 255);

delay(duration);

RGB.color(0, 0, 0);

delay(gap);

}

The syntax of the for command highlighted above is confusing. It looks a bit like a function call, but it isn’t because it has parts separated by semicolons - surely these should be commas?

If you are new to programming, you are probably best off to just use the for loop for counting, copy the line starting with for and change 9 to whatever number you want i to count up to. Its not you; the syntax really is a bit screwy.

What is actually going on is that the first thing inside the parentheses of the for command defines a variable. In this case the variable is called i (for index) and this variable is initialized to 0 and will be used to keep track of our position in the arrays.

Then there is a semicolon and the expression i < 9. This is the condition for staying in the loop. In other words, the program will not escape from for and go on to do the last delay command while i is less than 9. This means that our program will hang unless we do something to change the value of i. That is where the last part of the stuff inside the () of the for command come into effect. The expression i++ means add 1 to the value of i.

So, each time around the for loop, flash will be called with the i th value of durations (thats what [i] means) and the i th value of gaps. The variable i will then have 1 aded to it and then for will call flash again but this time i will have changed from 0 to 1. This will continue until i gets to 9 and then because i is now greater than 8 the for loop is finished and the program will move on to the last line of the loop function and delay for two seconds.

As we mentioned earlier, if we change what is in the arrays, we can change the message completely. To try this, load up the example ch_03_flash_photon. Note that the maximum value of i in the for loop has been changed from 9 to 16 because the arrays have got bigger.

You may have noticed that i starts at 0 rather than 1. In C, the first element of an array is the zeroth element rather than the first element.

Strings

The Morse Code example is gradually evolving away from something that very specifically can only flash SOS into something that will eventually be able to flash any message that we tell it to.

To do this, we need a way for the program to represent text and for this we will introduce a new type called String. Here is how you define a String variable.

String message = "My Photon speaks Morse";

The value given to the string is enclosed in double quotes. If you are used to languages like Python that will allow you to use double or single quotes, then beware because only double quotes will do for C. C does use single quotes but these are reserved for single characters of type char. You will meet the char type a little later on.

There are various things that you can do with strings. For a start, you can find out how many characters they contain like this:

String message = "My Photon speaks Morse";

int len = message.length();

The function length is a special kind of function called a method. The difference between a method and a function is that a method is owned by a type, so here strings have a method called length that you can call using the dot notation after the string variable name. In this case, the lengthmethod returns a value (the number of characters in the string) that can then be assigned to an int variable.

As we mentioned earlier, C has a type specifically for single characters. Since a string is made up of a sequence of characters, its a bit like an array. You can access any of the strings individual characters using the method charAt(). The following example will assign the value “P" to the variable letter.

String message = "My Photon speaks Morse";

char letter = message.charAt(3);

Just like arrays, the index positions start at 0 rather than 1.

There are lots of other things that you can do with strings, we will encounter these as we finish the Morse Code Flasher project.

Ifs

The C if command is one that you will find in pretty much any program of any size. It allows the program to make decisions as to what to do based on some condition. It works much the same way as the English word if in a sentence. So, the English statement “if the character is a space, delay for 7 dots worth of time" (the gap between words in Morse Code is 7 times the length of a dot) would be written in code as:

if (letter == ' ') {

delay(dot * 7);

}

Notice how, when comparing letter to a space character, the two equals signs are used. This is to distinguish it from the single equals sign used to give a variable a value. A common source of programs not doing what was expected is that an = was used instead of an ==.

You can use == to test if two things are equal, or != to test that they are not equal. You can also use < (less than), <= (less than or equal to), > (greater than) or >= (greater than or equal to).

It is also possible to combine more than one condition using && (and) and || (or). For example the block of code inside this if statement will only be run if the value of letter is between ‘A’ and ‘Z’. You can use these comparisons on ints, floats and chars, but not Strings.

if (letter >= 'a' && letter <= 'z') {

// its an uppercase letter do something!

}

The else command works with if. The usage is the same as in English. For example in English you could write: “if the temperature is less than 70 turn on the heating else turn it off.”

In C, this might look like this:

if (temperature < 70.0) {

heatingOn();

else {

heatingOff();

}

I have assumed that two C functions called heatingOn and heatingOff exist to actually control the heating.

Project 3. Morse Code Flasher

In this project, you will put together everything you have learned about programming the Photon/Core. This project will flash any plain text held in a string as Morse Code.

In Project 4 you will use this same code with an external LED and in Project 8 flash Morse Code messages using a web interface.

Software

You can find the code for this project in the example library as p_03_Morse_Flasher. I suggest you open this file up in the Web IDE while you are looking at the code.

The first line of code specifies the message that is to be flashed:

String message = "My Photon speaks Morse";

You can change this message to anything you like.

Following this are the variables dot and dash that set the timings for the flashes. Then we have an array of strings that defines all the letters in Morse code:

int dot = 200;

int dash = dot * 3;

String letters[] = {

".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", // A-I

".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", // J-R

"...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.." // S-Z

};

Each of the letters A to Z is represented by one element of the array. The first element of the array is the string “.-” for A, the second “-...” for B etc. This array will be used to look up the series of dots and dashes that must be flashed in order to flash a particular letter as Morse Code.

The setup function just takes control of the RGB LED and the loop function now just contains the function call to flashMessage.

void setup() {

RGB.control(true);

}

void loop() {

flashMessage(message);

delay(5000); // delay before repeat

}

This type of programming is called “programming by intention." You know what you intend to do in the loop function: you want to flash the message and then delay for a while before flashing the whole message again. You can worry about how the flashMessage function will actually do its job later.

In fact, implementing flashMessage is the next step. Logically what you need to do, to be able to flash a whole message is to flash each letter of that message in turn.

void flashMessage(String message) {

for (int i = 0; i < message.length(); i++) {

char letter = message.charAt(i);

flashLetter(letter);

}

}

So, all flashMessage needs to do is to step over each letter in turn and call a function flashLetter on that letter. Once again, we are deferring the actual LED flashing work to another function that we have not written yet called flashLetter. See how nicely the problem is breaking down for us?

void flashLetter(char letter)

{

if (letter >= 'a' && letter <= 'z') {

flashDotsAndDashes(letters[letter - 'a']);

}

else if (letter >= 'A' && letter <= 'Z') {

flashDotsAndDashes(letters[letter - 'A']);

}

else if (letter == ' ') {

delay(dot * 7); // gap between words

}

}

The flashLetter function is a little more complicated. First we need to use if commands to decide if the letter is an uppercase letter or a lowercase letter, or a space character. If its a lowercase letter, then we find the string containing the dots and dashes for that letter using the letters array and supplying the character code minus the code for ‘a’ to get the right sequence of dots and dashes from the letters array.

If the letter is uppercase, then you need to subtract the character code for “A” rather than “a.”

Finally if the letter is the space character, that indicates that it’s the end of a word and the Morse code standard is to leave a gap of seven dots worth of time between each word.

Yet again, we are deferring the job of making the flashes to a function called flashDotAndDashes.

void flashDotsAndDashes(String dotsAndDashes) {

for (int i = 0; i < dotsAndDashes.length(); i++) {

char dotOrDash = dotsAndDashes.charAt(i);

if (dotOrDash == '.') {

flash(dot);

}

else {

flash(dash);

}

delay(dot); // gap between dots and dashes of a letter

}

delay(dash - dot); // gap between letters of a word

}

The parameter passed to flashDotAndDashes is a String. This string will be made up of the dots and dashes for a particular letter. For example -... for B. So to flash out those dots and dashes, you need to step over each character in that string, flashing the dot or dash.

After you have flashed each dot or dash, you need one dots worth of delay before you start on the next dot or dash and when you have completed the whole sequence you need another delay of duration a dash. However, you will already have had a delay of one dot after the last dot or dash was flashed, so the delay is for the duration of a dash minus a dot.

And still we are not actually controlling the LED. This happens in the flash function, which just takes the duration of the flash as a parameter. It is this function that actually turns the LED on and off.

void flash(int duration) {

RGB.color(255, 255, 255);

delay(duration);

RGB.color(0, 0, 0);

}

That is all there is to this project. Try changing the message and also the speed of the Morse Code by altering the value of the dot variable.

Summary

This chapter has only really touched on programming the Photon/Core. Enough to get you started. As the book progresses you will learn more about programming the Photon.

In the next chapter, you will learn how to connect hardware to the Photon/Core using solderless breadboard.