Pico development serial - 2

Thursday, 24 September 2026

Introduction

In ‘Pico development serial - 1’ we were able to send and receive characters between the Raspberrry Pi and Pico, we can now progress to sending bytes. Which they were actually anyway, but they represented characters, and that is the point.

With reference to ‘ github.com/gbmhunter/CppLinuxSerial/blob/master/include/CppLinuxSerial/SerialPort.hpp ’. In our Pi program we were using the method ‘Write’, which is defined as ‘void Write(const std::string& data);’ to take a reference to a string, were we were sending it a single character ‘writeData += sendData[sendCharIdx]’. However there is a method called ‘WriteBinary’, being defined as ‘void WriteBinary(const std::vector<uint8_t>& data);’ where we can send one or more ‘uint8_t’ types using a reference to a ‘std::vector’1 of them. ‘uint8_t’2 is an unsigned eight bit integer, a ‘byte’ that has the value range of 0 to 255. Then with reference to ‘ github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_uart/include/hardware/uart.h#L466-L501 ’ we see that the Pico also deals with bytes as ‘uint8_t’s2.

Representation

As fundamentially computing machines only understand bytes as things they can process and compare, then it is us that programs them to represent our world. The character we have used represented by a value in a single byte is one example of this. Of course there is ‘UTF-8’3 that uses one to four bytes to allow representation of more characters beyond what ‘ASCII’4 can provide. This is great for when we wish to convey our languages, but what if we’re conveying just numbers for example? Then the number ‘100’ typed as digits, characters, becomes three bytes when we know that a single byte can represent it as a value.

What if then we wish to convey something more complex like a collection of different things? Just like we can have shopping baskets with different products. Those products have attributes, such as: quantity, expriry date, price and weight. All are different concepts that need to be efficiently represented by one or more bytes in order for us to use a computing machine as a tool to store and convey that data for our use. Now we’re no longer dealing with one or more bytes representing a given concept but a whole stream, collection, of bytes representing different things. A ‘structure’5 or even an ‘object’6 as an instance of a ‘class’7, with conveying, a ‘communication protocol’8 with ’network packets’9.

With the serial communication we have been doing, this is an example of a ‘communication protocol’8 and conceptually we have a ’network’10 even though we’ve connected to devices together. That is the aim here, to move beyond using characters in our langauge to then understand and have the ability to convey data (bytes) that represent different concepts as one or more collections between two devices. Then do something with it. Then we will be communicating using the least amount of bytes as possible which is helpful when it comes to the limitations embedded11 computing world.

One idea I had was to transmit the current time from the Pi, which it knows when connected to the internet, to the Pico, which only knows how long it has been active. I came up with the code to get the time and put that in the vector of ‘uint8_t’s2 that ‘void WriteBinary(const std::vector<uint8_t>& data);’ requires:

 1#include <ctime>
 2#include <iostream>
 3#include <vector>
 4
 5using namespace std;
 6
 7int main() {
 8    cout << "Current time is:" << endl;
 9
10    time_t timestamp;
11    time(&timestamp);
12
13    cout << ctime(&timestamp);
14    cout << timestamp << " : " << sizeof(timestamp) << endl;
15    uint64_t utime = timestamp;
16    int tssize = sizeof(utime);
17    cout << utime << " : " << tssize << endl;
18
19    vector<uint8_t> utimebytes(reinterpret_cast<uint8_t*>(&utime), reinterpret_cast<uint8_t*>(&utime) + tssize);
20
21    for (int i = 0; i < ts; i++) {
22        cout << hex << (int) utimebytes.at(i) << endl;
23    }
24}

This then lead me down a rabbit hole! So much so that I took things much further and then wrote an article about it ‘Endianness’.

https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_uart/include/hardware/uart.h#L466-L501

https://www.geeksforgeeks.org/cpp/how-to-get-time-in-milliseconds-in-cpp/

Now that there is a foundation of knowledge upon which to build upon, we can do so!

We are not ‘standalone’. In order to function and survive in our world we need to communicate. The same is true of computing solutions. An isolated device doing something does not reach its full potential unless the results of its actions can be retrieved. Likewise, it needs inputs to process, or rather external direction of what to do at times.

