The Glitch
 All Files Pages
Developers Guide



Developing for The Glitch

The Glitch is Arduino compatible hardware. Firmware for The Glitch can be written using the Ardunio IDE. There is some great documentation on development provided on the Arduino website. Code from existing Arduino sketches can also be ported and compiled for The Glitch (see How to Compile).

Firmware can be written to accept user input from the DIP switch and Micro SD card, so it is not necessary to write or edit code. The DIP switch allows dynamic input from the user which can be used in coordination with individual modules on the Micro SD card. These modules consist of a configuration file (plain text or otherwise) interpreted by the firmware to perform a specific task. Modules are configured by the user ahead of time on the Micro SD card to perform specific tasks based on the firmware. Developers are encouraged to use the Code Template for projects.

For example, a Keystroke Injection module would contain a configuration file and a payload. The configuration file tells the firmware that the payload is a Batch script that will run on a Windows computer. The firmware interprets the configuration and performs all the tasks necessary to read in the Batch script from the Micro SD card, type it out on the target system, run and delete the script.

Developers can follow these instructions to set up an environment to program for The Glitch.

User VS Developer

One concept that is different between projects using The Glitch and similar hardware platforms is the difference between a User and Developer. Most open hardware platform projects assume that the User will also be able to write and edits source code. Instead of requiring users to compile and edit code on their own, developers for The Glitch should provide a pre-compiled HEX file (firmware) along with the source code of their projects (see Compile for a guide on accessing your compiled firmware). This is similar to developers providing an application rather then just the source code. This makes it much easier for Users to flash The Glitch with the firmware from your project and hit the ground running (See Loading Firmware).

Install Arduino Environment

Download and install the Ardunio environment from http://arduino.cc/en/Main/Software. This software runs on Windows, Linux, and OXS. We recommend using version 1.0.x of the Ardunio software.

For more information on the Ardunio environment, see http://arduino.cc/en/Guide/HomePage.

Install Libraries

Install the libraries and resources.

Teensyduino

Download the Teensyduino library for Windows, Linux (32), Linux (64), or OS X. This bundle includes hardware resource files and many libraries. Follow the step-by-step menu to install the Teensyduino resources into the Arduino installation directory. It is recommended to install all available libraries in the Teensyduino bundle.

GlitchLib

The Glitchlib library includes some basic variables and functions to make developing for The Glitch easier. Copy and paste the GlitchLib folder from the Resource Files into the libraries folder of the Arduino installation directory. For more information see GlitchLib.

Edits to Resources

With the resources installed, there are still a few manual edits that need to be made.

Add "The Glitch" Board To the Arduino IDE

In the directory where the Arduino software has been installed, open arduino/hardware/teensy/boards.txt in a text editor. Add the following at the end of the file and save the file. This will add The Glitch as an Board in the Arduino IDE the next time it is started.

