Snek-Duino: Snek with Arduino I/O

At the suggestion of a fellow LCA attendee, I've renamed my mini Python-like language from 'Newt' to 'Snek'. Same language, new name. I've made a bunch of progress in the implementation and it's getting pretty usable.

Here's our target system running Snek code that drives the GPIO pins. This example uses Pin 3 in PWM mode to fade up and down:

# Fade an LED on digital pin 3 up and down

led = 3

def up():
    for i in range(0,1,0.001):
        setpower(i)

def down():
    for i in range(1,0,-0.001):
        setpower(i)

def blink(n):
    talkto(led)
    setpower(0)
    on()
    for i in range(n):
        up()
        down()
    off()

Snek-Duino GPIO API

The GPIO interface I've made borrows ideas from the Lego Logo system. Here's an old presentation about Lego Logo. In brief:

  • talkto(output) or talkto((output,direction)) — set the specified pin as an output and use this pin for future output operations. If the parameter is a list or tuple, use the first element as the output pin and the second element as the direction pin.

  • listento(input) — set the specified pin as an input (with pull-ups enabled) and use this pin for future input operations.

  • on() — turn the current output pin on. If there is a recorded power level for the pin, use it.

  • off() — turn the current output pin off.

  • setpower(power) — record the power level for the current output pin. If it is already on, change the power level immediately. Power levels go from 0-1 inclusive.

  • read() — report the state of the current input pin. Pins 0-13 are the digital pins and report values 0 or 1. Pins 14-19 are the analog input pins and report values from 0-1.

  • setleft() — set the current direction pin to 1.

  • setright() — set the current direction pin to 0.

With this simple API, the user has fairly complete control over the pins at the level necessary to read from switches and light sensors and write to lights and motor controllers.

Another Example

This implements a dimmer — reading from an analog input and mirroring that value to a pin.

led = 3
dial = 14

def track():
    talkto(led)
    listento(dial)
    setpower(0)
    on()
    while True:
        p = read()
        if p == 1:
            break
        setpower(p)
    off()

Further Work

Right now, all Snek code has to be typed at the command line as there's no file system on the device. The ATmega328P on this board has a 1k EEPROM that I'd like to use to store Snek code to be loaded and run when the device powers on.

And, I'd like to have a limited IDE to run on the host. I'm wondering if I can create something using the standard Python3 curses module so that the IDE could be written in fairly simple Python code. I want a split screen with one portion being a text editor with code to be sent to the device and the other offering a command line. Flipping away from the text editor would send the code to the device so that it could be run.

There's no way to interrupt a running program on the Arduino. I need interrupt-driven keyboard input so that I can catch ^C and halt the interpreter. This would also make it easy to add flow control so you can send long strings of code without dropping most of the characters.