With the generic you can be sure that a solution to a problem has already been done and documented. Therefore the key here is not to re-iterate what has already been done but rather demonstrate understanding through my own examples and provide that perspective so that you may visualise from another point of view.

We have an objective here and that is to have a means by which two devices may communicate. One of the most basic is ‘Serial’12, specifically here with ‘Universal asynchronous receiver-transmitter’13. The idea I have in mind is this:

Idea

Where a ‘Pi’14 connects to a ‘Pico’15 over serial and a ‘Debug probe’16 is used to inspect what we receive and send back to the ‘Pi’. As a Pi and a Pico are two different devices then rationally they can perform different tasks, complimenting each other by communicating their output.

Disclaimers

If replicating what I’ve done then be sure of what you’re doing, as information presented in this article is written according to my own understanding, there could be inaccuracies, so please do undertake your own research. All sources of information that are not my own have been cited / referenced. All screen shots taken on the ‘Pi 5’14. Images / video are my own.

A beginning

Like the Pico we need to have a means of building programs. Taking into account what I’ve already done in the last two posts (’Raspberry Pico development environment’ and ‘Raspberry Pico development structure’) then using ‘CMake’17 is a logical thing to do. We will need a compiler (and linker too) as the one for the Pico is an embedded one ‘gcc-arm-none-eabi’18. Typing ‘whereis gcc’ that gives the result of ‘gcc: /usr/bin/gcc /usr/lib/gcc /usr/libexec/gcc /usr/share/gcc’, then following the chain with ‘ls -al’ we have ‘lrwxrwxrwx 1 root root 6 Oct 10 2024 /usr/bin/gcc -> gcc-14’ leading to ‘lrwxrwxrwx 1 root root 24 Mar 15 2025 /usr/bin/gcc-14 -> aarch64-linux-gnu-gcc-14’ finally leading to ‘-rwxr-xr-x 1 root root 1121152 Mar 15 2025 /usr/bin/aarch64-linux-gnu-gcc-14’. This tells us several things:

  1. The compliler (and likely linker) are already installed as their date predates when the Pi’s OS was installed.
  2. The version of the compiler, 14, which we can further deduce with ‘gcc --version’, giving:
1gcc (Debian 14.2.0-19) 14.2.0
2Copyright (C) 2024 Free Software Foundation, Inc.
3This is free software; see the source for copying conditions.  There is NO
4warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Whereby following ‘ gcc.gnu.org/gcc-14 ’, ‘ gcc.gnu.org/onlinedocs/14.2.0/ ’ and ‘ gcc.gnu.org/onlinedocs/gcc-14.2.0/libstdc++/manual/ ’ we can understand that we can stick with version 14 of the C++ standard19 that we’ve been using with the Pico.

With that in mind we can create a basic ‘Hello’ program:

pihello.cpp

 1/**
 2 * @file pihello.cpp
 3 * @copyright (c) 2026 G J Barnard.
 4 *
 5 * @par License
 6 * SPDX-License-Identifier: BSD-3-Clause
 7 *
 8 * @version V1.0.0
 9 */
10#include <iostream>
11using namespace std;
12
13int main () {
14    cout << "Hello" << endl;
15
16    return 0;
17}

Which outputs the word ‘Hello’ to the console. It is built using:

CMakeLists.txt

 1cmake_minimum_required(VERSION 3.31)
 2
 3set(CMAKE_CXX_STANDARD 14)
 4
 5project(pi_hello
 6    LANGUAGES CXX
 7    VERSION 1.0.0
 8)
 9
10add_executable(${PROJECT_NAME}
11    ${CMAKE_CURRENT_LIST_DIR}/src/pihello.cpp
12)

with a familiar structure:

1.
2├── build
3├── CMakeLists.txt
4└── src
5    └── pihello.cpp

To build, navigate to the ‘build’ folder and type ‘cmake ..’, followed by ‘make’ which will give us (hopefully) the executable ‘pi_hello’, ‘-rwxrwxr-x 1 gareth gareth 71040 Jun 18 11:10 pi_hello’, which we can run with ‘./pi_hello’ giving ‘Hello’.

Pi and Pico serial configuration

