Photo by Etienne Girardet on Unsplash This is a post I have started to write several times already. First time 2017, then again in 2019 and 2020. I do not remember what was the drama then. Each time I procrastinated and thought things are not that bad yet. Leaving all politics a side, this is not the way the Internet was supposed to be. “The first truth is that the liberty of a democracy is not safe if the people tolerate the growth of private power to a point where it becomes stronger than...| Mika Tuupola
RISC-V is gaining traction and some development boards have already popped up. One of them is the widely available Sipeed Longan Nano. Written information is a bit sparse at the moment. Let’s try to fix this with a quick writeup on wiring and programming the board. If you just want to see what the board can do here is a video instead. Toolchain The situation with RISC-V toolchain is somewhat confusing. There are RISC-V Software Collaboration, RISC-V Software, RISC-V Microcontroller and RISC...| Mika Tuupola
One of the things which makes embedded programming so interesting is that you are constantly dealing with restricted resources. Playing video files is quite resource heavy. Let’s see how ESP32 can handle this. If you have short attention span here is a video instead. RAW RGB565 The easiest compression is no compression at all. Embedded displays are often configured to have RGB565 pixel format. This gives a good compromise between number of colors and bytes needed for one frame. Raw video me...| Mika Tuupola
What started as a project to learn C, I have now been using in all my hobby projects. HAGL is a hardware agnostic graphics library for embedded projects. It supports basic geometric primitives, bitmaps, blitting, fixed width fonts and an optional framebuffer. Yet another graphics library? Most embedded hobbyist projects do not seem to care about code reuse. Instead there is a graphics library for everydifferentdisplaydriver for every different architecture. They all implement the same functio...| Mika Tuupola
My life has come to a full circle. I remember sitting in my parents basement in the late 90’s programming the fire effect using mixture of Borland Turbo Pascal and Assembler. I had an Intel 80386 which also had the 80387 coprocessor. I remember downloading Lode’s graphics tutorials from FidoNet. It was all magic. Last week I found myself reading the same tutorials and creating the same fire effect again. Instead of Intel PC, it was written for ESP32 based M5Stack and using C programming l...| Mika Tuupola
Magnetometers are used to measure the strength of a magnetic field. They can also be used to determine orientation and to compensate gyro drift. Magnetometer provides the last three degrees of freedom in 9DOF sensors. There is one problem though, magnetometers are prone to distortion. Hard iron distortion The magnetic field used for determining the heading is the earth’s magnetic field. In addition to earth’s, there are additional magnetic fields which cause interference. Interference can...| Mika Tuupola
While evaluating M5Stack for a sidehustle project I created a proof of concept which needed to access wifi network, query an API and download an image. Wifi geolocation which displays a static Google map seemed like a perfect fit. Here are some notes about it. This project is based on the M5Stack kitchen sink. Development was done using Loboris fork of MicroPython. Finished code can be found in GitHub. Load Settings The program starts by loading settings from json file. This file contains con...| Mika Tuupola
M5Stack is an absolutely beautiful ESP32 based enclosure and development board. It has 320x240 TFT screen, three buttons, sd card slot, Grove I2C connector and can be powered with LiPo battery. Download the Micropython Firmware You could download the MicroPython firmware from the downloads page. But why bother when we have the commandline. First find the download link. $ curl --silent http://micropython.org/download | grep "firmware/esp32" | gawk -F'<a +href="' -v RS='">''RT{print $2}'http://...| Mika Tuupola
WiPy is a bit pricey but good quality ESP32 development board from Pycom. I got mine from Pimoroni. Pycom does offer their own firmware updater but for my taste it has too much magic going on. I prefer to do things from commandline and I stay in control and to see exactly what update is doing. Quick Googling did not reveal anything so here is my upgrade procedure. Download the Latest Pycom Firmware For starters we need to find the latest Pycom firmware. Links can be found from their forums. O...| Mika Tuupola
Branca is a catchy name for IETF XChaCha20-Poly1305 AEAD message with an additional version number and timestamp. It is well suited to be used as an authenticated and encrypted API token. Branca specification does not specify the payload format. Among others you can use for example JWT payloads but still have modern encryption and smaller token size provided by Branca. Currently there are implemenations for JavaScript, Elixir, Go and PHP and a command line tool for creating and inspecting tok...| Mika Tuupola
The popularity of WiFi networks has been rising rapidly during the last 15 years. In urban areas hotspots are ubiquous. These hotspots together with trilateration algorithms provide a cheap way to find out yours or someone elses location. Because of my previous work with Apple location services I wanted to figure out how trilateration works. Being a school dropout I am really really bad in mathematics. However I consider myself good at trial and error so I reckon this should be doable. Where ...| Mika Tuupola
Updates: Added new pdf link to the end (2017-05-11). Header is actually length-prefix framed byte strings (2017-05-13). While working on Whereami I got interested on how Apple location services actually work. I know it is handled by locationd since Little Snitch keeps blocking it. Usual way of inspecting traffic with proxychains did not work since macOS now has something called System Integrity Protection (SIP). Alternative way was to setup Charles as MITM proxy for an iOS device. After looki...| Mika Tuupola
Comparing the good old jQuery with modern alternatives. Fetch is an upcoming native standard. Axios is an elegant promise based HTTP client. In the end everything is wrapped together with Vue.js to create an example online base62 decoder. Creating a Simple API For demonstrating purposes lets create a simple JSON API. You can also call it a REST API but that might end with endless discussion on what is REST and what is not. As a basis I used a slimmed down version of Slim 3 API Skeleton. $ com...| Mika Tuupola
HTTP Basic Authentication middleware comes with simple PDO authenticator. It can be used to authenticate users from database. Authenticator assumes username and hashed password are stored in database. Default name for database table is users. Default column names for username and hash are unsurprisingly user and hash. Column and table names can also be set in options. Hash must be created with password_hash() function. Simplest possible table to store user data looks something like this. CREA...| Mika Tuupola
There are two kinds of people. Those who like their accessors and mutators to start with get and set. This is also what PHP-FIG seems to suggest. $unicorn =newUnicorn(); $unicorn->setBirthday("1930-24-12")->setColor("rainbow"); print $unicorn->getAge(); It works well with IDE autocompletion. It is also easy to write API documentation using PHPDoc. Then there are those like me who prefer to leave get and set out. $unicorn =newUnicorn(); $unicorn->birthday("1930-24-12")->color("rainbow"); print...| Mika Tuupola
Chained is now stable and in feature freeze. In 2.x version class support will be removed. Next major version will use data attributes will be used instead. After all, it is 2014 already! Legacy syntax removed Stable version removes legacy syntax. It is not 100% compatible with 0.9.x branch. You must pass all options to remote version as JavaScript object. Example of all possible options below. $("#series").remoteChained({ parents:"#mark", url:"/api/series.json", depends:"#series", loading:"L...| Mika Tuupola
Grab a Flat UI theme for TextMate 2 and Sublime Text. It is based on colors of the amazing Flat UI Pro framework made by Designmodo. Theme is for oldschool hackers who prefer their terminal windows to be green or yellow on black. It offers just enough highlighting without looking like a rainbow. ** NOTE! ** Designmodo link above contains my referral code. If you buy something from them I will get a reward and be a happy puppy. Textmate 2 To install download the zipped bundle. Unzip it and dou...| Mika Tuupola
New version of Chained mostly updates the remote version. Plugin now supports both Zepto and jQuery. You can avoid initial AJAX requests by bootstrapping select values. You can configure extra values to be sent to server. Since plugin now accepts more configuration options new prettier syntax was implemented. Lastly support for Bower was added. Zepto support Since plugin uses :selected you must also include Zepto selector extension. It is not included by default. <scriptsrc="zepto.js"></scrip...| Mika Tuupola
You can now lazyload CSS background images. Bind the plugin to non image element and it will automatically change the background-image style attribute when element is scrolled into view. You can also use effects. <divclass="lazy"data-original="img/bmw_m1_hood.jpg"style="background-image: url('img/grey.gif'); width: 765px; height: 574px;"></div> $("div.lazy").lazyload({ effect : "fadeIn" }); Optional placeholder image The placeholder image is now optional. If you omit it plugin will use the de...| Mika Tuupola
This version of Lazy Load is just a bugfix release. Minor release number bump is there because I pulled a new feature in last minute and I did not want to mess up my git branching. Bugfix usually does not normally warrant for the minor bump. Bugs fixed Plugin now works correctly when using many instances and they have different container. $("#column-1 img").lazyload({ container:$("#column-1") }); $("#column-2 img").lazyload({ container:$("#column-2") }); $("#column-3 img").lazyload({ containe...| Mika Tuupola
Previous version of Lazy Load gained traction pretty fast. Good patches were submitted to GitHub. This version of plugin mostly concentrates on speed optimization and event handlers. New Events Two new events were added. Handler for appear event is called when image appears to viewport but before it is loaded. Handler for load event is called when image is loaded. Both event handler receive two parameters. First parameter elements_left is numbers of images left to load. Second parameter setti...| Mika Tuupola
595 series shift registers come in many flavors. SN74HC595 is the most usual. TPIC6B595 is similar but can be used with more power hungry applications. Pin layouts are different but they all operate in the same way. Shift register is controlled with three pins. They are usually called DATA, LATCH and CLOCK. Chip manufacturers have different names. See the table below for two examples from Texas Instruments. 74HC595TPIC6B595 DATASERSER IN LATCHRCLKRCK CLOCKSRCLKSRCK CLOCK is an constant high -...| Mika Tuupola
Led matrices are fun toys. Who would not love blinkenlights? Electronics is hard. Electronics is much harder than programming. I had hard time trying to understand how do the led matrices work. What is best way to learn something? Build one yourself. Structure of Led Matrix In a matrix format LEDs are arranged in rows and columns. You can also think of them as y and x coordinates. Lets assume we have 4x4 matrix. Rows would be marked from A to D and columns from 1 to 4. Now we can address each...| Mika Tuupola
Heads up! This article was written in 2011 and it exists mostly for historical purposes. When Apple released iOS 4.2 end of last year I was on a boat trip to Finland. For me the most interesting features were added to Safari browser. I wanted to learn about WebSockets. New DeviceOrientation API just begged to be abused. I had an idea to control the content of laptop browser by tilting and rotating the phone. I had working but ugly code before ship arrived to Helsinki. If you have short attent...| Mika Tuupola
Heads up! This article was written in 2008. The theory itself is still good but the demos are currently broken. Static Maps API has URL length limit of around 2048 characters. You can hit this limit quickly when adding lot of markers. You can keep URL short by clustering markers together. Square Based Clustering Clustering is usually done by dividing map to squares. Square size depends on map zoom level. Markers inside a square are then grouped into cluster. This technique has some limitation...| Mika Tuupola
Heads up! This article was written in 2008 and it exists mostly for historical purposes. Most of the code from previous Static Maps experiments is now put into one clean package. Previously I showed you how to work with markers and bounds. Now we go forward and add zoom and pan controls. It takes only few lines of code. If you just started reading the series check the theory how it works. As a bonus lets add infowindows / bubbles too. Note! Image above is just a screenshot. You can test final...| Mika Tuupola
Heads up! This article was written in 2008 and it exists mostly for historical purposes. Lately I have been playing with Google Static Maps API a lot. Writing the same things again and again is tedious job. I decided to put the code together as one clean extendable package. Writing object oriented interface for generating URL is trivial. Real meat is having working zoom and pan controls on static map with just 9 lines of code (demo now includes also clickable markers and infowindows). Code is...| Mika Tuupola
Heads up! This article was written in 2008 and it exists mostly for historical purposes. Previously I showed you how to make a Google Static Map with clickable markers. Several people emailed me to ask how to show infowindow (or infobubble) when marker is clicked. Technique I explain below still needs JavaScript. It is used to open the infowindow. I use jQuery library in the examples. Image above is just a screenshot. There is a separate page for working demo. Full source code is also availab...| Mika Tuupola
Heads up! This article was written in 2008 and it exists mostly for historical purposes. Static map is one big image. Markers are embedded inside the image. You can not use traditional <a href="#"> tags around separate markers. Binding onclick event to separate marker images wont work either. There are no separate markers. Just one large image. With imagemaps you can specify arbitary areas inside an image which links to given url. Area can be circle, rectangle or polygon. Simple imagemap coul...| Mika Tuupola
In previous part we made a Google Map with sidebar navigation which works even JavaScript turned off. Marker locations and sidebar were parsed from two KML files. Beginning Google Maps Applications is a great book to learn about KML and Google Maps in general. In this second part of tutorial I show you how to add zoom and pan controls. Again, they work without JavaScript. Be sure to read tutorial part one first. Also check the live demo. Before going forward I would like to answer a question...| Mika Tuupola
We recently did a small Google Maps application for ERGO insurance. It consisted of submitting all their offices to Google Maps. KML export of office data was used to create map at ERGO autoabi campaign site. First version used all JavaScript approach to create the sidebar and map on the page. I was not happy with it. Map page was empty for browsers with JavaScript disabled. Page also took too long to render. Two problems I could not ignore. Second version was mixture of PHP, JavaScript and n...| Mika Tuupola
This library implements Base32 encoding. In addition to integers it can encode and decode any arbitrary data. Install Install with composer. $ composer require tuupola/base32 Usage This package has both pure PHP and GMP based encoders. By default encoder and decoder will use GMP functions if the extension is installed. If GMP is not available pure PHP encoder will be used instead. $base32 =newTuupola\Base32; $encoded = $base32->encode(random_bytes(128)); $decoded = $base32->decode($encoded); ...| Mika Tuupola
Chained is simple plugin for chained selects. It works with both jQuery and Zepto. You can choose from two different versions. Use jquery.chained.js if you do not want to make external queries for setting content of child selects. This version uses data attirbutes to decide the content. For more complex scenarios maintaining data attributes will get cumbersome. Also if you want to make queries against database use jquery.chained.remote.js instead. This version makes an external AJAX query and...| Mika Tuupola
This library implements the K-Sortable Globally Unique IDs from Segment. See also the article called A Brief History of the UUID. KSUID is for K-Sortable Unique IDentifier. It’s a way to generate globally unique IDs similar to RFC 4122 UUIDs, but contain a time component so they can be “roughly” sorted by time of creation. The remainder of the KSUID is randomly generated bytes. Install Install with composer. $ composer require tuupola/ksuid This branch requires PHP 7.1 or up. The older ...| Mika Tuupola
Simple Serial Communications With AVR libc| www.appelsiini.net