Intro to Computer Engineering

Studio 4 - Hex to Binary LEDs

========

Introduction

Click here to access the Canvas page with the repository for this studio.

========

Objectives

By the end of studio, you should know:

========

Today’s studio

Today you will begin the process of establishing communication between your Arduino and a Java program running on your computer. To do this, you will implement the Java SerialComm class that will provide methods that allow you to both send and receive data over the Serial Port in a Java program.

You will begin by reading a Nibble (also spelled “Nybble”), which is one hexadecimal digit, from your keyboard in Java on your computer. Then, you will implement the functions of the SerialComm class and use it to send the Nibble over the Serial Port to your Arduino, and displaying it on your Arduino using 4 LEDs to represent the bits of the nibble. So, by the end of the studio you should be able to type 0-9 and a-f into a console on your Java program and see the binary representation show up on the LEDs attached to your Arduino.

========

Background

Recap on Hexadecimal

DEC HEX BIN
0 0 0000
9 9 1001
10 a 1010
11 b 1011
12 c 1100
13 d 1101
14 e 1110
15 f 1111

Why Hexadecimal? — Humanizing Binary

Most common data types require many binary digits. For example, a Java int is 32-bits wide and uses Two’s Complement. In binary, a -12 would look like 11111111111111111111111111110100, which isn’t very easy to read. (Can you quickly tell if it even has 32 bits?) Since each digit of hexadecimal corresponds to exactly 4 bits of binary, we can break this down into just 8 hex digits: 0xFFFFFFF4, which is much easier to work with. Since it’s easier to read and can still be used to quickly find the value of a particular bit, hexadecimal is often used rather than binary.

Notice that the conversion from hexadecimal to binary (or from binary to hexadecimal) is like a simple substitution cipher. Given a number like: 11111111111111111111111111110100 you:

  1. Break it into groups of 4 bits: 1111 1111 1111 1111 1111 1111 1111 0100
  2. Look up each group of 4 bits in the table and substitute it with the corresponding hexadecimal digit: F F F F F F F 4

If you wanted to convert hex to binary you just use the table in reverse. You’d look up each hexadecimal digit and replace it with the corresponding four binary digits.

========

The Arduino End

An empty Arduino sketch has been created in CSE132-studio4 > HexLEDs > HexLEDs.ino. Use it for your Arduino work.

Start by assuming the User’s Input will be sent to the Arduino via the serial port. We can use the Serial Monitor window to emulate the values that will eventually be coming from a Java program on the computer. Notice the text field that can be used for input, like the ‘a’ that is entered here:

Serial Monitor with Echoed Input

In this example the Arduino program has “echoed” the value back to the Serial Monitor.

Reading from Serial Port

We will be using Serial.available() and Serial.read() to read from the serial port.

To Echo Data like in the above example:

Update the sketch using the above to merely “echo” whatever characters you type in the input prompt of the Serial Monitor. Test it to be sure you are reading data correctly.

Note: For all Serial Port Matters this reference is your friend.

Displaying on LEDs

Once you can successfully echo back the input using the serial monitor, build a circuit that includes four LEDs. Suggested components:

These LEDs will be used to represent the 4 binary bits of a hexadecimal digit that your sketch will receive over the Serial Port, first from the Serial Monitor and later from your Java program.

Update your sketch to use an int variable to store the result from Serial.read() and print the value. Test your code. What does it print when you enter a ‘0’?

Note that the input will be an ASCII character. The value stored in your variable is the encoding of the character you typed in.

You’ll have to use some code to convert or interpret the meaning of the ASCII value correctly.

ASCII is also like a simple substitution cipher, where each symbol is replaced by a numeric value. This ASCII table shows symbols in the center column and the decimal value that is substituted for it in the left column. For example, the character ‘0’ is represented by the decimal value of 48 (or 0x30 if we use hex). When the computer sends a ‘0’ (a character) it’s really sending the equivalent of 48 (decimal).

The order and values assigned in the ASCII table weren’t chosen at random. There are several things that are particularly convenient about the orders and values of symbols in the table:

Complete code that will convert the ASCII value stored in your int variable into the appropriate decimal value (that is, an ‘a’ should become the decimal value 10, a ‘7’ should be the decimal value of 7, etc.). (For a challenge, try to accomplish this in four or fewer simple lines of code).

