Skip to content

lancaster-university/microbit-datalogger-ui

Repository files navigation

User Interface for the micro:bit datalogger

GitHub Pages CI

How it works

The micro:bit supports the ability to log data to the internal flash memory of the micro:bit. This can be used by users of the micro:bit to store data such as those gathered from the internal sensors of the board, e.g. the light sensor or microphone.

Users can access this data by plugging their micro:bit into a computer, and accessing the virtual MY_DATA.HTM file. This isn't a 'real' file, rather, the contents of this file is mapped directly to the full flash storage of the micro:bit.

The MY_DATA.HTM file contains a very small, 2048 block header. This contains the actual HTML used to load and render the data into a visual format, allowing users to view, copy, and download their data easily. It's important that this block is as small as possible, to limit how much it is eating into the available flash storage on board the micro:bit. Therefore, the interface contains only essential functionality and limited styling and interactivity. However, the limited interface will attempt to load the full interface, which is contained within this repository. The full interface re-parses the data and loads in-place, removing the existing interface if present.

Ideally, this process should be as seamless as possible, hiding any form of flickering as elements are swapped out, and also should be as quick as possible in comparison to the limited interface.

Bundling

Unlike a traditional React app, we don't control the full HTML stack. Normally, the index.html would be generated by the React tooling, with appropriate script and CSS URLs injected into the header. But in this case, we don't use any HTML files generated from the build process -- the URLs for the main bundle script and stylesheet are instead hardcoded into the offline MY_DATA.HTM source stored within the micro:bit v2 target of its CODAL firmware.

Because of this, a fixed URL for the main bundle .js and .css is required. create-react-app uses a hash in the file name of each bundle. Whilst this could be okay, since we could just hardcode this still, this would greatly limit the flexiblity of updating the interface (requiring CODAL to be adjusted for every rebuild of the interface). We therefore use react-app-rewired, which allows for configuration of the filenames of the built bundles.

Loading the datalogger

The offline MY_DATA.HTM loads the main dl.js bundle. The bootstrap process begins with the index.tsx file.

The offline datalogger exposes a dl (for datalogger) global variable on the window object. This contains a load() function definition. This function is assigned as the callback to the window's onload handler, and is intended to parse and display the data from the log.

The definition for dl.load in the offline datalog also stores the raw log data in dl.raw. But because we also want to load ourself instead of the offline view, we still need to override this. The loading process is therefore as follows:

  • Store a reference to dl.load in a variable (baseLoad)
  • Replace dl.load with our own handler, which sets up React and removes the existing interface elements
  • When dl.load is invoked (onload), first call the offline load method to allow us to retrieve the log data and then do all of the actions listed above

Where is the log data actually stored?

Since MY_DATA.HTM is just a raw span of flash memory, the micro:bit stores the log data in an interesting way.

The first 2048 bytes of this file contain the actual HTML data, with embedded scripts and CSS data. Immediately following the HTML is the actual log data. This log data isn't actually stored within the HTML itself, such as within table elements, as JavaScript does this instead at runtime. Instead, it is stored within a trailing HTML comment, which is accessible using document.documentElement.outerHTML. The end of the 2048 bytes matches up perfectly with the start of this comment. The raw log binary data then follows.

In order to save on storage usage, there is no actual footer for the HTML following the comment. But this is okay, as basically every modern browser will accept the malformed HTML anyway and close everything for us, exploiting it greatly to our advantage.

The best way to understand this further is to make your own micro:bit program, if you can, then log some data, plug it into your computer and have a look at the source of MY_DATA.HTM.

While the online datalogger does make quite a few assumptions about the offline datalogger, it doesn't actually make any assumptions about how the data is stored, meaning this could change in the future without any changes needed in this project.

Checking for data updates

The datalogger uses a mechanism which allows users to update the interface with the latest data without having to manually refresh or reopen the page.

This is provided by the offline datalogger interface. Every 5 seconds, an invisible iframe is spawned which loads the datalogger. This iframe sends through the new data as a cross-frame message to the parent. The parent then calculates the hash of each to compare them. If they don't match, the interface will store the latest data and give the user an option to switch to this new data.

...

...

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages