Link Search Menu Expand Document

Networking and communication

Last day for on-time checkoff: Tuesday, 11/19 (three weeks)

Prelab due 10/28/24 at 11:00 am

Writeup due 11/18/24 at 11:00 am

About

In this lab, you will explore different ways microcontrollers can interact with each other, using both wired and wireless communication. You will write your own software UART to build understanding of how serial communication works. You will also use the BLE (Bluetooth Low Energy) capabilities of the Arduino Uno R4 to form a distributed system with other devices in the class. By the end of this lab, you should be comfortable with using your Arduinos to communicate with other devices.

Lab 7 Rubric

Resources

Starter code

Materials

Included in your kits:

  • 2x Arduino Uno R4 WiFi and USB cable
  • Jumpers/wires

Provided:

  • None necessary

Steps

  1. Download or clone the starter code. Install the following libraries through the Arduino IDE: Arduino BLE and Crypto. Step 2 does not require these libraries, so you can start working on it while the libraries install.

  2. Your Arduino has built-in UART serial communication that you can use to send data between two Arduinos. To use this functionality, we would use the onboard TX and RX (D1 and D0) pins and use the same syntax as Serial communication with the computer, replacing Serial with Serial1 (e.g. Serial1.begin()). You will make use of this feature in lab 8. However, for this lab, we will DIY a software UART that works on any* pins (*for the receiver, the pins have to support digital interrupts).

    1. Wire up the following circuit. Be sure to connect the GND pins of both Arduinos to each other!

      L07D01

    2. For this step, work with the lab7_uart sketch from the starter code. Take a few minutes to review the code.

      If the line #define SENDER is present in lab7_uart.ino, the device will function as a sender. It is going to send a pre-defined image of a monster (an array of three uint32_ts – a format the onboard LED matrix understands) via the outPin. We’ve taken care of the code that takes the monster array and splits it up into 18 bytes of data (3 4-byte integers + a array index + end byte for each integer), loads it into a circular buffer, and then calls uartSend while it removes every item from the buffer.

      serialization

      If the line #define SENDER is commented out, the device will function as a receiver. It uses an interrupt attached to the uartReceive function to detect the UART start bit (a change from HIGH to LOW in the input signal, receive a byte, and load it in a buffer. Once it receives 6 bytes (array index byte, 4 bytes to reconstruct the uint32_t, and the end byte), it uses the computation we’ve given you in the loop to make sure the 6 bytes have the expected format. It then updates the frame that it should display on the onboard LED matrix.

      Note that the use of #define SENDER is a bit of an unorthodox approach. It’s a consequence of the sender and receiver both using circular buffers, so we’re structuring the code this way so that you only have to edit the buffer file in one place. A better project structure would be to make the buffer code into a library (or, outside of the Arduino framework, a file that gets compiled separately and linked) and to create separate sketches for the sender and the receiver.

    3. Complete the uartReceive and uartSend functions according to your prelab logic. Also complete the indicated functions in buffer.ino.

    4. You can connect both Arduinos to one computer, or use two different computers. If you are using the same computer, you can switch between Arduinos by changing the port under Tools -> Port. You will have to do this even if you have multiple IDE windows open. Notice also that the Serial monitor changes which Arduino it is receiving data from based on which port is selected – this sometimes even happens in both IDE windows. When you upload the code, make sure that one device gets code with #define SENDER present, and the other device gets code with it absent Once the code is running, you should observe that a monster appears on the receiver’s LED matrix. It’s OK (and expected) if the image flickers a bit – this is due to the LED matrix code depending on an interrupt, which gets pre-empted by the GPIO interrupt we have enabled for the UART. Once you have the monster, get checked off by a TA.

    5. Inject some bit-flip errors by replacing the line digitalWrite(outPin, HIGH) in uartSend with digitalWrite(outPin, HIGH_BITFLIP). Upload the sender code (no need to change the receiver), remembering to select the correct Arduino and to include the #define SENDER line, and press the receiver’s reset button. HIGH_BITFLIP is defined in lab7.h and depends on the signal read in by the unconnected A2 pin, which will be sensitive to electric interference. You can observe the effects by moving the sender Arduino around closer and farther away from sources of interference, such as your hand, the other Arduino, or your computer. Press the reset button on the receiver and observe whether you can see the effects of the uartReceive function rejecting messages with bit flips.

      Now amp up chaos by plugging in an unconnected wire into the A2 pin, which will make it more sensitive to interference. Continue to press the reset button and talk about your observations.

  3. Now let’s collect some more monsters! For this step, you will need your two Arduinos, but you should disconnect the circuit from step 2, so that the Arduinos are communicating wirelessly. As described in the prelab, you will implement a “home” device, which has access to encrypted monsters, and a “roam” device, which will send keys to the “home” device so that it can decrypt its monsters. We will work with the lab7_home and lab7_roam sketch folders.

    1. Decide on a 16-character password and special home device name, and update both .h files where indicated with the “TODO” annotation. We have given you the code that implements the following sequence diagram from the prelab in the homeInit, checkInbox, and roamInit functions (found in the respective _ble.ino files). Take some time to locate where each step in the sequence diagram is implemented in the code and to talk about the use of the BLE functions, which will help you in subsequent steps.

      L7 SD1

    2. The home device should decode each monster before displaying it by XORing the decoded monster with its key (this is basically how decryption/encryption algorithms work, but with more complicated/mathematically secure operators!). Find the “TODO” annotation in home_utils.ino and perform this computation. Upload the code onto the Arduinos. Open the Serial Monitor for the home device, and note the command-line interface that allows you to display monsters by inputting a number. Input 0 on the serial monitor and observe your first captured monster!

      A note on resetting the boards: the communication between the devices is set up such they use the sequence diagram above as an initialization step. To re-run and test code after you’ve made changes, it will be necessary to reset both devices so that they can perform the initialization. Sometimes, resetting (especially on the roam device) will prevent the BLE module from starting up again – see the pinned Ed post for details. The stencil code triggers a hard reset of the ESP module if this happens, which might cause the device to temporarily lose serial connection with your computer. If this happens, close just the serial monitor (not the whole IDE!), check the port via the Tools menu, re-open the serial monitor, and send any character to get out of the setup loop that waits for serial communication.

    3. Find the “TODO” annotations in home_ble.ino. Implement the steps of the following sequence diagram. Note that similar steps exist in the first sequence diagram, so you would have found example uses of almost all of the relevant BLE functions as you read through the code we gave you. To set the value of a characteristic, you can use writeValue, e.g. outboxKey.writeValue. You will also have to change the properties of the outboxKey characteristic to match your prelab.

      L7 SD2

      One way to test that the initialization worked is to wait for the home device to initialize and then use your phone to check for available bluetooth devices. You can also initialize both devices, and then upload the ArduinoBLE -> Central -> PeripheralExplorer example to the board that was running the roam code. This code will display the names of all of the devices it has found on the Serial monitor as well as their advertised characteristics. Once you have your home device initialized, get checked off by a TA!

    4. Implement the functionality of the local roam device in the function scanForMonsters in roam_ble.ino, according to the third sequence diagram. Notice that you don’t have to write any code for the home device for this step, since the functionality to check the inbox and store the monster is the same as in step 3a.

      L7 SD3

      BLE hints: again, most of the BLE functions you will need already have examples elsewhere in the starter code. Follow the sequence diagram and use the following notes:

      * You will need to make use of BLE.scanForUuid, BLE.scanForAddress (scroll down for documentation), and our provided helper function getBLEIntValue

      * To mark the monster as found and to only connect to never-before-seen monsters, use [peripheral].localName to get the name and the addMonster/hasMonster helper functions provided in roam_utils.ino

      * When you find a peripheral after scanning, you must call [peripheral].connect() and [peripheral].discoverAttributes() on it before using its services and characteristics (see the comment starting with “IMPORTANT” as an example). Remember to also disconnect from the peripheral once you’re done communicating with it.

      * To get the characteristic of a peripheral that you’ve connected to, use [peripheral].characteristic(). Notice that this characteristic can be passed to our helper function getBLEIntValue.

      The TAs will be running a device that has the key for a special TA monster. If your code is correct, you should be able to collect this monster almost immediately when you run the code. Once you collect this monster, get checked off by a TA.

    5. Wait for more groups to finish this step, so that you can collect more monsters!

  4. Even though ArduinoBLE doesn’t provide a means of “pairing” devices, the design of our sequence diagrams was meant to ensure that the roam devices could read keys from all other home devices, but the home devices would only accept data from their own roam devices. If you have time, discuss the security implications of this distributed system. You will be asked about these in the lab writeup.

    1. Why does the roam device hash every message with a password when communicating with the home device and why are the INBOX attributes write-only? What could go wrong in terms of security if we didn’t do one or both of these things? Think about how an adversarial actor might compromise the integrity of data on the home device in the worst case. For the write-only case, it might help to think outside of the box – for example, what if the home device were restarted?

    2. Think about (don’t implement) how you could change how your roam device interacts with remote home devices so that their availability is compromised. Would you be able to prevent other roam devices from accessing data on some home device?

      Similarly, how could you be adversarial in setting up the home device? Don’t just think about putting an incorrect key value in the OUTBOX. What else can the home device do to mess with the home devices?

  5. If you have time, explore the WiFi capabilities of the Uno. Especially if you will be using WiFi for your final project, get your device registered to the Brown network using these instructions. You can find the MAC address of your device by running the ScanNetworks example sketch under the WiFiS3 built-in examples (no need to install any libraries here; these examples come bundled when you installed the software for the R4 in lab 1). You do not need to be connected to any networks to run that example. Take a look at the other examples, which are documented here. Specifically, run the NTP client example and observe the Arduino connect to an NTP server to get the time.

    Note: if you are trying to connect to a website using SSL (like a website that requires https), you will likely need to fetch and upload the SSL root certificate for that website. You can easily do this using the “Upload SSL Root Certificates” tool under the Tools menu.

    Another note: BLE and WiFi use the same antenna, so you cannot have one Arduino use BLE and WiFi at the same time. We have not tested if it’s possible to disable WiFi and enable BLE and vice versa in the same program. If you want to use both WiFi and BLE in your project, one approach is to have two Arduinos, one using WiFi and one using BLE, with a physical (Serial/UART) connection.

  6. Zip up both sketch folders and turn the code into the Lab 7: Code Gradescope assignment.