Now that we know we can create a program on the Pi, we have everything in place, or do we? We’re connecting two devices together with wires and going to send and receive bytes across them. We need to do some research and look at the specifications to understand how to undertake the required configuration we need. Looking at ‘ Configuration - Configure UARTs ’ and ‘ hardware_uart ’, we find that both the Pi and the Pico use the same ARM PL014 UART. That both operate at 3.3 volts (Implied by the GPIO pins in ‘Chapter 1. About Raspberry Pi Pico’ of the ‘Raspberry Pi Pico Datasheet: An RP2040-based microcontroller board’ as linked from ‘ Pico microcontroller boards ’ for the Pico and ‘Configuration - Configure UARTs’, along with ‘ GPIO and the 40-pin header ’ for the Pi.

Reseaching further, I found: ‘ Protecting IO Lines From ESD ’ and ‘ RPi Serial Connection - H/W considerations ’ which have recommendations on protecting the receive and transmit lines with resistors. I thought to be on the safe side I’d go with 1K Ohm as I actually had some.

As each Pi version has different UART configurations, then we need to consider how the UART is accessed. However, in all cases we need to enable the UART and stop the ‘console’ access interferring with our data. There are lots of places where there are instructions on how to do this, but perhaps the best source is the original, so following ‘ Configuration - Enable or disable serial port ’, we need to say ‘Yes’ to ‘Serial Port’ and ‘No’ to ‘Serial Console’.

Looking at ‘ Configuration - Configure UARTs ’ and ‘ RPi Serial Connection ’, and I was told by a friend / remember from University that everything in Linux is a ‘file’, we need to work out what serial device to use. In the case of the Pi514, I discovered that after enabling the UART and disabling the console that the UART is on ‘/dev/ttyAMA0’ with ‘/dev/ttyAMA10’ remaining for debugging, even though ‘/dev/serial0’ points to it. Thus best to use directly.

For the Pico there is no configuration to do yet as that is done in code.

Connecting things together

Looking at ‘ GPIO and the 40-pin header ’ and ‘ Board layouts ’ allows us to work out the actual pins to connect. As I’m already using UART0 on the Pico for the Debug probe, then for this I’ll be using the second UART1. This results in a connection diagram of:

Connections

Where:

  • Pi UART0 Tx pin 8, GPIO 14 connects to Pico UART1 Rx pin 12, GP 9 via a 1K Ohm resistor.
  • Pi UART0 Rx pin 9, GPIO 15 connects to Pico UART1 Tx pin 11, GP 8 via a 1K Ohm resistor.
  • Pi Ground pin 14 to Pico pin 13.

Note: USB and SWD connections not shown.

Mirror demonstration

Part one

I wanted something simple, something that would just prove that the hardware connections work. As VSCode20 has a ‘Serial monitor’ that allows you to both see what is received and send at the same time, then that meant no need for Pi code, yet, leaving just the Pico. Looking at ‘ uart_advanced.c ’ as an example and building upon the programs in ‘Raspberry Pico development structure’, I’ve written ‘mirror.cpp’:

 1/*
 2 * Copyright (c) 2026 G J Barnard.
 3 *
 4 * SPDX-License-Identifier: BSD-3-Clause
 5 */
 6
 7#include <stdint.h>
 8#include "pico/stdlib.h"
 9#include "pico/printf.h"
10#include "pico/binary_info.h"
11#include "hardware/uart.h"
12
13class Mirror {
14    public:
15        /**
16        * Initialise.
17        */
18        void init() {
19            bi_decl(bi_program_name("Mirror"));
20            bi_decl(bi_program_description("Demonstrate UART serial between a Pi and a Pico."));
21            bi_decl(bi_program_version_string("V1.0.0"));
22
23            stdio_uart_init();
24            stdio_usb_init();
25
26            uart_init(UART_ID, BAUD_RATE);
27            uart_set_hw_flow (UART_ID, false, false);
28            uart_set_format (UART_ID, UART_DATA_BITS, UART_STOP_BITS, UART_PARITY);
29            uart_set_irqs_enabled (UART_ID, false, false);
30            uart_set_fifo_enabled (UART_ID, true);
31
32            gpio_set_function(UART_TX_PIN, UART_FUNCSEL_NUM(UART_ID, UART_TX_PIN));
33            gpio_set_function(UART_RX_PIN, UART_FUNCSEL_NUM(UART_ID, UART_RX_PIN));
34        }
35
36        /**
37         * Run.
38         */
39        void run() {
40            sleep_ms(PAUSE * 2);
41
42            printf("run()\n");
43
44            while (true) {
45                if (uart_is_readable(UART_ID)) {
46                    char theChar = uart_getc(UART_ID);
47
48                    printf("Debug, got: %c\n", theChar);
49                    uart_puts(UART_ID, "Got: ");
50                    uart_putc(UART_ID, theChar);
51                    uart_putc(UART_ID, '\n');
52                } else {
53                    uart_puts(UART_ID, "Ready\n");
54                    sleep_ms(PAUSE);
55                }
56            }
57        }
58
59    private:
60        // Constants.
61        uart_inst_t * UART_ID = uart_get_instance (1);
62        uint BAUD_RATE = 9600;
63        uint UART_DATA_BITS = 8;
64        uint UART_STOP_BITS = 1;
65        const uart_parity_t UART_PARITY = UART_PARITY_NONE;
66        const uint UART_TX_PIN = 8;
67        const uint UART_RX_PIN = 9;
68
69        const uint16_t PAUSE = 5000;
70};
71
72/**
73 * Main.
74 */
75int main() {
76    Mirror mirror; // Instantiate an instance of the 'Mirror' class.
77    mirror.init();
78    mirror.run();
79
80    return 1;
81}

Referring to ‘ hardware_uart ’ and ‘ UART_FUNCSEL_NUM ’ to help understand the parameters of the functions / macros used.

The program initialises the UART*, then listens to see if anything has been sent. If it has then that is echoed back with an ‘Got: ’ prefix. If nothing has been received then ‘Ready’ is sent and the program pauses.

*I’ve chosen a slow baud rate of 9600 as I wondered if the 1K Ohm resistors would make an impact on the ability for a higher speed to work at.

The ‘CMakeLists.txt’ file is:

 1set(PICO_BOARD pico CACHE STRING "Board type")
 2
 3cmake_minimum_required(VERSION 3.31)
 4
 5# Use below when using the Pico VS Code Extension.  Seems to copy 'pico_sdk_import.cmake' when importing the folder.
 6include(pico_sdk_import.cmake)
 7# Uncomment below for 'Manual' and comment out above:
 8#include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
 9
10set(CMAKE_C_STANDARD 17)
11set(CMAKE_CXX_STANDARD 14)
12set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
13
14pico_sdk_init()
15
16project(mirror
17    LANGUAGES C CXX ASM
18    VERSION 1.0.0
19)
20
21add_executable(${PROJECT_NAME}
22    ${CMAKE_CURRENT_LIST_DIR}/src/mirror.cpp
23)
24
25pico_enable_stdio_usb(${PROJECT_NAME} 1)
26pico_enable_stdio_uart(${PROJECT_NAME} 1)
27
28pico_add_uf2_output(${PROJECT_NAME})
29# Have if debugging.
30pico_add_dis_output(${PROJECT_NAME})
31
32target_link_libraries(${PROJECT_NAME} pico_stdlib)

When run, this results in:

Mirror

Where I enter the word ‘Testing’ for ‘/dev/ttyAMA0’ and get the characters back. The serial ports ‘/dev/ttyACM0’ and ‘/dev/ttyACM1’ represent the USB connections to both the Pico and Debug Probe. I’ve not worked out yet which is which, but I suspect will depend on which Pi USB port they are plugged into. Will have to do some testing.

Part two

What has been done is only half of the story though. We’ve written serial code for the Pico but not the Pi as we’re entering text in the console. Thus the next step is to have something on the Pi. For that it needs to have code that controls and sends / receives bytes over the serial port. This is not the first time that this requirement has been required, so why re-invent the wheel?

Searching on the internet I found ‘Linux Serial Ports Using C/C++2122’ by ‘Geoffrey Hunter23’, which is luckily ‘MIT licenced24’ so I can reuse it. This will save a lot of time as all I want to do is send some text to the Pico using the serial port ‘/dev/ttyAMA0’.

Still using the same Pico code, on the Pi I have the structure:

 1.
 2├── CMakeLists.txt
 3├── CppLinuxSerial
 4│   ├── CMakeLists.txt
 5│   ├── include
 6│   │   └── CppLinuxSerial
 7│   │       ├── Exception.hpp
 8│   │       └── SerialPort.hpp
 9│   └── src
10│       └── SerialPort.cpp
11└── src
12    └── pimirror.cpp

Where we have the code I’ve written, being ‘pimirror.cpp’ building in (rather than using as a library for simplicity) Geoffrey’s code. Firstly:

pimirror.cpp

 1/**
 2 * @file pimirror.cpp
 3 * @copyright (c) 2026 G J Barnard.
 4 *
 5 * @par License
 6 * SPDX-License-Identifier: BSD-3-Clause
 7 *
 8 * @version V1.0.0
 9 */
10#include <iostream>
11#include <chrono>
12#include <thread>
13
14#include "CppLinuxSerial/SerialPort.hpp"
15
16using namespace std::chrono_literals;
17using namespace mn::CppLinuxSerial;
18
19int main () {
20    std::cout << "Pi Mirror" << std::endl;
21
22    SerialPort serialPort("/dev/ttyAMA0", BaudRate::B_9600, NumDataBits::EIGHT, Parity::NONE, NumStopBits::ONE, HardwareFlowControl::OFF, SoftwareFlowControl::OFF);
23    serialPort.SetTimeout(0); // Don't block when reading.
24
25    serialPort.Open();
26
27    std::this_thread::sleep_for(100ms);
28
29    std::thread readThread([&]() {
30        while(true) {
31            if (serialPort.Available()) {
32                std::string readData;
33                serialPort.Read(readData);
34                std::cout << "Rx: " << std::endl << readData << std::endl;
35            } else {
36                std::this_thread::sleep_for(500ms);
37            }
38        }
39    });
40
41    std::thread writeThread([&]() {
42        std::string sendData("Testing");
43        std::string writeData;
44        std::this_thread::sleep_for(12s);
45        for (int sendCharIdx = 0; sendCharIdx < sendData.length(); sendCharIdx++) {
46            writeData.clear();
47            writeData += sendData[sendCharIdx];
48            std::cout << "Tx: \"" << writeData << "\"" << std::endl;
49            serialPort.Write(writeData);
50            std::this_thread::sleep_for(2500ms);
51        }
52        std::this_thread::sleep_for(16s);
53    });
54
55    writeThread.join();
56    readThread.detach();
57
58    serialPort.Close();
59
60    return 0;
61}

To get the code correct, I was influenced by Geoffrey’s example ‘ FlowControl.cpp ’. Writing this was a bit of a challenge and actually fun. I understand the principles and have done threads before in Java, so really a matter of getting the syntax correct and seeing what methods are available. This included understanding ‘Lambda25’ expressions.

You can get the specific ‘CppLinuxSerial’ files I’ve used from ‘ github.com/gbmhunter/CppLinuxSerial/blob/master/src/SerialPort.cpp ’, ‘ github.com/gbmhunter/CppLinuxSerial/blob/master/include/CppLinuxSerial/Exception.hpp ’ and ‘ github.com/gbmhunter/CppLinuxSerial/blob/master/include/CppLinuxSerial/SerialPort.hpp ’.

The program:

  1. Opens the serial port to the Pico on the Pi’s UART ‘/dev/ttyAMA0’ as was done before in the serial monitor of VSCode, and with the same configuration.
  2. Sleeps for 100 milliseconds.
  3. Creates a thread to do the reading, passing in a ‘Lambda25’ expression that represents a function that the thread will start executing. A pass by reference ‘capture clause26’ is used to pass all variables in the enclosing scope by reference. For us that we will use our ‘serialPort’ object.
  4. The ‘readThread’ just loops around seeing if there is data on the serial port and reporting it if there is, otherwise it sleeps for 500 milliseconds.
  5. The creation of the ‘writeThread’ is similar, but the code waits for twelve seconds and then sends the text ‘Testing’ one character at a time with a 2500 millisecond gap in between. Finishing with a sixteen second gap before terminating.
  6. It is the ‘writeThread’ terminating that causes the ‘join’, ‘writeThread.join()’ to return and allow the main program to continue.
  7. With the ‘readThread’ still running in its infinite loop, ‘detach’ allows the main program to continue again.
  8. It closes the serial port and terminates.

The top level ‘CMakeLists.txt’ file is:

CMakeLists.txt

 1cmake_minimum_required(VERSION 3.31)
 2
 3set(CMAKE_CXX_STANDARD 14)
 4
 5project(pi_mirror
 6    LANGUAGES CXX
 7    VERSION 1.0.0
 8)
 9
10add_subdirectory(CppLinuxSerial)
11
12add_executable(${PROJECT_NAME}
13    ${CMAKE_CURRENT_LIST_DIR}/src/pimirror.cpp
14)
15target_link_libraries(${PROJECT_NAME} CppLinuxSerial)

Which pulls in the ‘CppLinuxSerial’ ‘CMakeLists.txt’ file:

1add_library(CppLinuxSerial INTERFACE)
2
3target_sources(CppLinuxSerial INTERFACE
4    ${CMAKE_CURRENT_LIST_DIR}/src/SerialPort.cpp
5)
6
7target_include_directories(CppLinuxSerial INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)

as an ‘INTERFACE27’ as used with the Pico. There might be a better way of doing this, but for now I’m leaving with what I understand at the moment. Plus it works!

We can then build the binary:

 1gareth@pi:~/code/pi_mirror/build $ cmake ..
 2-- The CXX compiler identification is GNU 14.2.0
 3-- Detecting CXX compiler ABI info
 4-- Detecting CXX compiler ABI info - done
 5-- Check for working CXX compiler: /usr/bin/c++ - skipped
 6-- Detecting CXX compile features
 7-- Detecting CXX compile features - done
 8-- Configuring done (0.8s)
 9-- Generating done (0.0s)
10-- Build files have been written to: /home/gareth/code/pi_mirror/build
11gareth@pi:~/code/pi_mirror/build $ make -j4
12[ 66%] Building CXX object CMakeFiles/pi_mirror.dir/CppLinuxSerial/src/SerialPort.cpp.o
13[ 66%] Building CXX object CMakeFiles/pi_mirror.dir/src/pimirror.cpp.o
14/home/gareth/code/pi_mirror/CppLinuxSerial/src/SerialPort.cpp:32:12: warning: "BOTHER" redefined
15   32 | #define    BOTHER 0010000
16      |            ^~~~~~
17In file included from /usr/lib/linux/uapi/arm64/asm/termbits.h:1,
18                 from /home/gareth/code/pi_mirror/CppLinuxSerial/src/SerialPort.cpp:24:
19/usr/include/asm-generic/termbits.h:108:9: note: this is the location of the previous definition
20  108 | #define BOTHER          0x00001000
21      |         ^~~~~~
22[100%] Linking CXX executable pi_mirror
23[100%] Built target pi_mirror
24gareth@pi:~/code/pi_mirror/build $ 

Note the warning though, but it does not actually matter as ‘BOTHER’ is not being used / commented out in the code ‘ github.com/gbmhunter/CppLinuxSerial/blob/master/src/SerialPort.cpp#L379 ’.

When ‘pi_mirror’ is run with the Pico connected as before, we can see on the terminal:

 1gareth@pi:~/code/pi_mirror/build $ ./pi_mirror 
 2Pi Mirror
 3Rx: 
 4Ready
 5
 6Rx: 
 7Ready
 8
 9Tx: "T"
10Rx: 
11Ready
12
13Tx: "e"
14Tx: "s"
15Rx: 
16Got: T
17Got: e
18Ready
19
20Tx: "t"
21Tx: "i"
22Rx: 
23Got: s
24Got: t
25Ready
26
27Tx: "n"
28Tx: "g"
29Rx: 
30Got: i
31Got: n
32Ready
33
34Rx: 
35Got: g
36Ready
37
38Rx: 
39Ready
40
41Rx: 
42Ready
43
44gareth@pi:~/code/pi_mirror/build $ 

The program sending and receiving characters from the Pico. We can also observe this with the serial monitor:

Pi Mirror

After a bit of testing, it appears that it is the order that you plug in Pico and Debug probe (regardless of actual USB port) that determines allocation of ‘/dev/ttyACM0’ and ‘/dev/ttyACM1’.

Conclusion

At this point I had intended to continue with using binary instead, but I think this will be enough for now with the amount I have covered.

References