Converting STM32 bin (binary) file to hex (Intel) file.

Today I tried to work on a firmware updater using the STM32 Bootloader driver. I’ll post about the program later since it took a while to figure out how to write something in C# to use the preferred STM32 Bootloader driver instead of the outdated DFU Device bootloader.

In any case, this firmware updater programer uses Intel Hex file for the firmware updating. Technically you can use Bin as well, but Intel Hex file is nicer because it already has the memory address mapped out. You need to the Bin file what memory address to start and that invites errors that could potentially brick your device. I worked with a firmware engineer who just quit recently and all he gave us for the firmware was the bin file. I do have the source code so I could technically compile a hex output from the source code, but the IDE environment and settings were not available from this engineer. So the best option is to find a way to covert this working bin firmware to hex so that I can use it to update device firmware with the program.

After doing a bit of search on how to convert bin to hex, I found that SRecord is the best tool to do this. You can download the appropriate installer for your desired OS here:

For my use case, I went with the Windows version. It’s actually quite easy to use once you figured out what to do. I mentioned how Bin file doesn’t have the memory address while hex does. If you just do the simple convert like the examples around the web show:

srec_cat.exe "firmware.bin" -binary -output "firmware.hex" -Intel

This didn’t work too well for STM32 since the firmware main program address doesn’t start at 0x00000000 because that’s where the boot loader firmware starts. The actual application memory address starts at 0x08000000. Therefore, we need to shift the data from the binary file to that address. This is easy to do using SRecord. Use the following command instead:

srect_cat.exe "firmware.bin" -binary -offset 0x08000000 -output "firmware.hex" -Intel

Now your newly created .hex file should be useable on STM32Cube Programmer as well.

Installing and Running TreeSheets on MacOS (12+, M1)

TreeSheets is a great free productivity tool created by Wouter van Oortmerssen (Creator of Sim City, Borderlands 2, etc.). This is a great tool for storing information in a hybrid text and spreadsheet method. The nice thing about it is that the file size is tiny, and it’s quite efficient at storing the information. You can also open your saved file on all the platforms running TreeSheets.