Modify your code so that it turns on the LEDs to represent the bit pattern for the corresponding hex digit you sent to the Arduino. Turn all lights on if ‘f’ is sent, all lights off if ‘0’ is sent, etc.

========

SerialComm Class Overview

The primary objective of this studio is to implement the SerialComm Java class that enables you to send data between your Arduino and a Java program running on your computer. We will use this communication as the basis of our next several modules. WE HAVE CREATED A SerialComm Guide WHICH WE STRONGLY ENCOURAGE YOU TO REFERENCE REGULARLY AS YOU DO THIS STUDIO, BUT IMPLEMENTATION DETAILS ARE IN THIS STUDIO!

The SerialComm class serves as a wrapper around an already-established SerialPort class (more on that later) that is already able to send and receive data via the Serial Port (cord) running between your computer to your Arduino. The SerialComm class you implement will have the additional feature of allowing you to view the bytes sent (both from Java to Arduino and from Arduino to Java) in real time via the debug functionality you will implement.

========

Writing to the Serial Port

Now that the Arduino is able to receive input and lights up the bits properly, we are ready to send data to it from Java.v

CSE132-studio4 > communication contains a partially complete Java class named SerialComm. It has some TODO items that need to be completed. Remember to reference the SerialComm guide as you do.

This class will send data via the serial port (to your Arduino). In order to do that, you will need to use the SerialPort class—that is available as a library, the JavaDoc is available here—and connect to the correct port.

