Finally got a degree

The events of 20th October, 2020 were a breaking point for me, and it led to me take certain steps for a better future, one of which was making the decision to embark on a journey to obtain the Professional Graduate Diploma in IT, a higher education qualification offered by BCS (the British Computer Society) which is equivalent to a UK Bachelor’s degree with honours (fancy). I decided to do this because I did not have a traditional university degree at the time. I will provide a minimal cost breakdown at the end of this if you wish to do the same, although you should note that the BCS is planning to retire the HEQ program in about 3 years (2026).

I was pretty ready to jump right into it, but registrations had closed for the November 2020 exam session. I had to wait a few months to be able to register for the next session which was May 2021. Each exam session is about six months apart, and I wanted to get things done as quickly as possible. But I ultimately learnt how to be patient.

I started with the Certificate in IT level, which has three core modules: Information Systems, Software Development, and Computer & Network Technology. I opted for self-study, so I decided to purchase a couple of recommended textbooks from the module syllabuses only for Information Systems and Computer & Network Technology. I have been developing software for over 27 years now, so I didn’t think it was necessary to get a textbook for that one. I also looked through the past papers which were available, and proved somewhat helpful. I hated Information Systems, Computer & Network Technology was quite hard (seeing as I had to remember intricacies about how laserjet and deskjet printers work, how hard drives store data, operating system features like paging and virtual memory, etc.), and I loved Software Development (27+ years of experience, obviously). It did take a couple of months to get the results which weren’t too bad. Note that the pass mark is 40%.

  • Computer & Network Technology – 51% (surprising, as I expected to do better with my detailed writeups)
  • Information Systems – 65% (most surprising, seeing as I hated the subject)
  • Software Development – 91% (well, duh!)

While waiting for the results, I embarked on a parallel journey to take a few ACCA exams in August 2021 for the Diploma in Accounting and Business, which was quite an interesting experience, as I was hungry for a challenge at the time. I also discovered that you could take any of the BCS exams for any of the modules at any level in any order. I had initially thought that you would have to take them in a particular order by level considering that there are 3 levels, Certificate, Diploma and Professional Graduate Diploma (PGD). This opened up a ton of possibilities and I decided to turbo through the rest. That turned out to be a not-so-great idea.

I ultimately decided to sit for six exams in the December 2021 session (4 modules from the Diploma in IT and 2 modules from the PGD in IT). These were:

  • Diploma: Professional Issues in Information Systems Practice – 53% (it is a core module, I studied for 6 different modules and I had brain fatigue and forgot some really easy questions).
  • Diploma: Web Application Development – 86% (18+ years of experience, ezpz)
  • Diploma: Object Oriented Programming – 70% (I don’t know, man. I kinda hate theory.)
  • Diploma: Big Data Management – 61% (I tried, man. Lots of theory. Brain fatigue).
  • PGD: Management Information Systems – 58% (very surprising result, to be honest, considering how much I hated Information Systems. I wrote what I could. Why did I pick this module, you ask? Well, because it seemed like one of the good options available on the exam calendar at the time.)
  • PGD: Software Engineering II – 64% (well, again, brain fatigue. This was the last paper on the calendar, and I was just glad it was over at the end.)

Why so much brain fatigue, you might ask? It turns out trying to study five different heavily theoretical modules is not a very bright idea. Plus I was also intrigued with trying to get the ACCA Advanced Diploma in Business and Accounting at the time, hence I was simultaneously studying Taxation, all while working a full-time software development job. I eventually burned out on the ACCA journey, failed my first attempt on the Taxation paper, and I had to forfeit the payment (£246, approx. $310) I made for a couple exams in March 2022 (Taxation retake and Performance Management), because I had to clear my head for the remaining couple of PGD papers: Web Engineering and Programming Paradigms which I was supposed to take in April 2022. I requested to defer the exams, but it was too late as I was past the deadline to do that, so I just rolled with it.

The results for the final pair of PGD papers turned out to be quite alright.

  • Web Engineering – 85% (Quite different from Web Application Development as this is more oriented to backend development. Again, I have been doing this for a long time now, so no surprises here.)
  • Programming Paradigms – 60% (Ugh! Another surprise seeing as I tried my best, but can we all just agree that theory sucks?)

Finally, I had to submit a project report. This turned out to be quite an annoying experience. There are only 2 submission dates in a year, and you have to wait six months to get a result. I submitted my report in May 2022 (August deadline), and waited until December 2022 to get the result, but it ended up getting marked as Fail. That ended up being rather disappointing, but I had to push forward and try again. I decided to contact a training centre for guidance, which required me paying a fee, but I went ahead with it since they’ve had students who have been successful with their project reports. I submitted again in February 2023, and waited until July 2023 to get another Fail mark. That really startled me and made me a bit upset, considering the amount of time, effort, blood, sweat and money that I had put into correcting my report based on the Project fail letter that was sent the first time around. I ultimately decided to appeal and that came back one month later with the score corrected to Pass. My final certificate is currently on the way and I am just glad this is all over.

What’s next? I’m really keen on pursing an online Masters degree in Computer Science, with Artificial Intelligence, since AI is all the rage right now. I’ve always been interested in AI since before it became cool, though. In any case, let’s look at the estimated total cost of everything at the time, and compare to now.

Cost breakdown
At the time

Student membership4 years£30≈$38~₦‎18,500$1/482
Certificate in ITthree core modules @ £40 each£120≈$152~₦‎74,000$1/482
Diploma in ITone core module + three elective modules @ £50 each£200≈$254~₦‎144,800$1/570
Professional Graduate Diploma in ITfour modules @ £90 each£360≈$456~₦‎260,000$1/570
Textbooks for all modules(bought at separate intervals, some used)~$360~₦‎189,400$1/526
PGD Project submission£115≈$146~₦‎88,700$1/607
PGD Project resubmission£115≈$146~₦‎110,600$1/757
~$1,552~₦‎886,000

Total cost – $1,552 or ₦886,000. I paid an additional ₦150,000 paid for project guidance from an accredited learning centre before the resubmission, and I also paid £100 (~$127) for the project appeal. Since the appeal was successful with the result changed to Pass, the £100 will be refunded.

Recently
With the parallel exchange rate at $1/920 today, which is just stupid (a story for another day), here’s what the total cost would look like (without a project resubmission).

Student membership4 years£30≈$38~₦‎35,000
Certificate in ITthree core modules @ £45 each£135≈$171~₦‎158,000
Diploma in ITone core module + three elective modules @ £50 each£200≈$254~₦‎234,000
Professional Graduate Diploma in ITfour modules @ £90 each£360≈$456~₦‎420,000
Textbooks for all modules(bought at separate intervals, some used)~$360~₦331,200
PGD Project submission£115≈$146~₦135,000
~$1,425~₦‎1,313,200

While this adds up to about $1,425 / ₦1,313,200 if you decide to take the self-study route, this is ultimately significantly cheaper than travelling all the way to the UK to obtain a degree from a university.

Handle gamepad input by reading from /dev/input using C# on the PINE64 running Linux

Now that we have a gamepad connected over bluetooth, and we are able to detect it programmatically, the obvious next step would be to able to handle the input events from the gamepad. Since evdev makes devices available through character devices in the /dev/input directory, we can easily read and parse the events from the corresponding input device file using a C# FileStream, and create corresponding events using the custom event raising and handling delegate model in C#.

In order to get a list of input device files available, I can run ls -lF in the /dev/input directory. This is what the output looks like on my PINE64.

If you are not running as root and you intend to be able to access the input device, you will need to add the user account to the input group. This can be done using usermod -aG input where is the current logged in user. Based on the output from my previous posts, the Xbox Wireless Controller will be accessible using /dev/input/input5.

The input event reader

Each evdev input event is represented as a struct which is defined in the uapi/linux/input.h header file.

The structure contains the following elements which can be read using a file stream in C#

  • time – a time value of 16 bytes. We will not actually be reading this with our code.
  • type – the event type, a short value of 2 bytes. Valid values can be found in the uapi/linux/input-event-codes.h header file.
  • code – the input event code, a short value of 2 bytes. Valid values can also be found in the uapi/linux/input-event-codes.h header file. The codes are determined based on the event type. For instance, an EV_KEY event will have an event code from one of the defined KEY_* values.
  • value – a value for the event, an integer value of 4 bytes. Dealing with a gamepad, for key events, this will be 0 and 1 corresponding to the up state and down state respectively, and for abs events, this would be a numeric value within the supported range.

Let’s create the aptly named EvdevReader class which will be used to open the file stream and read incoming input events. The constructor accepts an input Device as a parameter, which we created in the previous post for detecting the gamepad. The file stream is initialised in the constructor, and the class also implements IDisposable so that cleanup code for closing and releasing the stream can be called by the garbage collector.

Next is the Read method. A 24-byte buffer is created in order to read the input events as they come in. Since the open flag essentially indicates that the stream is open, the loop will keep running while input events (every 24 bytes) are read. The time value is skipped because we have no use for it. The type, code and value values are then retrieved and then passed as arguments to the DispatchEvent which we will look at next.

Since we’re only interested in gamepad events, we check that in the DispatchEvent method and then call the appropriate methods based on the event type. A subset of the event types and EV_ABS codes have been mapped as enums in the GamepadEventArgs class which will be used to store details about each event that is raised. Although only EV_ABS and EV_KEY events are being handled, you can extend the code to handle more event types depending on the particular input device.

The full code listing for EvdevReader can be found at https://gitlab.com/akinwale/NaniteIo/blob/master/GhostMainframe/Control/Input/EvdevReader.cs.

From evdev input events to C# events

With EvdevReader reading input events from /dev/input, we can essentially raise custom events making use of the type, code and values and also handle them as may be required. I created the GenericGamepad class to do just this. Since every gamepad is expected to have buttons (or keys), we can dispatch button up and button down events for EV_KEY events. An input event value of 0 means that the button is up, while a value of 1 means that the button is pressed down. We already have an InputEventCode enum which corresponds to the buttons that may be available on a gamepad. I also created a Button enum with more meaningful names. The idea behind this is to create a helpful key map for input events that are being received from the device, which will be used in GamepadEventArgs.