The installer ( works great on PC (tested on Windows 10/11) and Linux (tested on Ubuntu 22.04.1 LTS). Unfortunately, my Macbook Pro M1 running macOS 12.6 doesn’t quite work due to this warning:

Fortunately, there’s a way to get around this warning. Go to System Preferences -> Security & Privacy –> General Tab. You’ll see a message that was blocked from use because it is not from an identified developer. Click “Open Anyway”

Another dialog window will pop up. Choose “Open” again to keep going.

Now you should have TreeSheets running on your macOS

Follow the tutorial to get familiar with how TreeSheets work. Once you are proficient at using it, you won’t want to go back to using a text pad or anything else. Enjoy!

P.S. Another way of installing TreeSheets on MacOS with M1 is to use Brew. In a Terminal window, type in the following command:

brew install --cask treesheets

If you don’t have brew enabled on your system, then follow the installation guide on the Homebrew Documentation site:

After the installation is done, a will be available in your launcher. Unfortunately, it will not launch the first time you run it because of a permission error. To overcome this, permit the app to be accessed using the following command in a Terminal window:

sudo chmod +x "/Applications/"

Now the app should be able to launch, but then you would run into the problem mentioned at the beginning of this article. Follow the same steps, and you should have TreeSheets running on your macOS system.

Flutter Install Issue On Windows 10: Fixing Exception in thread “main” java.lang.NoClassDefFoundError: …

After installing Flutter and Android Studio on Windows, you run the following command:

flutter doctor

A common problem you might encounter after installing Android Studio is that Android Studio is not found. This is fixed by setting the Android Studio Directory with this command (assuming the default install path):

flutter config --android-studio-dir="C:\Program Files\Android\Android Studio"

Afterward, you might be asked to accept the Android license.

You can do so with this command:

flutter doctor --android-licenses

What you will now encounter after running the license acceptance would be the exception error.

To fix this, launch Android Studio, select Projects and the More Actions. Pick SDK Manager from the drop down list.

Choose the SDK Tools tab and check the “Android SDK Command-line Tools (latest)”. Click OK.

Run flutter doctor command again and now everything should be good.

Enjoy Flutter!

Setting up Remote Desktop (RDP) on Rocky Linux 8.4

As of this writing, I’m using 64-bit Rocky Linux 8.4 that came with GNOME by default.

Since this version already has the GUI that is GNOME, this will mainly work for the settings I have. I know there are issues if you use other GUI packages.

Setup EPEL Repository

First, become the root user since the setup requires superuser privileges.

su -

Run update to make sure your install is up-to-date

yum update

Run the following command to install EPEL Repository

yum install epel-release

Install and Enable XRDP

Now you can enable EPEL Repository and install Xrdp server using the following command

dnf --enablerep=epel -y install xrdp

After the installation is done, enable xrdp using the following command

systemctl enable xrdp --now

Firewall Configuration

Also, let xrpd go through the firewall. Assign the correct port if you are not using the default 3389 for TCP.

firewall-cmd --add-port=3389/tcp

Make the rule permanent using the following command

firewall-cmd --runtime-to-permanent

Connect Using Windows RDP

Now you should be able to connect to Rocky Linux using Windows RDP. Make sure that the user you are using for login is not already logged in on the server or the RDP session won’t connect.


Installing Rocky Linux on Windows 10 (Pro) Hyper-V

Hyper-V is a virtual machine module from Microsoft similar to Sun/Oracle VirtualBox or VMWare ESX. Hyper-V is a Type 1 Hypervisor that runs directly on the host machine’s hardware rather. This is different from Type 2 Hypervisor which the virtual machine’s commands are managed through the host running the virtual machine.

Why use Hyper-V?

If you are already running Windows 10 Pro or Windows Server, Hyper-V is free to use and it’s very easy to install. For the setup to run Rocky Linux 8.4 in this article, I’m using Hyper-V on Windows 10 Pro since I don’t have access to a Windows Server machine. Windows 10 Home doesn’t allow Hyper-V, unfortunately.

Download Rocky Linux (8.4)

At the time of this writing, Rocky Linux 8.4 is the latest stable release. Rocky Linux is likely going to be the chosen replacement for Centos OS 8 as the upgrade path now that Red Hat has officially killed the Centos project. Red Hat doesn’t want Centos to compete with RHEL anymore so it moved to CentOS Stream. CentOS Stream is a continuously updating distribution which is a problematic upgrade because there’s no more stable release. Although CentOS Stream continuously updates, it’s staying within the confine of the RHEL major version release.

Unfortunately, CentOS Stream is being treated as a development branch of RHEL which means that it’ll see all the bugs first before RHEL. Most users use CentOS because it’s tracking AFTER a stable release of RHEL.

Back to Rocky Linux, it’s emerging as the main replacement for CentOS. It’s started by CentOS co-founder and a the hardcore veteran Gregory Kurtzer. He and thousands of developers took the lessons learned from CentOS and its demise to create Rocky Linux. Hopefully, we won’t suffer the same fate that Red Hat dealt with CentOS because it had a conflict of interest. Mainly money-grabbing, but who knows?

Head over to Rocky Download page:

Select the x86_64 DVD distribution to get the iso we need to run on Hyper-V. The minimal package runs into problems when trying to install in a virtual machine.


First you must enable Hyper-V in Windows 10. There are a couple of ways to do it, but using Windows Shell is pretty straightforward. Launch Windows Shell as an Administrator.

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

A restart will be required to get Hyper-V working. Select Y to restart your computer after Hyper-V is enabled.

After Windows restarted, type in the search bar “Hyper-V” and select “Hype-V Quick Create”. This will launch a Create Virtual Machine module.

Uncheck the “This virtual machine will run Windows (enables Windows Secure Boot)”.

Click on the “Change Installation source” and select the Rocky Linux iso we downloaded earlier. Click “Create Virtual Machine” after the iso file is chosen.

Depending on your computer’s specs, the installation could be very fast. On my system, it only took a few seconds for the new virtual machine to be created.

Click “Edit settings …” to edit our new VM. It’s very important to make sure that the allocated RAM is at least 4 Gigabytes or you’ll have problems running Rocky Linux on the VM. By default, the new VM is only created with 2GB or RAM allocated.

You can also locate the virtual machine media in a different location. By default, it’s putting the image in your user profile which is not an ideal location. Click on the Hard Drive option on the menu bar on the left. Click “New” under the virtual hard disk option and then follow the steps to create your new virtual hard drive media location.

Connect To VM

Now that everything is ready to go, click on the “Connect” button to connect to our VM. Click the “Start” button on the screen to launch the VM.

After a few seconds, the Rocky Linux 8 install option should show up. Make sure you either disable the firewall or letting the Hyper-V VM go through the firewall to get it running. Select “Install Rocky Linux 8” option and hit Enter to start.

If it runs correctly, you should be presented with the Rocky Linux 8 Installation. Go through the setup steps

I won’t cover all the installation details here since everyone has his/her own preferences for the server. Let the installation run and you’ll have a Rocky Linux 8.4 Server on Hyper-V in no time.

I had to shutdown the VM when the automatic reboot seems to be stuck. After shutting down and re-starting the VM again, it lets me complete the configuration of the server and then accept the license.

All done! Enjoy!

One issue that you may encounter while running the new server is no internet connection. The issue is that the “Default Switch” might not be configured for the external internet connection. When you first created the VM, if you chose the switch to be “Default Switch”, it’d likely have an Internal network connection.

First, suspend and shut down your VM so you can make modifications to the settings. You can add a new switch by opening up Hyper-V Manager. Click on the “Virtual Switch Manager …” from the Actions menu on the right.

Select “New virtual network switch” option and make sure you choose “External” as the type then click “Create Virtual Switch” button.

I named the switch “INTERNET” to quickly differentiate it from the default switch. Make sure that you check the box for “Allow management operating system to share this network adapter”.

Click OK to accept the changes. Select “Settings …” for your vm from the Hyper-V Manager.

Choose the Network Adapter option from the left menu and change the Virtual Switch option to the newly created “INTERNET” switch. Click OK on Apply to accept the change.

Now you can start your vm again and check whether you now have an internet connection in your Hyper-V. Also make sure that your connection is enabled. Click “Connect” if your connection was off.

If everything goes well, you should now be able to connect to the internet in your VM.

One thing I noticed on my 4k resolution monitor is that the Hyper-V window containing Rocky Linux is running is a much lower resolution than I want. Since this is GNOME by default, we can increase the resolution using the following command:

grubby –update-kernel=ALL –args=”video=hyperv_fb:1920×1080″

You then need to reboot for this new resolution to take effect.


This is much better in my opinion.

Patterns for Mask

Due to the Covid-19 situation, face masks are very difficult to find. Thanks to a craft sites like this one ( ) we have a way to make your own mask.

To make it easier for other people to make this mask, I’ve made a PDF (Link Here) and InkScape SVG (Link Here) of the mask patterns. I added the X-large size to the pattern so that people with a larger face also has an option.

Adding Open Command Window Here in Windows 10

In Windows 7, you could be in a File Explorer window and hold Shift + Right click to bring up the “Open Command Window Here” in the context menu. It’s very hand when I want to just be in the correct directory to do stuff without having to go through all the paths to get there.

This feature is disabled in Windows 10 and you have “Open PowerShell window here” instead. I don’t (but should someday) use Power Shell. For now, I just want my good old command window.

There are instruction online to do a bunch of permission change via RegEdit and changing the flag of the cmd folder registry. It was pretty involved and in the end I couldn’t really get it to work. I then stumbled upon somebody’s comment on an easier way.

Basically, just save this script as a .Reg file and then run it. It’ll automatically add the registry key that allows the right click context that we need. You might want to close all the File Explorer windows to get it to work.

Windows Registry Editor Version 5.00


@="cmd.exe /s /k pushd \"%V\""


@="cmd.exe /s /k pushd \"%V\""

Now when you Shift + Right click in a File Explorer, you’ll have “Open Command Window Here” back.

How to embed icon data in Python 3.x for TkInter

Sometimes when you want to use TKinter or other GUI dialog but you don’t want to use the generic default icon. You also might not want to have the *.ico or *.png file included in the same folder as your script. Wouldn’t it be nice to just have the icon data embedded in your code?

It’s actually not too difficult to do in Python. I’m working with Python 3.x here so you might have to adjust the code for Python 2.x. We’ll use Tkinter dialog as an example here. Let’s try putting this example books.icon or any icon you would like to use in code. If you need icons to play with, you can get a great set of open-sourced icons from here:

The icon I’m using is from the icon pack and once you extract the archive, it’s in ../ico/16×16/others/books.ico. You can also just download the icon file here: books.ico


The trick is to converting the icon file data into string representation of hex data that we can store in the program. This is actually surprisingly easy to do using repr() function to generate string of the object. In this case, we are converting the icon image data into string hex values. The following code will print out the data for the icon file in the almost correct format for you to use. Make sure the icon file is in the same location as your script when running this code.

with open("books.ico", "rb") as image:
     a =

I said almost a correct format because you’ll end up with a really long string hex data dump and it’s in a single line. This could be used as-is but you’ll end up with a really long line in your python file that you’ll have to scroll right very far to see the entire thing. I’m truncating here so we don’t fill up the whole page.

b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x00\x00\x00\x00h\x04\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00 

For the sake of readability in our code, we’ll format it into a nicer format by breaking every 16th hex values into its own line. Here’s the previous code updated with a formatting code below:

with open("books.ico", "rb") as image:
    a =
data = (repr(a))

data = data[2:]  #trim out the b'
data = data[:-1]  #trim out the last '

dataList = data.split('\\x')  #split by hex unit
dataList = dataList[1:] #remove the blank  value at the beginning

totalLen = len(dataList)

i = 0
hexline = ''
lenCount = 0
groupCount = 0
for hex in dataList:
    if(lenCount == totalLen-1):
        hexline += '\\x' + hex
        print('b\'' + hexline + '\'')
    if(i == 16):  #change number of grouping here       
        print('b\'' + hexline + '\'')
        hexline = ''
        groupCount += 1

    hexline += '\\x' + hex
    lenCount += 1

This should now give us the format we can just cut and paste from the output window into our code for the Icon data. For every 16th hex value, a new line is created with b’ at the beginning of the line to represent byte code representation using string. Again I truncated the data to save space.

b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00 '

Now we’ll do an example of a TKInter window with the embedded icon data. Use the full icon data from the output generated by the code. The data shown in the code below is truncated in this code example.

import tkinter
import tempfile

ICON = (b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x00\x00\x00\x00h\x04\x00'
b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00 '

_, ICON_PATH = tempfile.mkstemp()
with open(ICON_PATH, 'wb') as icon_file:

root = tk.Tk()


If you cut and paste the data value into the ICON correctly, you should see a blank tk window with the icon that had the generated the data.

Here are the complete codes for the data generator and the tk example. You need to rename the file extension to .py. This server doesn’t allow .py extension to be viewed.


Pyinstaller Trouble with PyQt5 and Matplotlib on Python 3.7

Pyinstaller is a fantastic python to exe packager. When I tried making a stand alone exe with a python script ( using a quick PyQt5 example, it creates a working exe file right off the bat using this simple command:

pyinstaller --onefile


import sys
from PyQt5.QtWidgets import QWidget, QMessageBox, QApplication

class Example(QWidget):    
    def __init__(self):
    def initUI(self):               
        self.setGeometry(300, 300, 250, 150)        
        self.setWindowTitle('Message box')          
    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QMessageBox.Yes | 
            QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()

Running the executable file from the dist folder in works perfectly just as the same way as you just run the script in the interpreter

I left the console option in the background so that if there’s an error I could see it when the program runs. However, you could get rid of the console by adding “–noconsole” option to pyinstaller.

pyinstaller --onefile --noconsole

Now that works so well, I want to see whether I could make a standalone file with a script that has PyQt5 and Matplotlib. Here’s the code I use to test this:

import sys
import PyQt5
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QVBoxLayout, \
   QSizePolicy, QMessageBox, QWidget, QPushButton, QListWidget, QDesktopWidget
from PyQt5.QtGui import QIcon
from PyQt5 import QtCore
import PIL
import tkinter
from tkinter import filedialog

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt

import random

class App(QMainWindow):

    def __init__(self):
        self.left = 10 = 10
        self.title = 'PyQt5 matplotlib example'
        self.setFixedSize(640, 700)

    def location_on_the_screen(self):
        ag = QDesktopWidget().availableGeometry()
        sg = QDesktopWidget().screenGeometry()

        widget = self.geometry()
        #x = ag.width() - widget.width()
        #y = 2 * ag.height() - sg.height() - widget.height()
        x = sg.width() - widget.width()
        y = 2 * ag.height() - sg.height() - widget.height()
        self.move(x, y)

    def initUI(self):
        #self.setGeometry(self.left,, self.width, self.height)

        m = PlotCanvas(self, width=5, height=4)

        button = QPushButton('PyQt5 button', self)
        button.setToolTip('This s an example button')

        button2 = QPushButton('Plot', self)
        button2.setToolTip('Plot Data')

        listBox = QListWidget(self)

class PlotCanvas(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)

        FigureCanvas.__init__(self, fig)


    def plot(self):
        data = [random.random() for i in range(25)]
        ax = self.figure.add_subplot(111)
        ax.plot(data, 'r-')
        ax.set_title('PyQt Matplotlib Example')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()

When creating an exe for this script using Pyinstaller I see a lot of warnings but no errors. I even got an exe. However, when I ran the exe I got an error:
ModuleNotFoundError: No module named ‘numpy.core._dtype_ctypes’

I did have Numpy correctly installed using pip and I have version 1.16.0 and it’s supposedly the most up-to-date version.

After Googling the error, I found that the problem was indeed Numpy itself and the issue is fixed if I have version 1.16.1. However, doing pip install numpy doesn’t work since it insists that 1.16.0 was the up-to-date version.

Therefore, I have to force the install of 1.16.1 Numpy

pip install numpy==1.16.1

This forces the new version of Numpy to be installed. I tried to create the exe file again using Pyinstaller. Again, the exe creation went just fine as before. I wasn’t sure whether this would work or not, but to my surprise when running the exe file I have a working program!

I was quite pleased with the result. Now I could move forward with using Pyinstaller to make a standalone program.

Installing Python 3.7 on Raspberry Pi

As of Jan 2019, Raspberry Pi comes with Python 3 but it’s an older version of Python 3 (<3.6). The latest Python version is 3.7.2 at the time of this post. If we want to use the latest version on Raspberry Pi, we need to compile it from the source. Please make sure to note the use of ‘sudo’ in the command lines because at certain lines you don’t want to have sudo because it’ll change the location of the configuration and installation and you might not end up with a working Python 3.7.2

First make sure you update your Raspbian to the latest update. If any prompt comes up just answer ‘yes’. There might be some information page that you have to scroll through by holding down the space key to the end. After that press q to continue with the installation.

$ sudo apt-get update
$ sudo apt-get -y dist-upgrade

Your Raspberry Pi might require a reboot. If you end up with a black screen and no response at some point then you can unplug and plug in the power to re-start your Pi.

Now you are ready to upgrade to Python 3.7.2. One thing to note is that your GPIO libraries that’s specific to the hardware might not work. You can always still access your original system Python 3 using /usr/bin/python 3 to bring up the original system Python3

$ /usr/bin/python3

Before downloading and compiling the new Python 3, install all the required packages to do this:

$ sudo apt-get install libffi-dev libbz2-dev liblzma-dev libsqlite3-dev libncurses5-dev libgdbm-dev zlib1g-dev libreadline-dev libssl-dev tk-dev build-essential libncursesw5-dev libc6-dev openssl git

You might have to force install libssl-dev 1.0.2 in order to get pip to work with Python 3.7.2 since apparently you have to have OpenSSL 1.0.2 or 1.1 compatible libssl.

You can check your version of libssl-dev using this command:

$ sudo apt-cache policy libssl-dev

I found a post discussing how he solved this issue by running this install first before compiling Python 3.7.2

$ sudo apt install -t jessie-backports libssl-dev

Download Python 3.7.2 and extract it.

$ wget
$ tar xf Python-3.7.2.tar.xz
$ cd Python-3.7.2

Now configure the directory. It’s important to have the –with-ssl option or openssl wouldn’t be included. This will take a couple of minutes:

$ ./configure --prefix=$HOME/.local --with-ssl --enable-optimizations

Build and install Python 3.7.2. This step takes a long time. On my Raspberry Pi B (not B+) it takes about 30 minutes. DO NOT USE SUDO! Make sure to have the -l 4 option there to keep the error build limit or you’ll encounter problems.

$ make -j -l 4
$ make install

After the installation is done, update ~/.bashrc so that when you type Python3 as a command it will choose Python 3.7.2 over the pre-installed Python 3.4.

$ nano ~/.bashrc

Add the following line at the end of the file. Save and the exit nano.

export PATH=$HOME/.local/bin/:$PATH

You can now close this terminal and open a new one. Launch python3 using the following command and check what version you have. Use exit() to quit Python.

$ python3

You can also check what version of pip3 you have by typing in the command:

$ pip3 --version

Remember to have the 3 at the end of these commands otherwise you’ll launch the default Python 2.7.

If there you have limited space on your Raspberry Pi, you might want to remove all the compile tools and the source code to free up space. Use the following commands. Make sure you are not in the Python-3.7.2 directory where we were doing the compiling.

$ cd $home
$ sudo rm -r Python-3.7.2
$ sudo rm Python-3.7.2.tar.xz
$ sudo apt-get --purge remove libffi-dev libbz2-dev liblzma-dev libsqlite3-dev libncurses5-dev libgdbm-dev zlib1g-dev libreadline-dev libssl-dev tk-dev build-essential libncursesw5-dev libc6-dev openssl git -y
$ sudo apt-get autoremove -y
$ sudo apt-get clean

I want to give credit to the following pages for the original content on how to install Python 3.7.x on Raspbian:

Enjoy Python 3.7.2 on Raspberry Pi!