The Build

I finally got around to building a new workstation which I hope should be future-proof for the next 10 years, at least. It’s actually not yet complete, as I plan to upgrade the RAM to 96GB. I went with 32GB in the mean time since the Crucial kit I went with was dirt-cheap during the 2023 Black Friday sales. I am happy with the outcome so far though.


CPUIntel Core i7-14700K 3.4GHz
MotherboardASRock Z790M-ITX WiFi
RAM32GB (2 x 16GB) Crucial Pro RAM @ 5600MT/s
GPUPowerColor AMD Radeon RX 6800 XT 16GB
Storage1x WD_BLACK SN850X 2TB (Windows drive)
1x WD_BLACK SN850X 1TB (macOS drive)

This also happens to be my first small form factor (SFF) build, and it was surprisingly fairly straightforward, even with the tricky cable management. I opted for the Lian Li Dan A4-H2O case, which is a sleek 11L SFF case. Still get decent CPU and GPU temperatures with air cooling, although the case supports AIOs with liquid cooling. For some reason, I just can’t get comfortable with the thought of any liquid in the same vicinity as expensive computer components. The CPU and GPU temperatures are pretty decent, ~60ºC and ~76ºC respectively when gaming at 1080p (spent the latter part of December playing through Phantom Liberty).

Although I successfully got macOS running on my 5+-year old AMD machine, I was unable to run the Android emulator in macOS, which I need for streamlining my development work and productivity. That was probably the major factor which motivated me to switch to Intel. I’m currently running macOS Sonoma 14.2.1 with no headaches, and it’s smooth as butter. I’ve published the OpenCore EFI on Github for anyone interested.

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

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.

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

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.

Expired English

I took the IELTS exam a couple of years ago as part of my plans to apply for the Canadian Express Entry programme, and the results are about to expire. It is a weird concept that I have to re-take an exam to demonstrate my competence with a language that I have been speaking since I was born. Of course, it’s the same fee for admission, which is also just as frustrating. Then again, it is something that I have to do.

I’ve also spent the past few weeks trying to decide if I should just build a new desktop computer altogether (since my AMD Ryzen 7 2700 build is over 6 years old now), or build a separate Hackintosh machine. I managed to create a cheap build that’s a spec-to-spec match for the M2 Pro Mac mini which comes in at just about $850. A fully decked out desktop replacement that I liked would’ve been about $1600 (just $400 over my initial theory-crafted Hackintosh build). I could’ve pulled the trigger on that, but Intel’s next gen processors (Meteor Lake and Arrow Lake) which are around the corner will be using a new socket platform: LGA1851, instead of LGA1700. It doesn’t seem like a great idea to splurge on a new machine when there is no viable future upgrade path. And I do need Intel, so that I can run the Android simulator on the Hackintosh build. Virtualisation software do not like AMD processors in this scenario, unfortunately.

With my desktop replacement plans pushed further into the future, here’s the final cheap Hackintosh build I’ve arrived at. I already own a 1000W PSU back from my short-lived crypto mining days, and I purchased a RX 6600 just recently for my AMD build, for full graphics acceleration support. It can be $120 – $150 cheaper if I opt to go with DDR4 memory, but I think I like it this way. Sidenote: Why are DDR5 motherboards so goddamn expensive?!

PCPartPicker Part List

CPUIntel Core i7-13700 2.1 GHz 16-Core Processor $349.99 @ Amazon
CPU CoolerDeepcool AK400 ZERO DARK 66.47 CFM CPU Cooler $39.99 @ Amazon
MotherboardASRock Z790M-ITX WIFI Mini ITX LGA1700 Motherboard $209.99 @ Newegg
MemoryG.Skill Ripjaws S5 32 GB (2 x 16 GB) DDR5-6000 CL36 Memory $99.99 @ Amazon
StorageWestern Digital Black SN850X 1 TB M.2-2280 PCIe 4.0 X4 NVME Solid State Drive $84.99 @ Amazon
CaseMagniumGear Neo-G Mini V2 Mini ITX Tower Case $54.99 @ Newegg

Revisiting Hackintosh