glitch.name=The Glitch
glitch.upload.protocol=halfkay
glitch.upload.maximum_size=122880
glitch.upload.speed=115200
glitch.upload.disable_flushing=true
glitch.bootloader.path=undefined
glitch.serial.restart_cmd=true
glitch.serial.safe_baud_rates_only=true
glitch.upload.avrdude_wrapper=avrdude
glitch.build.mcu=at90usb1286
glitch.build.core=teensy
glitch.build.elide_constructors=true
glitch.build.cpp0x=true
glitch.build.dependency=true
glitch.build.linker_relaxation=true
glitch.build.serial_number=true
glitch.menu.usb.serial.name=Serial
glitch.menu.usb.serial.build.define0=-DUSB_SERIAL
glitch.menu.usb.hid.name=Keyboard + Mouse
glitch.menu.usb.hid.build.define0=-DUSB_HID
glitch.menu.usb.hid.fake_serial=teensy_gateway
glitch.menu.usb.int_disk.name=Disk(Internal) + Keyboard
glitch.menu.usb.int_disk.build.define0=-DUSB_DISK
glitch.menu.usb.int_disk.fake_serial=teensy_gateway
glitch.menu.usb.int_disk.build.elfpatch=mktinyfat
glitch.menu.usb.sd_disk.name=Disk(SD Card) + Keyboard
glitch.menu.usb.sd_disk.build.define0=-DUSB_DISK_SDFLASH
glitch.menu.usb.sd_disk.fake_serial=teensy_gateway
glitch.menu.usb.midi.name=MIDI
glitch.menu.usb.midi.build.define0=-DUSB_MIDI
glitch.menu.usb.midi.fake_serial=teensy_gateway
glitch.menu.speed.16.name=16 MHz
glitch.menu.speed.16.build.f_cpu=16000000L
glitch.menu.speed.8.name=8 MHz
glitch.menu.speed.8.build.f_cpu=8000000L
glitch.menu.speed.4.name=4 MHz
glitch.menu.speed.4.build.f_cpu=4000000L
glitch.menu.speed.2.name=2 MHz
glitch.menu.speed.2.build.f_cpu=2000000L
glitch.menu.speed.1.name=1 MHz
glitch.menu.speed.1.build.f_cpu=1000000L
glitch.menu.keys.en-us.name=US English
glitch.menu.keys.en-us.build.define1=-DLAYOUT_US_ENGLISH
glitch.menu.keys.fr-ca.name=Canadian French
glitch.menu.keys.fr-ca.build.define1=-DLAYOUT_CANADIAN_FRENCH
glitch.menu.keys.da-da.name=Danish
glitch.menu.keys.da-da.build.define1=-DLAYOUT_DANISH
glitch.menu.keys.fi-fi.name=Finnish
glitch.menu.keys.fi-fi.build.define1=-DLAYOUT_FINNISH
glitch.menu.keys.fr-fr.name=French
glitch.menu.keys.fr-fr.build.define1=-DLAYOUT_FRENCH
glitch.menu.keys.fr-be.name=French Belgian
glitch.menu.keys.fr-be.build.define1=-DLAYOUT_FRENCH_BELGIAN
glitch.menu.keys.fr-ch.name=French Swiss
glitch.menu.keys.fr-ch.build.define1=-DLAYOUT_FRENCH_SWISS
glitch.menu.keys.de-de.name=German
glitch.menu.keys.de-de.build.define1=-DLAYOUT_GERMAN
glitch.menu.keys.de-ch.name=German Swiss
glitch.menu.keys.de-ch.build.define1=-DLAYOUT_GERMAN_SWISS
glitch.menu.keys.is-is.name=Icelandic
glitch.menu.keys.is-is.build.define1=-DLAYOUT_ICELANDIC
glitch.menu.keys.en-ie.name=Irish
glitch.menu.keys.en-ie.build.define1=-DLAYOUT_IRISH
glitch.menu.keys.it-it.name=Italian
glitch.menu.keys.it-it.build.define1=-DLAYOUT_ITALIAN
glitch.menu.keys.no-no.name=Norwegian
glitch.menu.keys.no-no.build.define1=-DLAYOUT_NORWEGIAN
glitch.menu.keys.pt-pt.name=Portuguese
glitch.menu.keys.pt-pt.build.define1=-DLAYOUT_PORTUGUESE
glitch.menu.keys.pt-br.name=Portuguese Brazilian
glitch.menu.keys.pt-br.build.define1=-DLAYOUT_PORTUGUESE_BRAZILIAN
glitch.menu.keys.es-es.name=Spanish
glitch.menu.keys.es-es.build.define1=-DLAYOUT_SPANISH
glitch.menu.keys.es-mx.name=Spanish Latin America
glitch.menu.keys.es-mx.build.define1=-DLAYOUT_SPANISH_LATIN_AMERICA
glitch.menu.keys.sv-se.name=Swedish
glitch.menu.keys.sv-se.build.define1=-DLAYOUT_SWEDISH
glitch.menu.keys.en-gb.name=United Kingdom
glitch.menu.keys.en-gb.build.define1=-DLAYOUT_UNITED_KINGDOM
glitch.menu.keys.usint.name=US International
glitch.menu.keys.usint.build.define1=-DLAYOUT_US_INTERNATIONAL

How to Compile

Setting environment

Under the Tools menu, users can select the parameters for compiling.

Select Glitch, Tools -> Board -> “The Glitch”

Select USB Type, Tools -> USB Type -> “Keyboard + Mouse”

Select CPU Speed, Tools -> CPU Speed -> “16MHz”

arduinoidesettings.png

Set to Verbose

Change the Arduino environment to display verbose output. Select File -> Preferences

arduinoideverbose1.png


In “Show verbose output during”, Check the box for “compilation” and “upload”.

arduinoideverbose.png

Compile

The Glitch does not use the AVR serial uploader that is used by most Arduinos. Instead, HEX files are uploaded from the command line. Unfortuantly, the Ardunio IDE does not place the compiled sketch file in the same directory as the source code. Instead, the file is place in a semi-random directory. Look at the verbose output from the Ardunio IDE for the location of the compiled HEX file.

