{"id":15463658,"url":"https://github.com/hixie/localbit","last_synced_at":"2025-06-23T19:03:25.012Z","repository":{"id":38831175,"uuid":"139934884","full_name":"Hixie/localbit","owner":"Hixie","description":"Alternative software for the Littlebits w20 cloudbit module that talks directly to a local network server instead of to the Littlebits cloud.","archived":false,"fork":false,"pushed_at":"2024-03-22T22:42:18.000Z","size":131,"stargazers_count":36,"open_issues_count":5,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-10-18T21:59:11.252Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hixie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-06T04:56:10.000Z","updated_at":"2024-10-17T07:31:27.000Z","dependencies_parsed_at":"2024-12-12T14:37:44.988Z","dependency_job_id":"66b5f1b3-91d2-42ad-9502-59bf7096ad28","html_url":"https://github.com/Hixie/localbit","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"7b5649f936f8a1b436d9dcbd003bcb27ee308706"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hixie%2Flocalbit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hixie%2Flocalbit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hixie%2Flocalbit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hixie%2Flocalbit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hixie","download_url":"https://codeload.github.com/Hixie/localbit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232965379,"owners_count":18603802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T00:22:46.833Z","updated_at":"2025-01-08T02:31:24.459Z","avatar_url":"https://github.com/Hixie.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Local Network Cloudbit\n\n## Introduction\n\nThe [Littlebits w20 cloudbit\nbit](https://shop.littlebits.com/products/cloudbit) is a great idea:\nit allows your Littlebits circuits to be connected to the Internet,\nthus letting you integrate your contraptions with other services such\nas Google Home (via IFTTT) or even your own homegrown home automation\nsystems. Unfortunately, the [Littlebits\nCloud](http://control.littlebitscloud.cc/) is very unreliable. For\nsomething like this to work, you really need near-100% uptime, and in\nmy experience the API has an uptime of about 70%, sometimes being down\nfor weeks at a time.\n\nIn any case, it's a little crazy that a little circuit on your network\nshould communicate with a remote server if all it wants to do is tell\nyour Raspberry Pi on the other side of the room what the temperature\nis or when a button gets pushed or when your laundry washing machine\nhas finished.\n\nThe cloudbit is just an embedded Linux computer, though, and\nLittlebits kindly left a C compiler and a Perl interpreter on it, so\nexperimenting with the cloudbit is pretty straight-forward and solving\nthe problem of having to talk to the Internet just to send a message\nsix meters across the room is emminently addressable.\n\n\n## Communicating with the local network instead of the cloud\n\nThis repository contains a replacement for the default behaviour of\nthe cloudbit, so that instead of reporting the current value of the\ncloudbit to the Littlebits servers, it just sends it to a specified\nlocal server.\n\nThere are three ways to install this program. In all three cases, you\nwill need a machine where you can mount ext2 file systems (e.g. a\nLinux box, or a Mac using [FUSE for\nmacOS](https://osxfuse.github.io/)). Then, you either:\n\n * Use a bash shell to a script from this repository to complete the\n   installation automatically.\n\n * Walk through the script's steps manually.\n\n * Enable SSH access on the cloudbit, then SSH into the cloudbit and\n   install the software directly there using the script from the\n   repository.\n\n\n## Commissioning the cloudbit\n\nBefore you do anything described below, first make sure your cloudbit\nis configured for your local network. The steps below disable the\nLittlebits code that allows you to configure the network by pushing\nthe button on the cloudbit. To reconfigure the cloudbit after setting\nthings up as below, you will either need to reinstall the firmware\nusing the Littlebits updater, or manually figure it out.\n\nYou may also want to take note of the cloudbit's MAC address, since\nthat is used to identify the cloudbit.\n\n\n## Mounting the SD card\n\nThe details for mounting the SD card vary from system to system.\nConsult your local documentation (e.g. the `mount` program on Unix\nsystems) for instructions on doing this.\n\nThe SD card seems to have three partitions; you only need the third\none (the biggest one) which is where the Linux userspace filesystem is\nstored.\n\n\n## Installing automatically\n\n_You will need: bash, sudo, curl, grep, git, mkdir, mv, ln_\n\n_This has only been tested on Linux. It may work on other Unix-like\nsystems such as macOS, but this is untested._\n\nOnce you have the SD card mounted, run the command below.\n\nThis command prompts for your root password (because of the `sudo`).\nThis is necessary because the filesystem you have mounted has files\nthat are only writable by `root`. If you have configured your SD card\nto be mounted so that it is user-writable on your host but will create\nfiles that have `root` as the owner when run by the cloudbit, then you\ncan omit the `sudo`.\n\nIt's generally considered very sketchy to pipe a program from the\nnetwork into `sudo bash`; even piping it into bash without the `sudo`\nisn't great since it can compromise your account. The shell script\ndownloads a binary onto your cloudbit; that binary could also be\ncompromised. I highly recommend going through the more tedious manual\nprocess below instead, that way you have much more control over what\nexactly is going on.\n\nBut if you're ok with trusting me and GitHub and are sure you're not\nexperiencing a state-level attack on your communications or some other\nsuch thing, then run the following command, replacing\n`server.example.com` with the name of the host to which you want to\nsend the network messages, in a shell open to the root directory of\nthe mounted SD card filesystem:\n\n```\ncurl https://raw.githubusercontent.com/Hixie/localbit/master/install.sh | sudo bash -s server.example.com\n```\n\nThen, unmount the SD card, install it back in your cloudbit, and boot\nup your cloudbit. If everything worked, the LED should turn off once\nit has booted, and network traffic will start flowing to port 2020 of\nthe host you specified on the command line above. If the LED turns any\ncolour other than white, then something went wrong (unless you are\nalready sending your own packets to the cloudbit!).\n\n### Security considerations\n\nThe script above disables the routing tables that keep the cloudbit\nsafe from being attacked (it has to, since the whole point is to\nlisten to UDP connections). It's possible that this will expose you to\nsome vulnerability in some software running on the cloudbit.\n\n\n## Installing manually\n\nA technically safer alternative to the above is to walk through the\nfollowing steps. You can either do it over SSH on the device itself,\nor on the SD card directly.\n\nThe file `/usr/local/lb/etc/lb_scripts.conf` on the SD card ends with\na line that identifies the firmware version you are using. This\nrepository assumes you are using version 1.0.150603a, which as of the\ntime of writing is the latest version. If necessary, you can download\nupdates from\n[littlebits.com](https://littlebits.com/cloudbit-firmware).\n\n\n### Setting up SSH access for a w20 cloudbit\n\n_If you are going to set everything up on the SD card directly, you\ncan skip this step._\n\nPrior art:\n[Chris Wilson](https://github.com/yepher/littlebits/blob/master/CloubitFileSystem.md),\n[chobie](https://qiita.com/chobie@github/items/d41cfa2d60df5d7d1a3f),\n[rhomel](https://gist.github.com/rhomel/0598aa7c63e61001e63f).\n\nTo enable SSH, you need to make three changes: changing the root\npassword, enabling the SSH service, and turning off iptables.\n\nThere's one user account set up, the root account. To change its\npassword, use `mkpasswd -m sha-512` to generate a new hash, and then\nedit `/etc/shadow` and replace the hash (between the first two colons)\nfor the `root` user with the new hash. The password you give\n`mkpasswd` will be the password you use to log in to your cloudbit.\n\nTo enable SSH, first edit `/etc/ssh/sshd_config`. There are two lines\nto change. First, uncomment the line that says `PermitRootLogin yes`,\notherwise it will default to \"no\", which, as you might guess, disables\nlogin. The other line to change is the one that says `UsePAM yes`;\nchange that to `UsePAM no`. The Pluggable Authentication Module (PAM)\ninterface overrides the root login setting.\n\nNext, enable it by setting up symlinks in the\n`/etc/systemd/system/multi-user.target.wants/` directory as follows:\n\n```\nsudo ln -s /usr/lib/systemd/system/sshdgenkeys.service sshdgenkeys.service\nsudo ln -s /usr/lib/systemd/system/sshd.service sshd.service\n```\n\nFinally, you have to turn off iptables. Create a `disabled`\nsubdirectory in the `/etc/systemd/system/multi-user.target.wants/`\ndirectory, and then move the `iptables.service` file in\n`/etc/systemd/system/multi-user.target.wants/` into this new\n`disabled` directory.\n\nOnce you are SSH'ed into the cloudbit, you can either continue\nfollowing these steps, or you can run the `install.sh` script\nmentioned above (using the same instructions as above) to have the\nscript do them for you. This is slightly safer than running the script\non your machine, since if your cloudbit gets compromised, you only\nlose your cloudbit, instead of your workstation.\n\n\n### Configuring the local control client on the cloudbit device\n\nYou must specify the host name of the server to which messages will be\nsent in `/root/localbit_server.cfg`. This file should contain only the\nhost name optionally followed by a newline character, and nothing\nelse.\n\nFrom the root of the SD card filesystem (either after SSHing into the\ncloudbit, or on your host with the SD card mounted), run the\nfollowing, replacing \"server.example.com\" with the host name that you\nwill be running your server on:\n\n```\necho server.example.com \u003e root/localbit_server.cfg\n```\n\n\n### Fetching the code\n\nThe code for the localbit software is on GitHub.\n\nFrom the root of the SD card filesystem (either after SSHing into the\ncloudbit, or on your host with the SD card mounted), run the following\nto download it to your SD card:\n\n```\ngit clone https://github.com/Hixie/localbit.git root/localbit\n```\n\nIf you are running this on your host and have mounted the SD card\nnormally (i.e. honouring the permissions on the SD card), you may need\nto run this with `sudo` since the SD card filesystem's `/root/`\ndirectory is only writable by root.\n\nThe code for the program that sits between the cloudbit hardware and\nthe network is in\n[`localbit.c`](https://github.com/Hixie/localbit/blob/master/localbit.c).\n\n\n### Compiling the code\n\nA compiled binary of localbit.c suitable for use on machines with the\narchitecture of cloudbits is also in this repository. However, if you\nwould prefer to compile it yourself, you may do so by SSHing into the\ncloudbit and using the conveniently preinstalled `gcc` that Littlebits\nprovides.\n\nRun this command in the `/root/localbit` directory (the one you\ndownloaded from git above) to regenerate the binary. You must be SSHed\ninto the cloudbit for this to work. In theory you could also\ncross-compile from your host to the architecture of the cloudbit, but\nthat is left as an exercise for the reader.\n\n```\ngcc localbit.c -lm -o localbit\n```\n\nIf you are compiling your own version, consider using `-O3` or\n`-Ofast`. The version provided in the repository is currently compiled\nwith `-Ofast`, mostly to conserve power so that the bit doesn't heat\nup too much.\n\n\n### Turning off the built-in programs\n\nIf you followed the instructions earlier for enabling SSH, you will\nhave created a `disabled` subdirectory in the\n`/etc/systemd/system/multi-user.target.wants/` directory on the\ncloudbit SD card. If you did not do that, then do it now.\n\nThen, move the following files from\n`/etc/systemd/system/multi-user.target.wants/` into this `disabled`\ndirectory:\n\n* `iptables.service` (you will already have moved this if you enabled SSH)\n* `ADC.service`\n* `LEDcolor.service`\n* `button.service`\n* `dac_init.service`\n* `dac.service`\n* `netctl-monitor.service`\n* `onboot.service`\n\nBe aware that this will disable a number of features of the cloudbit:\n\nRemoving `button.service` disables the commissioning script (holding\ndown the button won't do anything anymore; normally `button.service`\nruns a program that watches the button and triggers the commissioning\nscript if the button is help for long enough). If you ever need to\nupdate the wifi configuration of this device, move these files back\ninto `/etc/systemd/system/multi-user.target.wants/` first.\n\nRemoving `netctl-monitor.service` will prevent `monitorNetctl.pl` from\nrunning. That script is mainly in charge of managing the program that\nsends the status of the cloudbit to the cloud, but, among other\nthings, it also runs the command that enables the network and sets the\nsystem clock (there's no clock battery on the cloudbit).\n\nRemoving `dac_init.service` will prevent `DAC_init` from running at\nstartup, and that program must be run before any code uses the DAC.\n\nThe other services all implement various features mostly used by the\nthree called out explicitly above.\n\nAs a replacement for all the above, this repository comes with a short\nshell script that enables the network, sets the date and time, and\ncalls the `DAC_init` program. To install it, run the following command\ninside the `/etc/systemd/system/multi-user.target.wants/` directory:\n\n```\nsudo ln -s /root/localbit/localbit-startup.service localbit-startup.service\n```\n\nThis script will log to `/var/log/localbit-startup` if you are curious\nto see how successful it is.\n\nThis script does require internet access. It tries to ping `8.8.8.8`\n(a Google DNS server) to test if the network is operational, and uses\nNTP time servers to update the clock. (It honours the\n`/usr/local/lb/etc/lb_scripts.conf` script, in particular to determine\nwhich NTP server to use (`NTP_SERVER`), which IP address to ping to\ntest the network (`PING_DEST`), and the directories to use to find the\nLittlebits binaries.)\n\n\n### Turning on the localbit program\n\nTo automatically run the localbit binary and keep it running, run the\nfollowing inside the `/etc/systemd/system/multi-user.target.wants/`\ndirectory:\n\n```\nsudo ln -s /root/localbit/localbit-daemon.service localbit-daemon.service\n```\n\nThis script runs the `localbit` binary compiled above, which listens\nto the ADC and the button and reports their status to the network, and\nlistens to the network for commands for changing the status of the\noutput and the LED.\n\nIf you want to turn it off, e.g. so that you can hack on it, run\n`systemctl stop localbit-daemon`.\n\n\n## The localbit network protocol\n\nThe protocol uses UDP.\n\nThe localbit program running on the cloudbit periodically sends the\nfollowing packet to the configured host on UDP port 2020:\n\n * 6 bytes of the cloudbit's MAC address.\n * 2 byte word in network byte order (big-endian) which is 0x0001 if\n   the button is pressed and otherwise 0x0000.\n * 2 byte word in network byte order (big-endian) representing the\n   input (0x0000 to 0xFFFF). The value is only significant to about\n   about 10 bits, and even the last two of these \"significant\" bits\n   fluctate a lot, so if 8 bit precision is enough, you can just treat\n   the first of these two bytes as the value in the range 0 to 255 and\n   ignore the second byte.\n\n```\n 00 01 02 03 04 05 06 07 08 09\n+--+--+--+--+--+--+--+--+--+--+\n|   MAC ADDRESS   |00| B| VAL |\n+--+--+--+--+--+--+--+--+--+--+\n  Button state --------'   |\n  Input value -------------'     16 bit word, big-endian.\n\nButton state:\nMSB                   LSB\n+--+--+--+--+--+--+--+--+\n|  |  |  |  |  |  |  |SS|\n+--+--+--+--+--+--+--+--+\n  State --------------'          Whether the button is set.\n                                 0x00 = no, 0x01 = pressed\n\n```\n\nThe localbit program listens for UDP packets on port 2021. If they\nstart with 6 bytes that match the cloudbit's MAC address, then the\nnext byte is examined. This is the LED state byte. If this byte's 8th\nbit is set (0x80), then then bits 1 through 3 of the LED state byte\nare interpreted as the red, green, and blue channels for the LED\nrespectively. The byte after this is the output state byte. If the\nhigh bit is set, then the next two bytes are interpreted as the 16 bit\nvalue in network byte order (big-endian) to which to set the output\n(0x0000 to 0xFFFF).\n\n```\n 00 01 02 03 04 05 06 07 08 09\n+--+--+--+--+--+--+--+--+--+--+\n|   MAC ADDRESS   |LL|OO| VAL |\n+--+--+--+--+--+--+--+--+--+--+\n  LED state -------'  |    |\n  Output state -------'    |\n  Output value ------------'     16 bit word, big-endian.\n\nLED state:\nMSB                   LSB\n+--+--+--+--+--+--+--+--+\n|CC|  |  |  |  |RR|GG|BB|\n+--+--+--+--+--+--+--+--+\n '---- Control  |  |  |          Whether to change the LED.\n  Red ----------'  |  |          If CC is set, new red channel state.\n  Green -----------'  |          If CC is set, new green channel state.\n  Blue ---------------'          If CC is set, new blue channel state.\n\nOutput state:\nMSB                   LSB\n+--+--+--+--+--+--+--+--+\n|CC|  |  |  |  |  |  |  |\n+--+--+--+--+--+--+--+--+\n '---- Control                   Whether to change the output value.\n```\n\nThe rate of messages being sent from the cloudbit increases if the\ninput's value fluctuates or if the button is pressed, and decreases if\nthe input's value remains steady. This is implemented by inserting a\ndelay in the program loop. If the input's value is seen to fluctate\ndramatically, the delay is set to its minimum value immediately; if\nthe rate of change is slow, then the delay is decreased by 10ms; if\nthe value barely changes at all, then the rate is increased by 10ms up\nto the maximum delay.\n\nThe fastest rate at which messages are being sent (e.g. while the\nbutton is being held down), is 100Hz (one message every 10ms). The\nslowest rate is about 0.5Hz (a delay of 2010ms).\n\nA new message is always sent immediately when one is received, without\naffecting the steady state rate, so the value may be polled by sending\na message with the two control bits set to zero (i.e. a ten byte\nmessage consisting of the six MAC address bytes followed by four zero\nbytes). The minimum delay is still enforced; at most one packet is\nconsumed every 10ms.\n\nThis variable rate is intended to keep the load on the cloudbit CPU to\na reasonable level so that the cloudbit can run continually with\nminimal risk of damage. Be wary of sending polling messages at a high\nrate continually since doing so defeats this mitigation.\n\n\n## Practical considerations\n\nOn a local network, realistically, the highest signal frequency you\ncan expect to send to the cloudbit with any sort of accuracy is about\n2Hz, with a latency of anything from 20ms to 100ms.\n\nThe following images show some oscilloscope traces of the input going\ninto the cloudbit and the output coming from the cloudbit, for a\nsquare wave signal that is being reflected back to the cloudbit over\nthe local network, at the highest rate that localbit will operate\n(100Hz), in close-to-ideal network conditions. The first is for an\ninput wave of 2Hz, the second for an input wave of 15Hz.\n\n![At 2Hz, the output signal is delayed but vaguely resembles the input.](scope_2Hz.jpeg)\n![At 15Hz, the output signal has much more noticeable gaps and irregularities.](scope_15Hz.jpeg)\n\n\n# Notes on the w20 cloudbit\n\nThe remainder of this file consists of notes I made while\nreverse-engineering the cloudbit.\n\n## Hardware\n\nAccording to `/proc/cpuinfo` and `/proc/meminfo`, the cloudbit has a\ncARM926EJ-S rev 5 (v5l) processor (113.04 BogoMIPS), 59844 kB of\nRAM, and a ~2.6GB SD card.\n\nThe schematic for the cloudbit is available [on\nGitHub](https://github.com/littlebits/w20-cloud/raw/master/hardware/LB_BIT_w20_cloudV1-(3_3)OHW/w20-cloudV1-(3_3)OHW.pdf).\n\nThe hardware is controlled from code by manipulating memory locations,\nas described below. The hardware is physically connected to pins on\nthe chip on the cloudbit. It's not clear to me how the pins map to\nmemory locations.\n\nThe cloudbit ships with some proprietary Littlebits programs. To\ndetermine their behaviour, a program such as\n[retdec](https://retdec.com/) is invaluable.\n\n\n### The LED\n\nThe program `/usr/local/lb/LEDcolor/bin/LEDcolor.d`, which is run when\nthe cloudbit boots, opens a Unix domain socket\n(`/var/lb/SET_COLOR_socket`), and executes commands written into that\nsocket to change the colour of the LED.\n\nThe program `/usr/local/lb/LEDcolor/bin/setColor` writes commands\ngiven on its command line to that socket.\n\nThe commands are colours, e.g. specifically `red`, `green`, `blue`,\n`yellow`, `teal`, `purple` (or `violet`), and `white`, the command\n`off` which turns off the LED entirely, the two commands `blink` and\n`hold` which stop and start a periodic timer that switches between the\ncurrent colour and `off`, and the command `clownbarf` which I'll leave\nas a surprise. The command `off` has no effect if a `blink` is in\neffect, and `blink` has no effect if `off` was the last colour\ntriggered. Setting a colour seems to reset the blink timer, with the\nLED enabled.\n\nThe 2KB page starting at 0x80018000 is used by the `LEDcontrol.d`\nprogram to control the LED. This will be called _gpioPage_ below.\n\nWhen the program starts, it sets the following memory locations to the\nfollowing values, in the following order:\n\n| Address             | Value      |\n|---------------------|------------|\n| _gpioPage_ + 0x0114 | 0xF0000000 |\n| _gpioPage_ + 0x0134 | 0x03000000 |\n| _gpioPage_ + 0x0704 | 0x40000000 |\n| _gpioPage_ + 0x0714 | 0x10000000 |\n\nI've no idea what these values do.\n\nThe LED is controlled by three lines, red, green, and blue, which can\nbe turned on or off. To turn one of the lines on, you send the value\nto the address to turn on, and to turn it off, you send the value to\nthe address to turn it off.\n\n| Color | Address to turn on  | Address to turn off | Value      |\n|-------|---------------------|---------------------|------------|\n| Red   | _gpioPage_ + 0x0508 | _gpioPage_ + 0x0504 | 0x80000000 |\n| Green | _gpioPage_ + 0x0508 | _gpioPage_ + 0x0504 | 0x40000000 |\n| Blue  | _gpioPage_ + 0x0518 | _gpioPage_ + 0x0514 | 0x10000000 |\n\nThese channels correspond to pins 128, 127, and 91 respectively on the\nbig box on the schematic.\n\n\n#### Areas for further research\n\nI haven't tested to see if you can read the addresses listed above. I\nhaven't tested what happens if you try to read or write nearby\naddresses, or set values other than those listed above (except I did\nonce try to set one of those addresses to 0xFFFFFFFF and the wifi\ndropped until I rebooted the device, though the device itself was\nstill executing code, which I could tell because the LED was still\nblinking).\n\n\n### Analog-to-digital convertor (input)\n\nAs with the LED, the ADC is controlled by a program\n`/usr/local/lb/ADC/bin/ADC.d`, which is run when the cloudbit boots,\nand which opens a Unix domain socket (`/var/lb/ADC_socket`). When a\nmessage is written to the socket, it outputs the current value of the\ninput to the socket.\n \nThe program `/usr/local/lb/ADC/bin/getADC` interacts with this socket.\nYou give it an arbitrary argument, such as `-1`, and it outputs two\nlines each containing a number. The first is a number in the range 0\nto 255 which corresponds to the input being in the range 0.0V to 5.0V.\nThe second is a number if the range 0 to 15 and I've no idea what it\ncorresponds to, except that when the input is off it's 0, when the\ninput is on full it's 15, and when the input is between those it\nvaries wildly between those two numbers (seemingly not with any\ncorrelation to the input value).\n\nThe 2KB page starting at 0x80050000 is used by the `ADC.d` program to\nread the input. This will be called _adcPage_ below.\n\nWhen the program starts, it sets the following memory locations to the\nfollowing values, in the following order (note that the values are not\nin ascending order):\n\n| Address            | Value      |\n|--------------------|------------|\n| _adcPage_ + 0x0008 | 0x40000000 |\n| _adcPage_ + 0x0004 | 0x00000001 |\n| _adcPage_ + 0x0028 | 0x01000000 |\n| _adcPage_ + 0x0014 | 0x00010000 |\n| _adcPage_ + 0x0034 | 0x00000001 |\n| _adcPage_ + 0x0024 | 0x01000000 |\n| _adcPage_ + 0x0144 | 0x00000000 |\n\nI've no idea what these values do. It's worth noting that there's also\ncode in `ADC.d` to do something with memory at address 0x80068000,\nthough it doesn't appear to actually be used.\n\n\u003e Updating the system memory with the values above is not sufficient\n\u003e to make the ADC work. If you set the values above then read the ADC\n\u003e values as described below, the program will hang. However, if you\n\u003e run `ADC.d`, then kill it, then read the value as described below,\n\u003e it works fine. I have no explanation.\n\nTo read the ADC value, it sets the value at _adcPage_ + 0x0004 to\n0x00000001, waits until the high bit of the 32 bit word at _adcPage_ +\n0x0050 changes value, then sets the value at _adcPage_ + 0x0018 to\n0x00000001. The value of the ADC is the low 31 bits of the 32 bit word\nat _adcPage_ + 0x0050. (Actually, more like the low 11 bits.)\n\nThe value appears to be a number in the range ~200\u0026plusmn;1 (when the\ninput is at 0V) to ~1700\u0026plusmn;10 (when the input is at a nominal 5V,\nthough it sometimes dips as far as ~1660 or so even when the input is\nsupposedly fully on).\n\nPins 115 and 108 on the schematic, labeled LINE1_INL and LRADC0\nrespectively, are connected to SIGIN1, which corresponds to the input\nside bitSnap, which is the input to the ADC.\n\n\n#### Areas for further research\n\nI haven't determined what `ADC.d` does that needs to be done to\nactually read the ADC.\n\n\n### Digital-to-analog convertor (output)\n\nThe pattern repeats itself with the DAC, but with a bit of a twist.\n\nWhen the cloudbit boots, it first runs\n`/usr/local/lb/DAC/bin/DAC_init`, which does a bunch of memory\nmanipulation that I haven't tried to understand.\n\nThere is a socket-listening program, `/usr/local/lb/DAC/bin/DAC.d`,\nwhich is run when the cloudbit boots, after `DAC_init`. It opens a\nUnix domain socket (`/var/lb/DAC_socket`) and listens to it. When a\nmessage is written to the socket, it tries to parse it as up to four\nhexadecimal digits (0-9, a-f; case-insensitive), and then sets the\noutput of the cloudbit to a voltage by doing a linear mapping from the\nrange 0x0000 to 0xFFFF to the range 0.0V to 5.0V. If the message is\nnot one to four hexadecimal characters, it is ignored.\n\nThe program appears to try to log errors to `/var/lb/dacerrorlog`\nthough I haven't ever seen that file be non-empty.\n \nThe program `/usr/local/lb/ADC/bin/setDAC` interacts with the\naforementioned socket by just passing whatever argument it is given to\nthe socket (unless it's `--help`, in which case it outputs a mostly\nuseless help message instead).\n\nThe 2KB page starting at 0x80050000 is used by the `DAC.d` program to\nset the output. This will be called _dacPage_ below. (The `DAC_init`\nprogram also uses that page as well as two other pages.)\n\nThere are two addresses that are used by `DAC.d` as far as I can tell.\nThe first is _dacPage_ + 0x00F0, which is used to set the value. The\nrange 0x8000 to 0xFFFF seems to represent voltages in the range 0.0V\nto 2.5V, and the range 0x0000 to 0x7FFF seems to represents voltages\nin the range 2.5V to 5.0V. Thus, if _value_ is in the range 0x0000 to\n0xFFFF, set the memory location at _dacPage_ + 0x00F0 to (_value_ +\n0x8000) % 0x10000.\n\nThe second address used by `DAC.d` is _dacPage_ + 0x0040, which is\nused as a signalling mechanism; specifically it appears that the\nsecond bit at that address toggles when the DAC is done dealing with\nthe last value that was set.\n\nIn practice, setting the value at _dacPage_ + 0x00F0 doesn't take\nuntil you've actually set it three or four times, so `DAC.d` tries to\nset it up to 20 times in a row each time it is supposed to update the\nDAC.\n\nPin 113 on the schematic, labeled HPL, corresponds to the DAC's\noutput, the output side bitSnap.\n\n\n#### Areas for further research\n\nI haven't determined what `DAC_init` does.\n\n\n### The Button\n\nThe button is managed by `/usr/local/lb/Button/bin/button.d`. It uses\nthe socket `/var/lb/BUTTON_socket`. If the button is pressed for long\nenough, `button.d` itself will run\n`/usr/local/lb/comm-util/signal_netmon.sh` directly.\n\nThe `/usr/local/lb/Button/bin/getButton` program communicates via the\nsocket to report the state of the button.\n\nThe `button.d` program operates in a manner similar to the other\nprograms, reading memory locations to find the state of the hardware.\nSpecifically, it uses the same 2KB page starting at 0x80018000 the\n`LEDcontrol.d` program uses to control the LED. This will again be\ncalled _gpioPage_ below.\n\nWhen the program starts, it sets the following memory locations to the\nfollowing values, in the following order:\n\n| Address             | Value      |\n|---------------------|------------|\n| _gpioPage_ + 0x0124 | 0x0000C000 |\n| _gpioPage_ + 0x0718 | 0x00000080 |\n\nThe actual status of the button is then available as bit 8 of the 32\nbit word at _gpioPage_ + 0x0610. (The other bytes seem unrelated to\nthe button, but were not set to zero when I was testing this.)\n\nThe button is wired to pin 9 on the schematic, labeled LCD_D07 and\nTACTSWITCH.\n\n\n## Original software\n\nThe cloudbit uses a Linux distribution with `systemd` as the init, and\n`pacman` as the package manager. I presume it's an archlinux variant.\n\n`uname -a` reports the following:\n\n```\nLinux noctilucent 3.7.2-8-littleARCH #1 PREEMPT Fri May 16 11:39:57 EDT 2014 armv5tejl GNU/Linux\n```\n\nSome interesting unique aspects of the configuration:\n\n* `/var/lb/mac` contains the MAC address of the cloudbit. It is\n  created by `/usr/local/lb/bit-util/onBoot.sh` which runs early on\n  boot.\n\n* `/etc/wpa_supplicant/cloudbit.conf` contains the network\n  configuration last provided by the user when commissioning the\n  device (including the password unencrypted).\n\n* There's a pair of shell scripts that set the CPU speed:\n  `/usr/local/lb/bit-util/hiPowerSet.sh` and\n  `/usr/local/lb/bit-util/lowPowerSet.sh`.\n\n\n# Notes on the o28 LED matrix (as driven by the w26 codebit)\n\nThe w26 codebit sends serial binary data to the o28 LED matrix to show\nimages and scrolling text. It uses an RS-232-like wire encoding at\n58K/8-N-1; that is, 57600 baud, 8 data bits, no parity bit, and one\nstop bit (whose width is usually slightly more than one bit's width).\n\nSpecifically, data is sent in packets of eight-bit bytes. Each byte\ntakes about 175.5μs. Each byte begins with 17.3μs at 0V, then eight\nbits, least significant bit first, each 17.3μs long, at 0V for 0\n(clear) and 5V for 1 (mark), and finally a terminating 5V for 19.5μs.\nWhen no data is being sent, the voltage of the data line is kept at\n5V.\n\nFor reasons I cannot explain, pulses from the w26 codebit are\nsometimes arbitrarily longer than they should be according to the\ndescription above. The o28 LED matrix appears to either ignore bogus\ndata or somehow correct for it; either way, I don't see glitches on\nthe LED matrix when glitches happen in the output of the codebit.\n\n## Data format\n\nEach packet starts with an 0x1C byte, a message type byte, a\npresentation configuration byte, and a length byte. This is followed\nby message-specific byte data whose length equals the length byte.\nFinally, the message ends with a trailing 0x26 byte. Messages are\ntherefore a maximum of 260 bytes long.\n\n```\n 00 01 02 03  04...    04+LL\n+--+--+--+--+---------+-----+\n|1C|TT|PP|LL| data... | 26  |\n+--+--+--+--+---------+-----+\n    |  |  |\n    |  |  `----------- Length byte\n    |  `-------------- Presentation, see section below\n    `----------------- Message type\n```\n\nThere are two message types that seem to be used by the w26 codebit\nand corresponding software: 0x00 for images, and 0x01 for scrolling\ntext.\n\n## Presentation\n\nThe third byte of every message represents the LED matrix display\npresentation configuration, and the intended audience for the message.\n\nThe high 4 bits represent the number of displays in the configuration.\nThe o28 LED matrix uses this to know how many channels to allow the\nuser to cycle through when they press the channel button. Values from\n1 to 4 are valid. I haven't yet tested what happens with invalid\nvalues.\n\nThe low 4 bits represent which channel the message is intended for.\nFor images in a four-display configuration, four packets are sent,\neach containing a different 8x8 image and assigned to a separate\nchannel. The four images for display channels 1 through 4 are\ntransmitted with the presentation configuration bytes set to 0x41,\n0x42, 0x44, and 0x48 respectively. For text, all the channels are\nenabled simultaneously, so in a horizontal four-display configuration,\nthe layout configuration byte is sent as 0x4F. (In a vertical\nconfiguration, only one display is enabled, using 0x1F.)\n\nThe o28 LED matrix ignores messages sent for channels beyond the\nnumber of channels declared in the high four bits.\n\n## Image messages (0x00)\n\nEach image is a sent as a 12.1ms burst of data, consisting of 4\nleading preamble bytes, 64 pixel bytes, and 1 trailing postamble byte.\n\nWhen the image is configured to target a single LED matrix, the\npreamble is four bytes, 0x1C001140 (in network byte order), and the\npostamble is one byte, 0x26.\n\nThe image data is 8 bit RGB. On the wire, the first two bits of each\nbyte represent the blue signal, the next three bytes represent the\ngreen signal, and final three bytes represent the red signal. This is\nequivalent to the low two bits being blue, the next three bits being\ngreen, and the high three bits being red.\n\n```\n 00 01 02 03  04...67      68\n+--+--+--+--+-------------+--+\n|1C|00|PP|LL| RGB data... |26|\n+--+--+--+--+-------------+--+\n    |  |  |\n    |  |  `----------- Length byte, always 0x40 for a single image (64 pixels)\n    |  `-------------- Presentation, see section above\n    `----------------- Message type, 0x00 for images\n```\n\n## Scrolling text messages (0x01)\n\nText is actually sent as ASCII text, not as a series of images, though\neach animation frame is sent as an individual message.\n\nThe data section of each message (following the preamble described\nabove) consists of a colour byte, a big-endian 16 bit value\nrepresenting how much the offset to apply to the text (in a multiple\ndisplay configuration, the offset is affected by the display's\nselected channel, so that adjacent displays appear as one long display\nscrolling the same text), and the text.\n\nThe full packet is sent as follows:\n\n```\n 00 01 02 03 04  05 06 07...           04+LL\n+--+--+--+--+---+-----+---------------+-----+\n|1C|01|PP|LL|RGB|SS SS| ASCII data... | 26  |\n+--+--+--+--+---+-----+---------------+-----+\n    |  |  |   |    |\n    |  |  |   |    `-- Scroll offset, 16 bit word, big-endian\n    |  |  |   `------- Color byte, 8 bit RGB: RRRGGGBB\n    |  |  `----------- Length byte, 3 plus the length of the string\n    |  `-------------- Presentation, see section above\n    `----------------- Message type, 0x01 for scrolling text\n```\n\nThe font is monospace; characters are 6 pixels wide including a 1\npixel wide margin between characters. The scroll offset appears to be\nin pixels; a scroll offset of zero indicates that the text should be\nflush left with the first display, and positive numbers move the text\nfurther to the left. Typically a message would be scrolled from offset\nzero to offset LL*5 (the width of the message).\n\nThe w26 codebit's software always prefaces scrolling text messages\nwith two 0x20 bytes (ASCII space characters). The two space characters\nare probably intended to provide a gap between subsequent scrolls of\nthe message, and to start the message a little off the edge of the\nfirst display.\n\nSending bytes above 0x7F (i.e. non-ASCII characters) results in\ngarbage on the display at that character position; I speculate that\nthis is reading data from outside the font array in the LED matrix.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhixie%2Flocalbit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhixie%2Flocalbit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhixie%2Flocalbit/lists"}