Oh look, Mr. Inconsistent Blog Poster is back. But let’s not have that conversation right now. I know I’ve promised several times to post more regularly, but I am clearly a disappointment to myself. Just to get a few life updates out of the way: I am currently unemployed, looking for work. I learned French, up to the B2 level and I’m planning to take either the TEF or TCF exam soon. And I completed a 3-year university program with BCS in 2 years. I also created a buymeacoffee profile, but for sandwiches, so if you’d like to support the content creation journey which I’m about to re-embark upon, it’ll be much appreciated. Cool? Cool.

Alright, I need to replace my late 2012 Mac mini. I’ve gone back to doing some React Native development recently (existing codebase, not by choice, but there’s money to be made), especially targeting iOS devices, and the mini just doesn’t cut it anymore. I had heard good things about the M2 Pro processor, and I was considering a replacement Mac mini, but the prices for the configuration are just too goddamn high! I initially thought that the 2012 mini was at the end of life due to the fact that I needed to run XCode 14.2, which only works on the official macOS releases that run on Apple Silicon. However, I was able to actually upgrade from Catalina to Big Sur (using Patched Sur), and then from Big Sur to Monterey (using OpenCore). The bad news is everything runs quite slowly, but I had a lightbulb moment!

The late 2012 Mac mini is a machine with an Intel CPU, which means if I could get the latest release of Apple running on that, then I should be able to get it working on other Intel machines as well. The bigger surprise? I was actually able to get Monterey 12.6.4 running on my AMD build (considering I haven’t purchased Intel for over 6 years now). The spec sheet: Ryzen 2700 with 32GB of DDR4 RAM, ASRock B450M Pro4 motherboard, NVIDIA Geforce RTX 2060 graphics and a spare 500GB Crucial MX500 SSD I had lying around. It actually worked (EFI here if you’re interested), but there’s no hardware acceleration due to the fact that NVIDIA GPU support has been dropped from macOS, so I have to manage until I can afford to purchase an AMD graphics card, which isn’t available locally. The plan is to get a cheap 5500XT which allegedly works great. Thing were looking good, then I decided to try out running an Android emulator, only to be greeted with a nasty error that virtualisation isn’t working, although I have SVM enabled in the BIOS. Turns out I need an Intel CPU to be able to get this to work.

The ideal Mac mini M2 Pro configuration that I was aiming for cost $2,199.

  • M2 Pro 12-Core CPU | 19-Core GPU
  • 32GB Unified RAM
  • 1TB SSD
  • Wi-Fi 6E (802.11ax) | Bluetooth 5.3
  • I/O: 4 x Thunderbolt 4 / USB4 ports, 1x USB-A 3.1 Gen 1, 1x HDMI, 3.5mm headphone jack, 1 x Gigabit Ethernet Port

I put together an Intel build on pcpartpicker matching spec for spec, including discrete graphics which practically costs half, and performs way better with the benchmark scores available online. Look, I get that inflation is crazy all over the world right now, but this Apple tax is just something else! And there’s no way I’m willing to pay anything close to that.

CPUIntel Core i7-13700KF 3.4 GHz 16-Core Processor $391.96 @ Amazon
CPU CoolerDeepcool AK400 ZERO DARK 66.47 CFM CPU Cooler $39.99 @ Amazon
MotherboardASRock Z690M-ITX/ax Mini ITX LGA1700 Motherboard $139.99 @ Newegg
MemoryG.Skill Ripjaws V 32 GB (2 x 16 GB) DDR4-4000 CL18 Memory $79.99 @ Newegg
StorageWestern Digital Black SN850X 1 TB M.2-2280 PCIe 4.0 X4 NVME Solid State Drive $94.99 @ Amazon
Video CardMSI RX 6600 XT MECH 2X 8G OC Radeon RX 6600 XT 8 GB Video Card $259.99 @ Newegg
CaseFractal Design Torrent Nano Mini ITX Tower Case $99.98 @ Newegg
Power SupplyCorsair RM750e 750 W 80+ Gold Certified Fully Modular ATX Power Supply $99.99 @ Amazon
PCPartPicker Part List

I’ve been growing wary of tinkering (looking at you, Linux) and building software from source as I have become older because things that just work make life easier, but I’m excited to get back into this once again considering what can be achieved. Thanks Apple!