The DispatchKeyEvent method is quite simple. The input event code is checked using the IsInputEventKeyCodeSupported method to determine if the gamepad actually supports that key code. If it’s supported, the corresponding Button value is assigned to the event arguments, and the corresponding OnButtonUp or OnButtonDown event delegate is called based on the input event value (0 or 1).

Implementations of the GenericGamepad class are expected to initialise the buttons that are supported and a key map. The code from the XboxWirelessController implementation that I created shows how this can be achieved.

While EV_KEY events are fairly straightforward, EV_ABS events are a bit more involved, and may vary from gamepad to gamepad. I made the DispatchAbsEvent method a virtual method in GenericGamepad, meaning any class which extends the base class has to override the method. The XboxWirelessController class contains an implementation with some comments showing what the corresponding buttons and expected values are. EV_ABS events are raised by the dpad, the analog sticks and the triggers on the Xbox Wireless Controller.

Finally, we can test all of this in addition to detecting the gamepad with a sample console application. This will try to detect a gamepad, assign event handlers if found and then output the event args stdout whenever an input event occurs.

With this, it is very easy to build a program that can accept input system-wide and respond accordingly, and if you’re feeling adventurous, extend the code to support a plethora of input devices. You can obtain the full code listing for all the classes and enums named in this post from https://gitlab.com/akinwale/NaniteIo/tree/master/GhostMainframe.

How to programmatically detect if a gamepad is connected in Linux using C# and evdev

Since I managed to get the Xbox Wireless Controller connected to the PINE64 using bluetooth, I had to come up with a way to detect that a gamepad is connected, which is neater than having to create a configuration file containing the path to the evdev file, or if I felt like being lazy, hardcode the path in the program. evdev (short form of event device) is the generic input event interface used by the Linux kernel, making input device events available and readable using files in the /dev/input directory.

The /proc/bus/input/devices file contains information about the input devices currently connected to the system. We will have to read this file in order to determine whether or not a gamepad is connected to the system. Here is what the /proc/bus/input/devices file on my PINE64 looks like.

This gives us quite a decent amount of information to make use of when dealing with input devices. The I, N, P, S, U and H prefixes simply represent the first letter in the corresponding name value while B means bitmap, representing a bitmask for that particular property. The EV bitmap represents the type of events supported by a particular device, while the KEY bitmap represents the keys and buttons that the device has. So now that we have all this information, how do we detect if a particular input device is a gamepad? Referring to section 4.3 of the Linux Gamepad Specification in the kernel documentation, which is titled Detection, gamepads which follow the protocol are expected to have BTN_GAMEPAD mapped. BTN_GAMEPAD is a constant defined in the uapi/linux/input-event-codes.h kernel header file with a value of 0x130 (decimal 304). This means we will have to check if the bit corresponding to BTN_GAMEPAD (bit 304 counting from the rightmost bit to the left) is set to 1.

Moving on to the code, the first thing we should do is create a simple class that represents an input device. We’ll call it Device and it should have a name and a property to store the evdev path. The IsGamepad property is completely optional if you intend to deal with only gamepads.

Next, we’ll create an InputDevices class, with a static method which we will call DetectGamepad. The method will parse the /proc/bus/input/devices file, retrieve the name and evdev path and check the KEY bitmap for each device found. When a device that has the BTN_GAMEPAD mapped key is found, the method will return that particular device. If no input device with the mapped key is found, null will be returned.

We make use of StreamReader to open the /proc/bus/input/devices file as readonly, and then try to read each line until we reach the end of the file (or stream).

Obtaining the name of the device is fairly easy. The line starts with the N prefix, so we check this, and then we retrieve a substring containing the device name by stripping the double quotes surrounding the name.

Next we obtain the evdev path by checking the handlers on the line prefixed with H. The handler values are separated by spaces, so we split the string based on the space and check for the handler that starts with event. Once this has been obtained, we combine this with the the /dev/input/ prefix to get the full evdev path. In an upcoming post, we will look at how to monitor the evdev file for events using C#.

Finally, we need to detect the keys defined in the KEY bitmap. Let’s take the value for the Xbox Wireless Controller KEY bitmap as an example.
7fff000000000000 0 100040000000 0 0

This is a bitmask made up of hexadecimal values which we will convert to binary strings in order to check which bits are set. There are 5 groups of values, with each group expected to be 64 bits each. Just as a quick refresher, computers deal in binary, so 1 = 0001, 2 = 0010, 3 = 0011 and so forth. Each hexadecimal character value corresponds to 4 bits, and the individual 0-value groups can be padded with zeroes to make up 64 bits. For the KEY bitmap above, the total expected number of bits is 320. A bit value of 1 indicates that a value has been mapped. The bit position (counting from the rightmost bit to the left) corresponds to the values defined in the uapi/linux/input-event-codes.h header file referred to earlier.

With all of that making sense, we can write the code to parse the bitmap.

The bitmap value is split into groups using the spaces as the delimiter. If a group is equal to 0, then we pad the binary string with up to 64 zeroes, otherwise, we convert each hexadecimal value in the group to a binary string. Each hexadecimal value should be represented as 4 bits, so we pad to the left with zeroes if the conversion results in a string which is less than 4 bits. If a particular group’s binary string is less than 64 bits, we pad to the left with zeroes to make sure it’s up to 64.

