Arduino Usertools -- simple threading, simple user interface, powerful debugging

So I've been working on a suite of tools for the Arduino over the past couple weeks, such as the errorhandling library and the ArduinoISP_talk library, but as I was working on my newest library I decided to merge them all together.

I present to you the usertools library, and I hope you find it cool :slight_smile:

To Install
extract contents into a folder you create named "usertools" in your arduino "libraries" folder

Overview

What does it offer? It gives simple threading, debugging, error handling, and even a clean simple user interface that integrates with all of these things. And it does all of this with less than 800 bytes of memory and 8k of flash.

The code below shows how this library can solve a whole bunch of issues that people have all the time whe trying to make threads. To overview.

Calling a function
as simple as exposing it (expose_function(name, func)) and then calling it's name in the terminal

Getting a variable
as simple as exposing it and then "v name"

Starting / Killing threads
Expose thread and call it to start it (or call_name(name, input) in software)
Kill thread with call_name("kill", "thread_name") or just kill_thread(F("thread_name")) -- F to save memory
Threads that are killed go to their PT_KILL location (see examples and documentation).

Code Basics

/* Copyright (c) 2014, Garrett Berg
 * This example code is released into the public domain
 *
 * Author: Garrett Berg <garrett@cloudformdesign.com>
 * 
 * Example code to demonstrate the ui.h and threading.h
 * libraries
 * 
 */

//#include <Stream.h>

#define DEBUG  // if commented out, DEBUG statements and other logs go away

#include <SoftwareSerial.h>  // BUG: must be included before errorhandling.h
#include <errorhandling.h>

#include <ui.h>

// Simple function we are going to call from user interface
void hello_world(char *input){
  Logger.print(F("HELLO WORLD: "));
  Logger.println(input);
}

// Does a hangup to show that the Arduino automatically records
//  where the timeout failure was and then restarts
void hangup(char *c){
  Logger.println("hanging...");
  while(1);
}

// Threads must also recieve a protothread pointer (pthread)
// These they can use with the protothread library to keep track
// of where they are between calls.
uint8_t print_back(pthread *pt, char *input){
  static char saved[100];  // character array to store input, there are better ways to do this
  static uint16_t time;        // keep track of time for waiting
  
  PT_BEGIN(pt);  // from pt library
  strncpy(saved, input, 99); //returns the word. Input goes to 

  PT_YIELD(pt); // future calls will ignore the input. You can reset this thread by killing it
  Logger.println(F("Print Back Starting"));
  while(1){
    Logger.print(F("Your phrase:"));
    Logger.println(saved);
    PT_WAIT_MS(pt, time, 5000);  // automatically uses the "time" variable to do a wait.
    //   note that time has to be static!
  }
  PT_END(pt);
}

unsigned int answer = 0x42;

void setup(){
  uint16_t mem;
  Serial.begin(57600);  
  debug(F("Debug active"));
  ui_setup_std(1, 2, 1);
  
  // make variables and functions available to the user interface
  expose_variable("answer", answer);
  expose_function("hi", hello_world);
  expose_function("hang", hangup);
  expose_thread("print", print_back);
  
  call_name("mon", "");     // start the system monitor -- will print every 5 seconds
                            // turn off with "kill mon" in the terminal
                            // turn back on with "mon" in the terminal
  ui_std_greeting();        // print standard greeting.
}

void loop(){
  ui_loop();
}