arduinoideverboseoutputhl.png

While the Arduino environment is running, the HEX file will be replaced every time the code is compiled. When the environment is closed and open again, the directory path may change.

Linux:

/tmp/build[RANDOM NUNBER].tmp/[FILENAME].cpp.hex

OSX:

/tmp/build[RANDOM NUNBER].tmp/[FILENAME].cpp.hex

Windows:

C:\temp\[FILENAME].cpp.hex

Copy Executable

(Optional) Copy the .HEX file to the directory of the source code.

Upload HEX

Firmware can be uploaded to The Glitch using the glitch_loader command line utility. Follow the instruction in Loading Firmware to upload firmware.

Publishing Projects

Projects published for The Glitch should include:

  • Source Code - Source code project files and custom libraries. Including the .ino or .pde file.
  • Firmware - The compiled .hex firmware binary.
  • Documentation - Documentation online or in a README file.
  • Module Directories - Follow the guide to provide module folders for each module on the Micro SD card.

Code Template

The following code is the suggested template for Glitch projects. It provides the functionality to utilize the DIP switch and read configuration files from the Micro SD card.

Create a new Arduino project, then copy and paste the following code. Customize the code in the specified CHANGE BLOCKs.

Template

//
// The Glitch template
//
// Libraries:
// GlitchLib
// SD
//
// Version:
//
#include <glitchlib.h>
#include <SD.h>
// Global Variables
unsigned long waitTime = 1000; // Time to delay
short nextInt = -1; // Next payload to run
char file_sd_path[66] = {0}; // Used to define a path to a file on the Micro SD card
char config_file[13] = "config.txt\0"; // Configuration file for Module on MicroSD card
char wait[10] = {'\0'}; // Method of delay before payload launch
//###################################### CHANGE BLOCK ########################################
char frimwarename[16] = "name\0"; // Name of firmware. CHANGE 'name' to the project name
char frimwareversion[16] = "1.0\0"; // Version of firmware. CHANGE '1.0' to the software version
char file_sd_root[9] = "example\0"; // Root of files. CHANGE 'example' to a directory name
//###################################### END ######################################
// Global variables
//###################################### CHANGE BLOCK ########################################
// The Options are strings read in from the config file. Options specify the type of parameter.
//
// char opt_one[10] = {0};
// char opt_two[10] = {0};
// char opt_three[10] = {0};
// ...
// Parameters are variables for the Option
//
// char param_one[10] = {0};
// char param_two[10] = {0};
// char param_three[10] = {0};
// ...
//###################################### END ######################################
//
// The setup() method runs once, when the sketch starts
//
void setup() {
// Slight delay
delay(100);
// Value set by the DIP Switch
short selection = 0;
glitchSetLED(); // Set LEDs as output pins
glitchSetDIP(selection); // Get selection from current DIP switch positions
if (!glitchSetSD()) { // Initialize SD card reader
printError("MicroSD read fail."); // don't do anything more: fail
return;
}
SelectPayload(selection);
}
//
// Execute the payload.
//
void runPayload(int selection) {
// Wait number of milliseconds set in waitTime
delay(waitTime);
//###################################### CHANGE BLOCK ########################################
// Set the path to a payload file if one exists
// setSDModPath(selection, file);
//###################################### END ######################################
//###################################### CHANGE BLOCK ########################################
/* if (strcmp(param_one, "choice_one") == 0) {
// action ...
} else if (strcmp(param_one, "choice_two") == 0){
// action ...
} else if (strcmp(param_one, "choice_three") == 0) {
if (strcmp(param_two, "choice_b") == 0)
// action ...
} else {
// action ...
}
} else {
printError("'config.txt' format.");
}
*/
//###################################### END ######################################
}
//
// Read in the content of config.txt.
//
void readConfig(int selection) {
// Configuration filename
setSDModPath(selection, "mod.cfg");
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File confFile = SD.open(file_sd_path,FILE_READ);
unsigned int sizeConfFile = confFile.size();
unsigned int positionConfFile = 0;
// if the file is available read it
if (confFile) {
while (positionConfFile < sizeConfFile) {
delay(50);
// Read in line (up to 262 characters)
int i = 0;
char line[262]={0};
char c;
do
{
c = confFile.read();
line[i]=c;
i++;
positionConfFile++;
} while (c >= 0 && c != '\n' && c != '\r' && positionConfFile < sizeConfFile);
// Check for blank line
if (c == '\n' || c == '\r') {
line[i]=c;
}
// Remove end of line
if (line[i] == '\n' || line[i] == '\r') {
i--;
}
// Read in variable
// Check for comment lines starting with '#'
if ((i > 5) && (line[0] != '#' ) && (line[0] != '\n')){ // Parse line
int k = 0;
char option[5]={'\0'};
// Read in option
while (line[k] != ':' ){
option[k]=line[k];
k++;
}
// Increment to account for colen
k++;
unsigned short varLength=k;
// Read in the paramter
if (strcmp(option, "wait") == 0) {
while (k < i) {
wait[k-varLength]=line[k++];
}
waitTime = strToInt(wait); // Convert to string to int
//###################################### CHANGE BLOCK ########################################
/*
} else if (strcmp(option, opt_one) == 0) {
while (k < i) { param_one[k-varLength]=line[k++]; }
} else if (strcmp(option, opt_two) == 0) {
while (k < i) { param_two[k-varLength]=line[k++];}
} else if (strcmp(option, opt_three) == 0) {
while (k < i) { param_three[k-varLength]=line[k++];}
*/
//###################################### END ######################################
} else {
printError("'config.txt' format.");
}
}
}
} else {
printError("no file 'config.txt'.");
}
confFile.close();
}
//###################################### CHANGE BLOCK ########################################
//
// ADD FUNCTIONALITY HERE
//
/*
void DoThingOne()
{
}
void DoThingTwo()
{
}
void DoThingThree()
{
}
*/
//
//
//###################################### END ######################################
// DO NOT CHANGE
//
// Do something based on the selection of the DIP Switch.
//
void SelectPayload(short selection) {
// Choose action based on DIP switch selection.
switch (selection) {
case 0: // Do Nothing
delay(500);
break;
case 1: // Print help
writeHelp();
break;
case 2:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 3:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 4:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 5:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 6:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 7:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 8:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 9:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 10:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 11:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 12:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 13:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 14:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 15:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 16:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 17:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 18:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 19:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 20:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 21:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 22:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 23:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 24:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 25:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 26:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 27:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 28:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 29:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 30:
// Do something
readConfig(selection);
runPayload(selection);
break;
case 31:
// Do something
readConfig(selection);
runPayload(selection);
break;
}
}
// DO NOT CHANGE
//
// Define the root path for files to be read from
//
// It should end up looking something like: glitch/mon07/config.txt
//
void setSDModPath(int num, char * file){
if (num < 10) {
sprintf(file_sd_path,"%s/mod0%i/%s", file_sd_root, num, file);
} else {
sprintf(file_sd_path,"%s/mod%i/%s", file_sd_root, num, file);
}
}
// DO NOT CHANGE
//
// Convert string to Int
//
int strToInt(char * string){
unsigned short strLength = strlen(string);
long int strInt = 0;
unsigned short i=0;
for (i; i < strLength-1; i++) {
strInt = strInt + (((int)string[i]-48)*(pow(10,(strLength-1-i))));
}
if (i == strLength-1) {
strInt = strInt + (((int)string[i]-48));
i++;
}
// Add 1 to account for Double to Int conversion
if (strInt > 0){strInt++;}
return strInt;
}
// DO NOT CHANGE
//
// Read in text from the help.txt file in every module directory.
//
extern void writeHelp(){
delay(3000);
// Type out a header
Keyboard.print("\n\n ");
Keyboard.print(frimwarename);
Keyboard.print(" ");
Keyboard.print(frimwareversion);
Keyboard.print(" Modules\n\n");
for(unsigned short i = 0; i < 32; i++){
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
setSDModPath(i, "help.txt");
File dataFile = SD.open(file_sd_path,FILE_READ);
Keyboard.print("\n\n Module ");
Keyboard.print(i);
Keyboard.print(":\n\n");
// Type in the content of help.txt
// You will need to open a text editor before running this selection
if (dataFile) {
delay(1000);
while (dataFile.available()) {
delay(5);
Keyboard.print((char)dataFile.read());
}
} else {
printError("No help.txt file\n");
}
dataFile.close();
}
}
// DO NOT CHANGE
//
// Print error message
//
void printError(char * message){
Keyboard.print("Error: ");
Keyboard.print(message);
digitalWrite(ledRed, HIGH);
}
// Loop //
// Doing nothing in the loop
//
// Code here will continuously run in a loop
//
void loop(){}