Now that we have the binary string, we count from the rightmost bit to the left and store the bits that are set to 1 (value mapped) in the keybits list. Next, we check if the value for BTN_GAMEPAD (304) exists in the list. If it does, then the input device is a gamepad, and we can break from the loop and return a reference to the input device. If a particular line is empty, which is checked using line.Trim().Length == 0, that signifies that the next device is about to be parsed from the file, so we create a new device instance at that point.

InputEventCode is an enum based on a subset of values defined in the uapi/linux/input-event-codes.h kernel header file.

We can test the DetectGamepad method with a simple program to output the device name and evdev path to the console if found. Add the following code to the Main method of a console application to try it out.

With the /proc/bus/input/devices file, the device name and handlers can be determined, as well as supported event types and additional capabilities. If you’re feeling adventurous, you can extend the code to detect multiple gamepad devices if connected, or to identify all supported keys / buttons for a particular gamepad, or decode the other bitmaps for a particular device. In my next post, I’ll cover how to read the evdev file in order to detect the input device events and then handle them as may be required.

The full code listing of the InputDevices class can be found at https://gitlab.com/akinwale/NaniteIo/tree/master/GhostMainframe/Control/Input/InputDevices.cs.

Xbox Wireless Controller connected to the PINE64 running Ubuntu Linux using bluetooth

Although the goal of the autonomous robot project is to have a robot that can navigate without human input, it’s not a bad idea to be able to manually override and control the robot one way or another which could come in useful in cases where it gets stuck due to being trapped in between large physical obstacles, or perhaps a bug in the code. My PINE64 order came with the stock WiFi / Bluetooth 4.0 module which is still available from the PINE store, and I also got the Xbox Wireless Controller with bluetooth support ($39.99). Any bluetooth controller should be able to get the job done, but I particularly like the look of the Xbox Wireless controller. However, it was a little difficult getting the controller to actually pair due to certain quirks with the controller implementation. I finally got it to work after spending almost an entire day on the issue and accidentally wiping my primary Ubuntu install with dd (which shouldn’t have happened, but I suppose someone shouldn’t do dangerous things when they’re tired).

In this post, I will cover how to setup the PINE64’s stock Bluetooth module, how I got the XBox Wireless controller to successfully connect via bluetooth, and run some input tests using the evtest tool. I am currently running the longsleep xenial image with kernel version 3.10.105. In a future post, we’ll write C# code to handle system-wide input events for Ghost Mainframe (which is what I’ll be calling the autonomous robot project going forward until I can think of a better name).

How to setup the stock Bluetooth module on the PINE A64+

The first thing we need to do is install the firmware which will enable the bluetooth module to work properly and load the necessary drivers. This is fairly straightforward and can be done using these steps.

After make install completes, copy rtk_hciattach to your preferred bin path, either /usr/bin or /usr/local/bin.

You will also need to install the bluetooth service and the bluez stack by running sudo apt install bluetooth bluez. Once this is complete, you can test to make sure it works using the following comamnds:

Run sudo rfkill list and you should get output similar to what’s shown below.

If Soft blocked under Bluetooth is yes, unblock it using sudo rfkill unblock 3. This only needs to be done once. You can run the list command again to make sure that it actually got unblocked.

You can bring up the Bluetooth interface using sudo hciconfig hci0 up. Note that the hciconfig command is not available in BlueZ 5.47. Since the BlueZ version available from the xenial repository is 5.37, this is not a problem. If you don’t have hciconfig in your path, you will need to turn on the bluetooth module using bluetoothctl. Simply run power on in the bluetoothctl prompt.

Finally, you can add the following lines to /etc/rc.local if you wish to automatically power on the PINE Bluetooth module on every boot.

bluetoothctl

bluetoothctl is a command line tool that you can use to power on/off the bluetooth module, scan, discover and connect to nearby bluetooth devices. Simply run sudo bluetoothctl to get the to the bluetooth control prompt. If you are at the prompt and it’s not accepting your keyboard input, that could indicate that the bluetooth service is not running. Exit (using Ctrl+C if input is not being accepted) and then run sudo service start bluetooth.

Pairing the XBox Wireless Controller with the PINE64

This is where things got hairy. You can skip to the solution if you don’t want to read about how I arrived there.

The Story
I had been following the xpad kernel driver project for a while which is how I had initially found out that there was a new version of the Xbox controller that could be connected using bluetooth. Following the instructions in this issue and this comment didn’t seem to work. Instead, I ended up with an AuthenticationCancelled error.

My initial foray into finding solutions for the problem led me to build BlueZ 5.47 from source and install, but that didn’t change anything. There were also some posts about having to update the controller’s firmware which can only be done with a Windows 10 (Why, Microsoft?!) store app called Xbox Accessories. I created a VirtualBox VM running Windows 10 Fall Creator’s edition but the app did not recognise the controller when connected over USB. This led me into a deep hole where I was trying to obtain various older Windows drivers in order to get the controller to work. None of them worked so I eventually decided to just boot Windows on my notebook, as opposed to within the VM since I guessed that the VirtualBox USB implementation was probably causing detection problems (spoiler: I was right).

I tried to boot Windows from a preinstalled SSD, which resulted in a blue screen, then I tried to burn the VM’s VHD file to a different drive connected over USB, which somehow ended up destroying all the partitions on my internal SSD (I am very sure I used /dev/sdb as the of parameter for dd, not /dev/sda, but I don’t even care anymore). Finally, I created a Windows bootable flash drive and attempted to install on the external SSD only to discover that Windows cannot be installed to a drive connected over USB or Firewire. RAGE! Since my internal SSD was wiped anyway, I finally got Windows installed with the Xbox Accessories app up and running only to discover that the controller already had the latest firmware installed. That was pointless!

I almost gave up until I decided to re-read the btmon logs which led to me noticing the error, Result: Failure - unknown options (0x0003). This finally led me in the right direction as I found this mailing list thread which points to a couple of patches I had to apply to the kernel source. After rebuilding the kernel from source and modules, the bluetoothctl connect command works, although the pair command still fails. The connect command however forces the controller to pair, and that’s what’s important.

The Solution
Apply the changes in this commit (you may need to change the USB device ID – obtained using lsusb – to match your controller; mine is 0x02ea) to the kernel source and then rebuild and deploy the kernel, headers and modules following these instructions. You can also make use of the helper scripts in that repository. Following redeployment, you can reboot the board so that the new kernel and modules are loaded. You can also add the disable_ertm line to your /etc/rc.local so that it is done at boot time. Your /etc/rc.local file should have lines like so (including changes applied above):

Finally, you should get output like what’s showing using bluetoothctl (input commands are preceded with the bluetooth prompt). You will notice that although the pair command still fails with Failed to pair: org.bluez.Error.AuthenticationCanceled, the connect command actually works.

evtest: Testing the Xbox Wireless Controller input

You can exit from bluetoothctl after the connection has been successfully established. Install evtest using sudo apt install evtest and then run it using sudo evtest. With the output like so, enter the number corresponding to your controller.

I got the following output after I entered 5:

Here’s the output when I press a few buttons and move the analog sticks.

Conclusion

While it wasn’t a pleasant experience, I’m glad I was able to get the XBox Wireless Controller to actually work with the PINE64. In my followup post, I will write out (or probably create a diagram) of the controller button mappings through evtest and then write C# code to handle the input directly from the /dev/input/event* file and generate input events accordingly.

Installing Visual Studio 2017 Community edition on Windows 10 1607 (Anniversary Update) could break your boot process

Well, that’s a long title. I decided to give Xamarin a shot for cross-platform Android and iOS development a couple of days ago which led me to install the Visual Studio 2017 Community edition. I performed a basic installation with only Xamarin selected (I already have the Android SDK and NDK, so I unchecked those). The installation was successful and my system ran fine until the next day when I tried to launch a VirtualBox VM. This failed with an error stating that it was unable to start, asking me to check my VBoxHardening.log file. I couldn’t make any sense of the last entry in relation to starting to VM, so I decided to try the good old solution to everything.

I restarted my laptop, only to be greeted with a blue screen of death and the stop code: CRITICAL_SERVICE_FAILED. I tried restarting a couple more times and was greeted with the same error. I went through the usual troubleshooting process. I tried:

  • Using startup repair. This failed spectacularly with an error asking me to check C:\Windows\System32\LogFiles\Srt\SrtTrail.txt. The last line in this file started with: Unknown bugcheck: 0x5A param 0x1 xy. Searching for this led me to try some startup options.
  • Tried to use System Restore, but it turned out I didn’t have any restore points. I probably disabled this due to the Windows taking up more and more space on the SSD partition created for the OS. Why?!
  • Tried to boot into Safe Mode after startup repair. Got the same CRITICAL_SERVICE_FAILED blue screen.
  • Based on some of the search results I found for the bugcheck error in #1, I tried booting with the Driver Signature Verification option disabled and this worked. However, I got an popup error that nvcpl.dll (NVIDIA Control Panel-related) failed to start, and my WiFi device wasn’t working (failed to start error in device manager). I updated my WiFi driver which seemed to fix the WiFi device problem, but I didn’t bother rebooting to test it out.

Trying to remember the last major change I made to my computer, I figured it must have been the VS2017 installation from the day prior that may have interfered with certain things. This led to me searching for a combination keywords related to Visual Studio 2017 breaking Windows 10, which led to me a reddit thread with 2 people having encountered something very similar: install VS2017 Community Edition, CRITICAL_SERVICE_FAILED blue screen of death upon next boot. Installing the Windows 10 Creator’s Update fixed the problem for them, and I tried the exact same thing. And that worked. I no longer have any problems booting. And VirtualBox works fine too.

So, if you would like to install Visual Studio 2017 Community edition, make sure you upgrade to the Windows 10 Creator’s Update first. I was able to do this using the Windows 10 Update Assistant. Steps to fix if you encounter the BSOD boot loop:

  • Boot with Driver Signature Verification disabled.
  • Download the Windows 10 Update Assistant and upgrade to Windows 10 Creator’s Update.
  • Reboot as many times as you like after the upgrade is complete.

No idea if it’s a combination of hardware or software and drivers installed on my notebook, a Lenovo Y700, that caused this issue, but it’s 2017 and I just find it bizarre how installing VS2017 which is meant to be a developer tool should affect the Windows boot process. But hey, if you do encounter the issue, now you know what to do!