How I got the ACCA Diploma in Accounting and Business in 3 weeks

ACCA Diploma in Accounting & Business - Akinwale Ariwodola

I decided to obtain an accounting certification for a couple of personal reasons, one being that my dad advised me to do so several years ago in addition to my software work. Of course, I ignored him at the time since I didn’t think I would need to do anything else but software, but it looks like I have eventually come around. I was also quite upset by the fact that the Diploma I got from Informatics back in 2005 was pretty much useless for my purposes, so there was a bit of anger driving my determination.

After doing some research, I decided to start off with the ACCA diploma, seeing as it was possible to get it done in the shortest possible time (6 – 12 months on the ACCA website, but some individuals on various Internet forums posted they were able to get it done within a couple of months). There are 3 exams and an online module that need to be completed in order to get it done. I signed up as an ACCA student on the 15th of July using the Foundations in Accountancy (FIA) route, which cost £36, got approved on the 16th of July, finished the online module called Foundations in Professionalism the same day, and scheduled and paid for my first exam on the 23rd July.

To backtrack a little, let’s go over what the 3 exams are. Numerous posts on the Internet refer to these exams F1 to F3, but here are the actual names (they are all prefixed with F if you go through the foundation route).
F1 – FBT/BT – Business & Technology (formerly Accountant in Business)
F2 – FMA/MA – Management Accounting
F3 – FFA/FA – Financial Accounting

The 3 exams are available as on-demand computer based exams (CBE), and can be taken at any time, with a 50% pass mark on each of them, so I decided to tackle just one at a time just to test the waters. The first one I booked was the hardest one, FFA, since it had the lowest pass rate (70% as at July 2021) compared to the others. I paid $69 for the ACCA-X FFA course, and went through 10 weeks of course material within a week (over a weekend and most nights). I understood most of it and then proceeded to fail the first exam by scoring 49% (partly due to some stress caused by the British Council exam centre, which we’ll get to later, and I did not have a calculator because I wrongly assumed there would be an on-screen calculator provided by the CBE software). It turns out there are questions that tend to be worded in ways that trick you if you don’t pay attention.

One other important piece of advice that I ignored was to do practice / mock tests before the exam. I assumed since I already answered the questions at the end of every session in the course, I would be fine. I then proceeded to purchase 3 practice tests (available from the myACCA dashboard for £14) and scored 60%, 65% and 66% respectively. One thing the practice tests are really useful for is identifying where you’re likely to make mistakes and to be able to identify the trick questions. They also indicate which parts of the syllabus that you need to focus on for revision purposes. Another thing to keep in mind is that the practice tests seemed to be easier than the actual exam, but that could probably be due to the combination of questions you get from the question bank.

I decided to retake the exam on the day I failed, so I booked another session at a different centre the following Monday, July 26th and I passed with 55%. I decided to move on to FMA (second hardest with a 75% pass rate as at July 2021), paid $69 for the ACCA-X FMA course, purchased a set of 3 practice tests (again, proved useful to identify trick questions and where I was lacking) and booked a CBE exam at yet another centre (will cover reasons why later on) the following Monday, August 2nd, passed with 69%.

Finally, I decided to use the free OpenTuition course material instead of paying for the corresponding ACCA-X course for FBT, since it was the easiest of the 3 (highest pass rate). I finished the course material over 2 days, purchased another 3 practice tests just to be sure I was ready, booked a CBE exam for Thursday, August 5th and achieved a 75% score. I was transferred from the FIA (Foundations in Accountancy) path to the ACCA qualification path (you can choose to opt-out of this) with the first 3 exams marked as free exemptions as soon as my results were uploaded to the myACCA portal, and my diploma certificate got issues on August 6th.

CBE Centre reviews

This is more location-specific since I live in Lagos, Nigeria. I had an overall positive experience with the CBE centres except for the British Council, which was completely abysmal.

