This guide is intended to help code contributors understand how relevant system components of Tessel 2 work, where to find code and design files, and accelerate the development process through technical transparency.

Relevant Github Repositories

Quick guide to the Tessel stack (in order of complexity):

Level Stack Repo
User / Module Code JS (Many)
CLI JS t2-cli
Tessel Library Linux / JS / Comms t2-firmware
OpenWRT Linux / C / Shell / More t2-firmware
SSH/GPIO Daemons Linux / C t2-firmware
Firmware C / Comms t2-firmware

Tessel 2 Core Repos:

You can find all of the Tessel repositories on the organization page but this section provides some guidance over relevant Tessel 2-specific repositories.

Tessel 2 Command Line Interface (CLI)

The CLI is the primary method of interacting with Tessel for users and developers. It provides useful functions like listing available Tessels, deploying code, and setting wifi credentials on the device.

Tessel 2 Operation System (OpenWRT)

The primary processor of the Tessel 2 runs a very lightweight version of Linux called OpenWRT. OpenWRT provides all of the TCP/IP drivers, threading/schedule support, and runs Node, Rust or whatever other language you’re using with Tessel 2. This repo contains all of the source files of the Tessel build of OpenWRT.

Tessel 2 Co-processor Firmware

Tessel 2 features a SAMD21 co-processor that manages a handful of responsibilities like routing USB communication from the CLI and the realtime operations on the GPIO pins of the two module ports. This repo contains not only the firmware that drives this microcontroller but hardware-related scripts that define the interface to other languages (like tessel.js for Node scripts) so that the available hardware functionality doesn’t get out of sync with what is exposed to the OpenWRT processor.

Tessel 2 Tools

Tessel 2 Virtual Machine (VM)

The VM is used primarily by Tessel developers who either don’t have hardware available or want to develop on a faster computer. The repo provides the ability to create and run these Tessel virtual machines. You can use the CLI (see above) to interact with the running VM just as you would an actual Tessel 2. The VM has the limitation of not being able to set wifi credentials (it passes through the host network interface). It is not able to use 10-pin hardware modules but USB devices do get passed through.

Tessel 2 Compiler

The Tessel 2 compiler is another virtual machine with all the build tools needed to develop native add-ons to Node modules. These add-ons are built to perform faster or interact with lower level hardware than JS alone would provide. The compiler is being used, for example, to develop the audio-video Node module for webcams and recording audio from microphones.

Hardware Designs

Tessel 2 Hardware Design Files

These are the production schematic and assembly files for the Tessel 2 hardware. You can find information about the parts that are used and how they are all connected to each other. These files were created with KiCad, a completely open source electronics design tool.

Tessel Parts Library

This repo contains all of the KiCad part models for all Tessel hardware (not just Tessel 2). You will need this library in order to recreate the schematic and PCB of the hardware design files above.


10-Pin Modules

There are 9 compatible 10-pin hardware modules for Tessel 2 available at the time of this writing. Each of these modules have a repo that contains the JavaScript driver. These repos can also be found on NPM under their respective Node modules names.

USB Modules

Tessel supports interfacing with USB devices. Here are libraries we support for Tessel to interoperate with USB modules, available from many vendors:

System Architecture

High Level Look At Hardware

Below is a high level diagram of the hardware architecture: 

As you can see from the diagram, the Atmel co-processor manages the USB connection and can communicate with the MediaTek through a SPI bus. The MediaTek can execute user scripts, and when it interprets hardware commands (like pulling a GPIO high or sending data over I2C), it packages it up and sends it over to the Atmel over a pre-defined protocol on that SPI bus.

Software Architecture

The MediaTek is responsible for managing the two USB Host ports, the ethernet port, and the WiFi network interace directly from the OpenWRT Operating System.

The USB Port on the Atmel actually has three interfaces to the to the MediaTek:

  1. A UART connection that acts a serial terminal to the MediaTek. You can use a program like dterm to access the console through this connection.
  2. A direct connection to the SPI Flash bus of the MediaTek. This allows the Atmel to rewrite the OpenWRT image and helps prevent the Tessel from becoming bricked by any corruptions to OS.
  3. A SPI bus connection to the MediaTek for arbitrary data.

A Code Deploy Example

A good method of understanding all the components of the system is to go through an example of running a simple script on Tessel 2:

The user code to light up an LED

The user might have code like the example below to light up LED 0 on Tessel 2.

var tessel = require('tessel');

Deploy with the CLI

First, the user will use the command line interface to deploy the script from the host computer:

t2 run index.js

The CLI will compress the code and break this simple run command into a number of bash commands required to deploy the code like untarring the code and running it with Node.

Accepting USB Communication On The Atmel

The utf-8 encoding of each command is sent over the USB connection via a USB pipe. The USB pipe driver hands off the data to the general purpose SPI bridge (labeled as “SPI SLAVE SERCOMMx” in the diagram above) which transfers the command to the MediaTek.

Relaying Data to the MediaTek SPI Daemon

On the MediaTek, the SPI Daemon is constantly waiting for data over the SPI bus and checks whether this data is from one of the module ports (for example, if an analog voltage was previously requested and was now returning the result) or from the USB port.

The shell script that starts up the SPI Daemon on boot also creates three unix domain sockets: one for Module Port A (/var/run/tessel/port_a), one for Module Port B (/var/run/tessel/port_b), and one for USB (/var/run/tessel/usb). We’ll get to the two module ports in a moment, but first, the data from the CLI is passed into the USB domain socket.

One More Relay Into The USB Daemon

Waiting on the other end of the domain socket is the USB Daemon. This program has the thrilling task of accepting shell commands, initializing new threads to execute them, and routing stdin, stdout, and stderr of those threads back to the CLI.

So by this point, the CLI has executed a handful of bash commands that transferred the code onto the Tessel 2 and started a Node process to run it. The next question is how we actually do anything with the hardware.

Accessing Hardware Through tessel.js

For JavaScript files, the answer comes from the var tessel = require('tessel') line of the user script. When Node executes this on the MediaTek, it finds the tessel module in /usr/lib/node/tessel.js. When this file is executed, it connects to a domain socket for each module port: two of the three domain sockets created by the SPI Daemon earlier! That means that whenever you run a command on a port like tessel.led[0].high(), it’s packaging that command into a array of bytes and sending it back over the SPI bus to the Atmel bridge firmware! That firmware then parses the command as pulling the specific GPIO high, and executes it. It can then return the result of that operation back through the SPI bus to the MediaTek SPI Daemon.

Why Domain Sockets?

The beauty of this architecture with domain sockets is that most legitimate programming langauges have the capability to utilize domain sockets. This is how Tessel 2 can be used by any language, not just JavaScript (the code that packages up the commands into array bytes just has to be ported to that language first).

How Does Deploying Code over LAN Work Into This?

In the case of a LAN connection over WiFi or Ethernet, the procedure is much the same except all of the shell commands are executed over SSH. All of the module port communication between the SPI Daemon and the USB Bridge firmware is entirely the same. That’s why the CLI is able to abstract out USB and LAN interfaces into a single Connection object that simply accepts shell commands and returns a process object with the three streams (stdin, stdout, stderr) regardless of physical connection.

What is UCI/ubus on the diagram above?

UCI and ubus are unique features of OpenWRT that essentially let you access system configuration programmatically and receive results in a JSON format. It’s very handy for the command line interface. You can see that the CLI makes use of these features heavily, especially for wifi related settings.