SEO-friendly, user-readable URLs with phpBB 3.2

I set up a forum using phpBB 3.2 this week and I wanted the URLs to be user readable and SEO-friendly (although this doesn’t really matter to search engines anymore, still figured it’d be a nice-to-have feature). I decided to make some changes to the phpBB core files. Now, my approach isn’t exactly ideal, because there will definitely be problems that arise from merging if any of the files modified for this are updated in newer versions of phpBB, but it gets the job done. If you would like to achieve this, you can proceed with the steps below after the friendly warning.

Disclaimer: Proceed with these steps at your own risk. I am not liable for any damage or harm that may occur to your forum, database, server, computer, or even pets from making use of the modified files in order to achieve the desired functionality. Always remember to make multiple backups of your files before making any changes.

First things first. Here are the fancy URL formats that we want to achieve.

  • /memberlist.php becomes /members
  • /memberlist.php?mode=viewprofile&u=2 becomes /members/u2-admin
  • /viewforum.php?f=1 becomes /f1-awesome-forum-url
  • /viewtopic.php?t=1&f=2 becomes /f2-another-awesome-forum/t1-just-do-it

This can be achieved by adding the following Apache rewrite rules to your .htaccess file (or your httpd configuration). Please note that mod_rewrite needs to be enabled for this to work.

If you’re running on nginx, you can add the following lines to your configuration.

Once you’ve updated your configuration files, unpack the ZIP archive into the top-level folder of your phpBB installation. Remember to make a backup of all your files before doing this. For reference, here are the files that will be overwritten after extracting the files in the archive.

  • .htaccess
  • index.php
  • memberlist.php
  • posting.php
  • search.php
  • viewforum.php
  • viewonline.php
  • viewtopic.php
  • includes/functions.php
  • includes/functions_content.php
  • includes/functions_display.php
  • includes/functions_posting.php
  • phpbb/feed/helper.php

You can view the modifications in action at https://www.eresidency.co. To reiterate, this is not an ideal solution, and you have to watch out for conflicts if you’re trying to upgrade to newer versions of phpBB, but it gets the basic job done. If there are any improvements you’d like to see, post a comment below.

The archive can be downloaded from Google Drive.

Controlling an Arduino connected to the PINE64 over I2C with C and C#

In a previous post, we connected an Arduino Mega to the PINE64 and wrote a sketch for the Mega for data communication. The data to be sent and received will follow the simple rules which were listed in the post. Next, we’re going to write a shared library with some C code to interface with I2C natively, and then a C# class which will call the shared library and bring everything together. Just a quick recap of the data rules:

  • Maximum length: 16 bytes.
  • First byte: Number of bytes sent/received.
  • Second byte: Control command. CMD_DIGITAL_WRITE (0x01 or 1), CMD_DIGITAL_READ (0x02 or 2) and CMD_ANALOG_WRITE (0x03 or 3).
  • Third byte: Pin number.
  • Fourth byte: Value of either 1 (for high) or 0 (for low) for CMD_DIGITAL_WRITE, or
  • Fourth to seventh bytes: Integer value for CMD_ANALOG_WRITE.

Linux has native I2C support which lets us communicate directly with any device connected to the bus. Since native communication is possible, we create a shared library with methods which can be invoked from our C# code. Since we can open the connection to a device on the I2C bus as a file descriptor, we will be making use of fcntl.h for the descriptor. Let’s take a look at the C library.

The first thing we do is include required headers and define a constant specifying the maximum number of bytes, which is 16. Then we create the nanite_i2c_open function try to open the specified device file (usually /dev/i2c-1). Next we call ioctl so that we will be able to control the device using a reference to the file descriptor, and the specified slave address. The file descriptor is returned for reference in other function calls. If any of the steps in the function fails, -1 is returned to indicate an error condition. Other functions in the library will handle the failure the same way.

The nanite_i2c_close function is fairly simple. It takes the file descriptor as an argument and checks if it is open in order to close it.

Next is the nanite_i2c_send function which takes the file descriptor and the data to be sent as arguments. The bytes are written to the open file descriptor, and the number of bytes written is verified. If it does not match the length defined in the first byte, -1 is returned to indicate an error condition.

The nanite_i2c_read function will be used to read data over I2C. The first byte is retrieved in order to determine how many more bytes to read. Then we validate the number of bytes that were received with the expected length. 0 is returned if the operation was successful.

The final function in the library is nanite_i2c_max_bytes() which returns MAX_BYTES. This gives us a complete library that we can use for I2C data communication. You can create the shared library using gcc -shared -o libnanitei2c.so -fPIC main.c. The full code listing for the library is available at https://gitlab.com/akinwale/nanitei2c/blob/master/main.c.

Using DllImport, we can call functions from the shared library in the C# code which we’re going to look at next. We create our class, define the supported commands as an enumeration and specify the private members. We also define a couple of constructors with the default constructor using the default I2C device file which is /dev/i2c-1 on the PINE.

The DllImport calls are defined within the class and are used to map the functions from the library to functions that we can call in the I2CExtendedIO class. For instance, to call the nanite_i2c_send in the class, we’ll make use of I2CSendBytes.