The SerialPort methods might throw an Exception. For example, the port you provide could not exist, or your drivers could be set improperly. When code you write calls other code that might do this, you have two options: pass the exception up for someone else to deal with (by specifying that your function throws an exception sometimes, or handle it yourself using a try-catch block. Eclipse will help you write one.

Note the SerialPort constructor code sets the baud rate (feel free to leave it at the current 9600 baud), the rate at which your serial port expects data from your Arduino.

Add a new writeByte() method to SerialComm. It can simply use the writeByte() method of SerialPort.

Since we want our wrapper SerialComm class to also print out the data being sent to the console, your writeByte() should do more than just send the byte of data to the Arduino. When debug is true, you will also print the bye that is being sent to the console.

You need to convert to hex before you print: for every byte that goes to the Arduino, the debugging output should be 6 characters: the string “<0x”, 2 characters that represent the data byte in hexadecimal, and the character ‘>’ (e.g., if the byte in the data stream is 5f, the string sent to the console should be “<0x5f>” (or “<0x5F>” if you prefer). You can use String.format("%02x", byte value) to format a byte as a two-character String in hexadecimal.

Get User Input

Open the HexTX.java (in the communication package). In this file you will read in a hexadecimal character (a “nibble”) from the user and send it to the Arduino.

Notice a TODO comment inside the main method about gathering user input. Write the code for this portion of the studio there.

To input our hexadecimal character, we will be using the Console panel in Eclipse.

You might have noticed the console is where all of your System.out.print()s are sent:

Console: Hello World

Input can also be entered at the Console:

Never trust User Input / Sanitizing Input

Now that your program can receive Input, we must be cautious before sending to the Arduino.

The LEDs can represent 0-9 , a-f

Often user input must be “validated” or “sanitized” to remove undesirable values. Both validation and sanitization are about avoiding undesirable values in the input. The term validation usually refers to ensuring input is in a valid format and range and sanitization usually means that no “covert” input is included. Unsanitized input is a prime culprit in many forms of attacks on internet sites (See: Prevent Web Attacks Using Input Sanitization, or Keeping Web Users Safe By Sanitizing Input Data, or Bobby Tables (Bobby Tables Explained)).

Before writing code to validate input you first have to identify what constitutes valid vs. invalid input and then you have to decide how to handle the problem.

For example, we know that with just 4 LEDs the Arduino can only display 1 Nibble (1 hex digit) at a time. If the input is longer than 1 character it’s invalid, but do you…

Whenever receiving user input try to predict what will happen if they don’t follow your guidelines and plan appropriate responses. Planning responses to invalid input can avoid many run-time errors.

Decide how you will accept input, prompt and store a proper hex digit (‘0’-‘f’) into a char variable.

Now it is almost time to send our nibble to the Arduino! Uncomment the SerialComm object and be sure to set debug to true os you can ensure the data being sent is what you expect.

Next, send valid input from the console to the Arduino by calling the writeByte() method, and then prompt the user for additional input (i.e., put the prompt to the user and the sending of the input to the Arduino in a loop). Be careful how you take a char type and send only a byte. They are not the same thing in Java.

The Arduino sketch you wrote earlier to turn on the lights should be able to receive bytes to manipulate the LEDs from the Java program just like it did the Serial Monitor.

========

Warnings

We are using a recently updated version of the serial port library, and it has an issue where it gives a warning about missing logs (when you run your Java program). You may ignore this warning.

========

PortInUseException

Make sure you’ve closed all your Java programs with the Terminate button in the console. Make sure you’ve closed Serial Monitor. Make sure you’ve run the Terminal commands in the list above.

PortNotFoundException

See what SerialPort is connecting to— it should match the port name in the Arduino IDE (/dev/cu.usbmodem0000 or something similar on Macs, COM1, COM2, or something similar on PCs).

Startup debugging

You can only have one open connection to your Arduino at any given time, be it uploading new code, Serial Monitor, or a custom Java app.

So make sure to close all your Java programs after running them.

  1. Click the red square on the side of the Java Console to stop the program.
  2. Click the x next to it to clear that program’s output and show any other running programs (if there are)
  3. Repeat for all open programs.

Also close Serial Monitor when you are not using it.

========

Switching things up

Most of time time we won’t just want to send data from Java to the Arduino. SerialComm will need to be able to accept data from the Arduino program, too. We will not use them in this studio, but you will now implement SerialComm’s readByte() and available() methods that you will need for this module’s assignment.

Receiving data

We will once again be using the SerialPort class methods, this time to receive data. You may want to refer to the JavaDoc for the jSSC library.

Author two new methods in your SerialComm class: available() and readByte().

The available() method should return a boolean that is true if there is at least one byte available to be read from the serial port. The getInputBufferBytesCount() method of SerialPort is helpful here.

The readByte() method should read a single byte from the serial port and return a byte that contains the value read. The readBytes(int byteCount) method of SerialPort is helpful here, but watch out for its return type (an array of bytes, byte[], rather than a single byte). When debug is true, you will need to print the byte you just read. Don’t forget to convert to hex before you print: for every byte that comes from the Arduino, the debugging output should be 6 characters: the string “[0x”, 2 characters that represent the data byte in hexadecimal, and the character ‘]’ (e.g., if the byte in the data stream is 5f, the string sent to the console should be “[0x5f]” (or “[0x5F]” if you prefer). You can use String.format("%02x", byte value) to format a byte as a two-character String in hexadecimal.

A debugging version

Recall from above that there was a debug option that could be used to examine outgoing bytes from Java to the Arduino. We wish to replicate this behavior for bytes going from the Arduino to Java.

Reimplement the readByte() method you made earlier so that it conditionally (based upon the value of the debug instance variable) prints incoming bytes to the console in hex. When debug is true, you will need to convert to hex before you print: for every byte that comes from the Arduino, the debugging output should be 6 characters: the string “[0x”, 2 characters that represent the data byte in hexadecimal, and the character ‘]’ (e.g., if the byte in the data stream is 5f, the string sent to the console should be “[0x5f]” (or “[0x5F]” if you prefer). You can use String.format("%02x", byte value) to format a byte as a two-character String in hexadecimal.

It should continue to return the value of the byte that was input from the serial port.

You should now be able to view the data in hex as it goes through the readByte() method and be able to view the “true” ASCII value in the Java console.

PLEASE REFER TO THE SerialComm GUIDE REGULARLY!

========

Finishing up

Check out and get out.

  1. Make sure to commit your workspace

    In Eclipse’s package explorer, any files you have modified since your last commit are prefixed with a >.

    Right-click the outer-most folder (you want to commit everything within), and choose Team>Commit.... Write a helpful message and press OK.

    You can verify that your changes went to the server by opening the repository URL in any web browser.

  2. Get checked out by a TA.

Repository structure for this lab:

========

Key Concepts

This is a mental checklist for you to see what the Studio is designed to teach you.