The British Council
The British Council offers the on-demand exams only 3 days in a month, it was the closest centre to home, and I already had some experience with them since I took my IELTS exam there, so booking the first exam there was a no-brainer. They were also the cheapest option. However, several things went wrong.

  1. I did not receive a confirmation email regarding my exam booking, so I had no idea whether or not the exam would hold.
  2. I got to the centre on the day of the exam by 8am, and they verified that my name was on the system. However, the exam which was supposed to start at 9am did not commence until about 11.30am. We were only just informed of technical issues about 1 hour before we started.
  3. They lost power (or turned off the generator) during the exam, which resulted in a network disconnection error and ended up terminating the CBE software (thankfully, progress was saved).
  4. The CBE software could not be relaunched immediately because the computer had a pending Windows software update. The power cut plus the wait for the update resulted in another 30 minutes of wasted time.
  5. I have not yet received my provisional result by email.

I did not have a good time, and the 49% fail was the icing on the cake.

Synergy Professionals
I retook FFA here, and the experience was fine, but they only offer exams from 12 noon, and I prefer to take exams in the morning.

The New Synergy Specialists (TNSS)
The furthest from home, and also a decent experience. I took the FMA and FBT exams here. The only complaints I have are table space was cramped, and you have to follow up to get them to email the provisional results.

So what did I learn?

  • Bring your own calculator.
  • The OpenTuition courses are actually pretty good, and best of all they are free (as in free beer). I only discovered OpenTuition after I had paid for the ACCA-X courses.
  • Always purchase a set of 3 practice tests for the CBE exams (they help identify where you’re likely to make mistakes and which parts of the syllabus to focus on for revision).
  • Depreciation, current ratio (I remember failing a question in the first FFA exam – I calculated with all assets and liabilities instead of just current assets and current liabilities, so I’ll never forget), variances, standard costing, financial performance measurement (I have all the formulae memorised) and more!
  • If you’re in Lagos, don’t count on the name brand of the “British Council”. Unless you’re prepared to deal with the stress, get your exams done elsewhere.
  • Don’t believe everything you read on the Internet, but we already know this. I went in with the expectation that everything would be very hard and I would require more than a month to study for each subject.


Total damage (with local currency equivalents)

  • Student registration £36 – ₦23,400
  • FFA failed attempt – ₦36,666
  • FFA successful attempt – ₦47,500
  • FMA successful attempt – ₦50,000
  • FBT successful attempt – ₦50,000
  • 3 sets of practice tests x 3 (£14 x 3 = £42) – ₦27,300
  • Optional – ACCA-X FFA course $69 – ₦30,360
  • Optional – ACCA-X FMA course $69 – ₦30,360

My total cost to certification was ₦295,586.
Total cost without failed attempts (OpenTuition courses) ₦198,200.
Total cost if you’re willing to deal with British Council’s timeline and shenanigans (OpenTuition courses) ₦160,698.
Cheapest approach (no practice tests) ₦133,398.

What the future holds

There are only 6 more exams in order to get the Advanced Diploma, so I’ve decided to pursue that, since I found a lot of what I’ve studied so far interesting. I already have the next exam booked, LW (GLO) – Corporate & Business Law. It’s the final on-demand CBE, as everything else is session based (March, June, September or December). It’s a mostly theoretical paper, and it’s got practice tests. Once I obtain the Advanced Diploma, I may explore taking the Strategic Professional exams yet, but I’ll decided when I get to that bridge.

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

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

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

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 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.


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.

Portable chargers and power banks that support passthrough charging

Keeping a single board computer or Arduino powered without interruption tends to be a requirement for several projects, examples including a home automation system, media centre or an autonomous robot. Portable chargers are very convenient and readily available at various online and brick-and-mortar electronics stores. However, not all of them support passthrough charging, which is a feature where power is provided to a connected device while plugged in to a wall socket. The only caveat here is if the device being powered consumes more power than the wall or socket AC output,

I have spent some time looking for options and here are a few brands that you can consider if you’re looking for a portable passthrough charger.


Most of the RAVPower portable chargers I’ve come across support passthrough charging. I personally have experience with the 16750mAh charger and I can confirm that it works great. With several good reviews from buyers on Amazon, it looks like you cannot go wrong with this option.

RAVPower Portable Charger 10400mAh
Capacity – 10400 mAh
Outputs – 2 USB Type-A (2.4A, iSmart)
Max Input – 2A
Weight – 226g (0.5lbs)
Price – $21.99