Here, we’ve defined our class dispose function which closes the file descriptor if it is open. We also have a bunch of simple helper functions which will be called within the class.

The Open function is simple as it delegates to the OpenI2C function with the specified device filename and the slave address, and assigns the returned file descriptor to a private member.

With DigitalWrite, we build the data to be sent based on the specified rules. Then we delegate to I2CSendBytes using the specified arguments, which calls the corresponding library function.

AnalogWrite is similar to DigitalWrite, except that we convert the integer value to 4 bytes instead of the single byte for low (0) or high (1). Valid values are between 0 and 255 inclusive.

To wrap it all up, we have the DigitalRead function which is a little different because we have to send data and then immediately receive a response. We obtain a mutual-exclusion lock so that the send and receive process completes before any subsequent operations are run. Then we validate the received data and return the value for the pin that was read.

You can obtain the full code listing for the C# class at https://gitlab.com/akinwale/NaniteIo/blob/master/Nanite/IO/I2CExtendedIO.cs.

We can put this all together and test with a simple interactive console application.

The console application accepts inputs like 13 on, 18 off or 9 analog 172 which makes it easy to test the Arduino pins. Although this is practically a complete solution for most requirements with respect to controlling an Arduino connected to the PINE (or Pi or any other SBC) over I2C using C#, you could choose to implement an additional command for analogRead. All you would have to do is follow the logic for digitalRead and add the necessary code to the sketch and the C# class.

Extending GPIO with an Arduino connected to the PINE64 using I2C

Although the PINE64 provides quite a decent number of GPIO pins, there are several reasons that you may want to have access to more pins. For example, the Arduino can provide an extra number of native PWM pins, or you may want to implement low-level control of a robot using the Arduino, with high-level operations being handled by the PINE. This post will cover how this can be achieved with the PINE64 and an Arduino Mega. We’ll also create a sketch for the Mega which for handling I2C communication. In the next post, we will write some C and C# code which will show how to send and receive data between the PINE and the Mega. Note that this can be done with any single board computer that supports I2C including any of the Raspberry Pis, the Beagleboard and others.

PINE64 connected to Arduino Mega over I2C

I2C stands for Inter-Integrated Circuit and it is a serial computer bus that enables communication between multiple devices that support the protocol. Every board that supports I2C will have 2 pins called SDA (serial data line) and SCL (serial clock line).

Pins 3 and 5 of the Pi 2 pinout on the PINE64 are the SDA and SCL pins respectively. On the Mega, they are pins 20 and 21. Connect the SDA and SCL pins from the PINE64 to the SDA and SCL pins respectively on the Arduino. I have also connected the 5V from the PINE to the Mega in order for the Mega to be powered by the PINE. If you decide to take this approach, one of the ground pins also has to be connected between both boards.

A closer look at the I2C connection between the PINE64 and the Arduino Mega

Before connecting the Mega, we’ll need to create and upload a sketch that will assign an I2C address which will be used to access the device. The sketch will make use of the Wire library which will be used for I2C communication. We will be making use of byte arrays to send and receive data over the I2C bus. You can come up with a fancy protocol for this, but I came up with the following simple rules.

  • Maximum length of 16 bytes.
  • First byte will always be the length (inclusive of the first byte) of the data sent or received.
  • Second byte is the command. We’ll support 3 simple commands, digital write (0x01 or 1), digital read (0x02 or 2) and analog write (0x03 or 3).
  • Third byte is the pin number.
  • For digital write only, fourth byte be a value of either 1 (for high) or 0 (for low).
  • For analog write only, the next four bytes after the third byte will store an integer value between 0 and 255 inclusive.

With that out of the way, let’s take a look at the sketch. First things first, define our constants and variables.

The code is straightforward. We define 0x08 as the I2C address that we want the Mega to use. We also define our commands, pin states (for digital read / write), buffers for storing data to be sent and received and other variables that will be used. The ioPins array is a list of all the pins available on the Mega. This will need to be changed to match the board that the sketch will be uploaded to. The ioPinStates is a pseudo hashmap which will map the pin number (used as the array index) to one of the defined pin states (IO_PIN_STATE_INPUT or IO_PIN_STATE_OUTPUT). We’re keeping track of the pin states so that we can activate the pins on demand, instead of activating them all at once in the setup() function.

The setup function simply initialises the Wire library using the specified I2C address, and enables Serial output which will be used to output debug messages. Wire.onReceive registers the onDataReceived function which will be called when data is sent from the PINE64, while Wire.onRequest registers the onDataRequested function which will be called when the PINE64 requests data from the Mega. The isPinValid function is a helper method which checks if the pin specified as the parameter is valid for the board. It checks the pin against the ioPins array that we defined earlier.

Next is the onDataReceived function which handles most of the work. It accepts an argument which represents the number of bytes that were received.

The while loop checks if there is data available from the Wire library. If there is, the absolute minimum number of bytes received that can be considered valid based on the rules we defined earlier is 3 (length, command, pin). If the number of bytes received is less than 3, then the function ends at that point and output is written to the Serial console. The next step is to use a switch statement to check and handle the command that was received. The second byte (index 1) contains this data.

For digital write, the minimum number of bytes to be considered valid is 4 (length, command, pin, value). The function is terminated if we received less than 4 bytes for the command. The isPinValid is called to check if the pin received is valid, and if it isn’t, the function ends at that point. Next thing to be done is to check if the pin has been activated. We make use of the ioPinStates array to do this making use of the pin number as the index. If the pin has not yet been activated (IO_PIN_STATE_OUTPUT), then we activate the pin using pinMode. Once this check is complete, we can call digitalWrite using the pin and the value specified.

Digital read also follows the same set of steps as digital write (validate date length, validate pin, check pin state) but we will call the actual digitalRead function in onDataRequested. What we do here is store the command and the pin in variables (lastReadCommand and lastReadPin respectively) which we can then make use of in onDataRequested.

Similar to digital write, analog write follows a couple of steps (validate data length and validate pin). We don’t need to check or set the pin state before calling the analogWrite function. We check that the value is between 0 and 255 inclusive before calling analogWrite with the pin and the value as the arguments.

If the data sent did not match any of the defined commands, the code falls back to the default statement which outputs Unrecognised command. to the serial command, and then the onDataReceived function will be called again when new data is received.

Finally, we have the onDataRequested function which makes use of lastReadCommand and lastReadPin. The function is straightforward, as it uses the Wire library to send data back to the PINE following our simple rules.

And that’s it! Compile the sketch using the Arduino IDE and then upload it to your board. Connect your Arduino to the PINE after the sketch is successfully uploaded, and boot up the PINE. You can obtain the full code listing for the sketch at https://gitlab.com/akinwale/nanitei2c/blob/master/nanitei2c_mega.ino.

Install i2c-tools using sudo apt-get install i2c-tools. By default, only root can use the I2C commands, but you can add the user account with useradd -G i2c ubuntu (replace ubuntu with the username that you want to use to access I2C). Reboot the PINE and then scan the I2C bus with the command, i2cdetect -y 1. You should get output should be similar to the following:

Based on this output, we can see that the Mega was recognised over the I2C bus with the configured address in our sketch (0x08 or 8). With this, we have access to the extra pins which we will be able to control directly from the PINE. That’s pretty neat. In the next post, we will write the C and C# code for the PINE for handling I2C communication.

Control GPIO pins on the PINE64 with C#

Similar to the Raspberry Pi, GPIO pins on the PINE64 can be controlled through sysfs. You can refer to my previous post which goes into the concept in detail, and the C# code remains the same for the PINE64. However, with the longsleep Ubuntu image, root access is required to control the GPIO pins. You will need to grant the necessary permissions in order to be able to control GPIO pins as a normal user.

Granting user permissions
We’ll assume that we want to be able to control the pins as the default ubuntu user. Follow these steps to grant the necessary permissions.

  1. Create a user group called gpio.
    groupadd gpio
  2. Add the ubuntu user to the gpio group.
    useradd -G gpio ubuntu
  3. Add a udev rule to run chown on the sysfs files. The chown command will set group ownership to the gpio group. Adding the udev rule will run the chown command automatically whenever you export a pin. Create a file called 99-com.rules in /etc/dev/rules.d and paste the following contents.

    Physical pin to GPIO number mapping
    I took some time to test the physical pins on the PINE in order to determine the sysfs gpio numbers and came up with this table. As an example, physical pin 22 on the Pi 2 pinout corresponds to /sys/class/gpio/gpio79.

    Pin #GPIO #
    Pi 2 pinout
    3227
    5226
    832
    1033
    1171
    1272
    13233
    1576
    1677
    1878
    1964
    2165
    2279
    2366
    2467
    26231
    27361
    28360
    29229
    31230
    3268
    3369
    3573
    3670
    3780
    3874
    4075
    Euler pinout
    7363
    10232
    1135
    1236
    1337
    1538
    1639
    18100
    1998
    2199
    22101
    2397
    2496
    26102
    2734
    28103
    2940
    3041
    Exp pinout
    2359
    740
    841

Implementing cross-origin resource sharing (CORS) using middleware in CakePHP 3.3

I worked on a project recently where I had to allow XMLHttpRequests from a different domain. I initially thought about adding the necessary Access-Control headers at the controller level, but after doing some reading, it turned out it was a better idea to make use of a dispatcher filter. However, dispatcher filters would only apply prior to CakePHP 3.3 since they are now deprecated.

Enter middleware, which I found to be quite familiar since I have made use of a similar concept in Express during my Node.js development. Think of middleware as reusable components which you can use to handle your web requests and modify responses.

The CakePHP middleware classes should be placed in the src/Middleware folder. You can create the folder if it doesn’t already exist in your project.

We’ll create a class in the Middleware folder called CorsMiddleware.php.

The code listing is pretty straightforward. The response is modified with the necessary headers to enable the cross origin requests to be successfully handled by the browser.

You can modify the header values as you see fit, like limiting the Access-Control-Allow-Origin header to specific domains – the wildcard (*) allows requests to be accepted from all domains – or the the request methods to just GET and POST, or the allowed request headers.

To make use of the cors middleware, modify src\Application.php and add the middleware using:
$middleware->add(new CorsMiddleware())

And that’s all there is to it. There are more details about what you can do with middleware in the CakePHP documentation, so be sure to check it out.