RAVPower Portable Charger 16750mAh
Capacity – 16750 mAh
Outputs – 2 USB Type-A (2.4A, iSmart)
Max Input – 2A
Weight – 303g (0.67lbs)
Price – $31.99

RAVPower Portable Charger 20100mAh
Capacity – 20100 mAh
Outputs – 2 USB Type-A, 1 USB Type-C (2.4A, iSmart, 3A)
Max Input – 2A (micro USB), 3A (USB-C)
Weight – 381g (0.84lbs)
Price – $49.99


My first portable charger was by Anker, but I soon discovered that whenever I plugged the charger to AC, the power from the USB ports was shut off. Apparently, their earlier products supported this feature, but they decided to remove it due to possible issues with the difference between the wall charger output and the input of the device being recharged (see caveat above). However, there is the 5000mAh PowerCore Fusion which is a hybrid wall and portable charger with support for passthrough charging.

Anker PowerCore Fusion 5000
Capacity – 5000 mAh
Outputs – 2 USB Type-A (2.1A / 3A)
Max Input – 2A
Weight – 190g (0.42lbs)
Price – $20.49


I haven’t had any experience with Aukey, but they do provide a number of portable chargers that support passthrough charging and they appear to be well reviewed on Amazon.

AUKEY 10000mAh Portable Charger
Capacity – 10000 mAh
Outputs – 2 USB Type-A (2.4A)
Max Input – 2A
Weight – 198g (0.44lbs)
Price – $25.99

AUKEY 20000mAh Portable Charger
Capacity – 20000 mAh
Outputs – 3 USB Type-A, 1 USB Type-C (3A)
Max Input – 2A (micro USB), 3A (USB-C)
Weight – 379g (0.84lbs)
Price – $39.99

AUKEY 30000mAh USB-C Portable Charger
Capacity – 30000 mAh
Outputs – 2 USB Type-A, 1 USB Type-C (3A)
Max Input – 2.4A (micro USB), 3A (USB-C)
Weight – 635g (1.4lbs)
Price – $59.99


This is a lesser known brand with several options that have received a significant number of good reviews on Amazon.

EasyAcc 10000mAh Power Bank
Capacity – 10000 mAh
Outputs – 2 USB Type-A (3.1A)
Max Input – 2A
Weight – 272g (0.6lbs)
Price – $19.99

EasyAcc 15000mAh Power Bank
Capacity – 15000 mAh
Outputs – 3 USB Type-A (2.4A)
Max Input – 2A
Weight – 334g (0.74lbs)
Price – $28.99

EasyAcc 20000mAh Power Bank
Capacity – 20000 mAh
Outputs – 4 USB Type-A (3.1A)
Max Input – 2A
Weight – 408g (0.9lbs)
Price – $39.99

That is quite a number of options from 4 different brands, and there are probably more that I haven’t even come across. Feel free to comment if you’ve got experience with portable passthrough chargers and you’d like to share.

Python 2.7.13 running on Android

I stumbled across a very interesting project called LBRY a while back, which I can describe as bitcoin meets bittorrent, Youtube and Soundcloud and and they all have a baby. The app includes a daemon developed in Python which is used to communicate with the LBRY network, and the goal was to get this running on Android one way or another. Prior to this, I had absolutely no idea there was a way to actually get Python on Android. I mean, it was theoretically possible since Android is based on Linux, but I had just never come across anything related to that.

Then I found out about Kivy, and the python for android (p4a) project. P4A makes use of a mechanism called recipes which define how certain Python modules or components should be built for a platform. There was a joint effort to get the daemon to compile and actually run on Android, which was eventually successful, but the Python version for the current p4a master branch is 2.7.2. I wasn’t exactly satisfied with this, so I went down the rabbit hole of getting Python 2.7.13 up and running. This took quite some time and effort, but I managed to get it to work. I found it to be quite frustrating at times, but it was also very exciting and I had a feeling of satisfaction after I had finished.

Funny story, after figuring it all out, I discovered there were pull requests created in Github for the p4a project related to building with Python version 2.7.11. If I had found them earlier, my life would have been a whole lot easier! Either way, it was a good learning experience and I’m glad to say it works pretty well.

You can find the LBRY Android project on Github if you’re interested in the recipes for building and running Python 2.7.13.