Julian Hespenheide
Published © GPL3+

émile – A Hommage in 5-Bit

émile is a writing machine using the Baudot code – a binary 5-bit code, predecessor of ASCII and EBCDID.

IntermediateShowcase (no instructions)3,727
émile – A Hommage in 5-Bit

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Standard LCD - 16x2 White on Blue
Adafruit Standard LCD - 16x2 White on Blue
×1
Micro Limit Switch
OpenBuilds Micro Limit Switch
×5
Wire Cable - By the Foot
OpenBuilds Wire Cable - By the Foot
×1
Black Marble
The physical bits!
×5

Software apps and online services

Arduino IDE
Arduino IDE
Code written entirely in the Arduino platform
Processing
The Processing Foundation Processing
Used for the creation of the punch cards

Hand tools and fabrication machines

Wood working tools
For constructing the whole object
Aluminum pipe cutting tool
For make the alu pipe stand-offs
Laser cutter (generic)
Laser cutter (generic)
Cutting the "punch" cards and laser cut the small acrylic starting area for the marble as well as the arduino holder

Story

Read more

Custom parts and enclosures

Sketchup file of enclosing

Sketchup file for the project file

Schematics

Punch card (A – H)

These are files for a laser cutter, so you can reproduce the cards that are seen in the video. They represent the 5-bit of Baudot in a physical form.

Punch card (I – P)

These are files for a laser cutter, so you can reproduce the cards that are seen in the video. They represent the 5-bit of Baudot in a physical form.

Punch card (Q – X)

These are files for a laser cutter, so you can reproduce the cards that are seen in the video. They represent the 5-bit of Baudot in a physical form.

Punch card (Y, Z – SPECIAL CHARACTERS)

These are files for a laser cutter, so you can reproduce the cards that are seen in the video. They represent the 5-bit of Baudot in a physical form.

Arduino holder plexi plate

to hold the arduino in place at the end of the device

Code

PinballBaudot_v14.ino

Arduino
Upload this to your arduino
#include <LiquidCrystal.h>
#include "Timer.h"
#include "BaudotDecoder.h"
#include "Display.h"

#define DEBUG false
#define INPUT_COUNT BaudotDecoder::BIT_COUNT
#define DECODE_DELAY 1000 // waits for bit input for 1000 ms = 1 sec before decoding.
#define SLEEP_DELAY 300000 // puts the display to sleep after 300.000 ms = 5 min.


int inputPins[INPUT_COUNT] = { A1, A2, A3, A4, A5 };
int inputValues[INPUT_COUNT] = { 0, 0, 0, 0, 0 };
int readValue; // variable to temporarily store the value read from pin.
Timer _decodeTimer = Timer(DECODE_DELAY); // instantiate timer for delayed bit decoding.
Timer _sleepTimer = Timer(SLEEP_DELAY); // instantiate timer to put display to sleep when no activity is registered.
Display _display = Display();


void setup() {
  // initialize serial connection
  Serial.begin(9600);
  
  // set correct pin mode for buttons
  for(int i = 0; i < INPUT_COUNT; i++) {
    // use internal input pullup, which inverts the pin reading: 1 = 0, 0 = 1
    pinMode(inputPins[i], INPUT_PULLUP);
  }
  
//  char initValues[8] = {'A', ' ', 'P', 'A', 'T', 'I', 'E', 'N'};
//  for(int i = 0; i < 8; i++) {
//    _display.printChar(initValues[i]);
//  }
  
  // start sleep timer
  _sleepTimer.start();
}


void loop() {
  // update readings from pins
  for (int i = 0; i < INPUT_COUNT; i++) {
    // invert the reading due to pin mode.
    readValue = !digitalRead(inputPins[i]);
    // check whether the new pin value is different from last
    if (readValue == 1 && readValue != inputValues[i]) {
      // store the value in the array.
      inputValues[i] = readValue;
      // check if timer needs to started
      if (_decodeTimer.isStopped()) {
        _decodeTimer.start();
      }
      
      /*if (_sleepTimer.isStopped()) {
        _sleepTimer.start();
      } else {
        _sleepTimer.reset();
      }*/
    }
  }
  
  if (DEBUG) {
    BaudotDecoder::printBits(inputValues);
  }
  
  if (_decodeTimer.isFinished()) {
    // check whether the display is put to sleep.
    if (_display.is_sleeping()) {
      _display.wake_up();
    }
    
    // convert bits to char
    char c = BaudotDecoder::convertBitsToChar(inputValues);
    
    // evaluate action
    if (BaudotDecoder::getLastIndex() == BAUDOT_CLEAR_ID) {
      _display.clearAllChars();
    } else if (BaudotDecoder::getLastIndex() == BAUDOT_BACKSPACE_ID) {
      _display.deleteLastChar();
    } else {
      _display.printChar(c);
    }
    
    // reset array which stores the button readings
    for (int i = 0; i < INPUT_COUNT; i++) {
      inputValues[i] = 0;
    }
  }
  
  if (_sleepTimer.isFinished()) {
    Serial.println("SLEEP");
    
    _display.sleep();
    _display.clearAllChars();
    
    _decodeTimer.stop();
    _sleepTimer.stop();
  }
}

BaudotDecoder.h

C Header File
#ifndef BaudotDecoder_h
#define BaudotDecoder_h

#include <Arduino.h>

#define BAUDOT_BACKSPACE_ID 8 // 0b01000
#define BAUDOT_CLEAR_ID 31 // 0b11111

class BaudotDecoder {
  public:
    static const unsigned int BIT_COUNT = 5;
    static char convertBitsToChar(int *bits);
    static void printBits(int *bits);
    static unsigned int getLastIndex();
  private:
    static char _charSetMode0[32];
    static char _charSetMode1[32];
    static unsigned int _lastDecodedIndex;
    static char _lastDecodedValue;
};

#endif

BaudotDecoder.cpp

C/C++
//#include <Arduino.h>
#include "BaudotDecoder.h"

char BaudotDecoder::_charSetMode0[] = {
  NULL, 'Y', 'E', 'I', 'A', 'U', 'P', 'O',
  NULL, 'B', 'G', 'F', 'J', 'C', 'H', 'D',
  ' ', 'S', 'X', 'W', '-', 'T', 'Z', 'V',
  '.', 'R', 'M', 'N', 'K', 'Q', 'L', NULL
};

unsigned int BaudotDecoder::_lastDecodedIndex = 0;
char BaudotDecoder::_lastDecodedValue = NULL;

char BaudotDecoder::convertBitsToChar(int* bits) {
  Serial.println("BaudotDecoder -> decode bits: ");
  printBits(bits);
  
  _lastDecodedIndex = 0;
  
  for (int i = 0; i < BIT_COUNT; i++) {
    Serial.print(i);
    Serial.print(" : ");
    Serial.println(bits[i]);
    _lastDecodedIndex = _lastDecodedIndex | (bits[i] << (4 - i));  
  }
  Serial.print("index: ");
  Serial.println(_lastDecodedIndex);
  
  Serial.print("char: ");
  Serial.println(_charSetMode0[_lastDecodedIndex]);
  
  return _charSetMode0[_lastDecodedIndex];
}

void BaudotDecoder::printBits (int* bits) {
  Serial.print(millis());
    Serial.print(" - [ ");
    for(int i = 0; i < BIT_COUNT; i++) {
      Serial.print(bits[i]);
      if(i < BIT_COUNT - 1){
        Serial.print(", ");
      }
    }
    Serial.println(" ]");
}

unsigned int BaudotDecoder::getLastIndex() {
  return _lastDecodedIndex;
}

Display.h

C Header File
#ifndef Display_h
#define Display_h

#include <Arduino.h>
//TODO optimize import of system library
//#include <LiquidCrystal.h>
//#include "/Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/src/LiquidCrystal.h" // old Arduino
#include "/Applications/Arduino.app/Contents/Java/libraries/LiquidCrystal/src/LiquidCrystal.h" // Arduino 1.6.3

#define DISPLAY_MAX_CHAR_PER_LINE 16
#define DISPLAY_MAX_LINES 2
#define DISPLAY_MAX_CHARS (DISPLAY_MAX_LINES * DISPLAY_MAX_CHAR_PER_LINE)

class Display {
 public:
   Display();
   void printChar(char c);
   void clearAllChars();
   void deleteLastChar();
   void sleep();
   void wake_up();
   bool is_sleeping();
   bool is_awake();
 private:
   void _reset();
   void _stepBack();
   void _updateCursor();
   void _printBuffer();
   LiquidCrystal _lcd;
   char _charBuffer[DISPLAY_MAX_CHARS];
   uint8_t _row, _position, _bufferIndex;
   bool _sleeping;
};

#endif

Display.cpp

C/C++
#include "Display.h"

// Arduino c++ classes, How to make instance variables of another class/library
// http://stackoverflow.com/questions/26602268/arduino-c-classes-how-to-make-instance-variables-of-another-class-library

Display::Display () : _lcd(8, 9, 4, 5, 6, 7) {
  // setup display
  _lcd.begin(16, 2);
  
  // initialize counter variables and display cursor
  _reset();
  
  _sleeping = false;
}

void Display::printChar(char c) {
  // check for display constraints
  if (_row >= DISPLAY_MAX_LINES) {
    Serial.println("BEFORE CHAR SHIFT");
    _printBuffer();
    
    //TODO clear first 16 chars from buffer and shift the rest to the front
    for (int i = 0; i < DISPLAY_MAX_CHARS; i++) {
      if (i < DISPLAY_MAX_CHAR_PER_LINE) {
        _charBuffer[i] = _charBuffer[DISPLAY_MAX_CHAR_PER_LINE + i];
      } else {
        _charBuffer[i] = ' ';
      }
    }
    
    Serial.println("AFTER CHAR SHIFT");
    _printBuffer();
    
    //TODO redraw all display characters - clear and write first line
    _lcd.clear();
    
    for (int i = 0; i < DISPLAY_MAX_CHARS; i++) {
      _lcd.print(_charBuffer[i]);
    }
    
    _position = 0;
    _row = DISPLAY_MAX_LINES - 1;
    _bufferIndex = DISPLAY_MAX_CHAR_PER_LINE;
    
    _updateCursor();
  }
    
  Serial.print("row: ");
  Serial.print(_row);
  Serial.print(" - position: ");
  Serial.println(_position);
  
  // print new character to display
  _lcd.print(c);
  
  // save char to buffer
  _charBuffer[_bufferIndex++] = c;
  
  // look ahead for next cursor position
  _position++;
  
  // check for line break
  if (_position >= DISPLAY_MAX_CHAR_PER_LINE) {
    _row++;
    _position = 0;
    
    _updateCursor();
  }
  
  _printBuffer();
}

void Display::clearAllChars() {
  _lcd.clear();
  _reset();
}

void Display::deleteLastChar() {
  _stepBack();
  printChar(' ');
  _stepBack();
}

void Display::sleep(){
  if (!_sleeping) {
    _lcd.noDisplay();
    _sleeping = true;
  }
}

void Display::wake_up(){
  if (_sleeping) {
    _lcd.display();
    _sleeping = false;
  }
}

bool Display::is_sleeping(){
  return _sleeping;
}

bool Display::is_awake(){
  return !_sleeping;
}
   

void Display::_reset() {
  _row = 0;
  _position = 0;
  _bufferIndex = 0;
  
  for (int i = 0; i < DISPLAY_MAX_CHARS; i++) {
    _charBuffer[i] = ' ';
  } 
  
  _lcd.setCursor(_row, _position);
}

void Display::_stepBack() {
  
  if ((_row == 1 || _row == 2) && _position == 0) {
    _position = DISPLAY_MAX_CHAR_PER_LINE - 1;
    _bufferIndex = DISPLAY_MAX_CHAR_PER_LINE - 1;
    _row--;
    _updateCursor();
  } else if (_position != 0) {
    _position--;
    _bufferIndex--;
    _updateCursor();
  }
}

void Display::_updateCursor() {
  _lcd.setCursor(_position, _row);
}

void Display::_printBuffer() {
  Serial.print("[ ");
  for (int i = 0; i < DISPLAY_MAX_CHARS; i++) {
    Serial.print(_charBuffer[i]);
    if (i != DISPLAY_MAX_CHARS - 1) {
      Serial.print(", ");
    }
  }
  Serial.println(" ]");
}

Timer.h

C Header File
#ifndef Timer_h
#define Timer_h

#include <Arduino.h>

class Timer {
  public:
    Timer(unsigned long timerDelay);
    void start();
    void reset();
    void stop();
    bool isRunning();
    bool isStopped();
    bool isFinished();
  private:
    bool _running;
    unsigned long _timerDelay;
    unsigned long _startTime, _millisRead;
};

#endif;

Timer.cpp

C/C++
//#include <Arduino.h>
#include "Timer.h"

Timer::Timer (unsigned long timerDelay) {
  _timerDelay = timerDelay;
  _startTime = 0;
  _running = false;
}

void Timer::start () {
  _startTime = millis();
  
  Serial.print("Timer -> start time: ");
  Serial.println(_startTime);
  Serial.print("Timer -> estimated end time: ");
  Serial.println(_startTime + _timerDelay);
  
  _running = true;
}

void Timer::reset () {
  _startTime = millis();
}

void Timer::stop () {
  _running = false;
}

bool Timer::isRunning () {
  return _running;
}

bool Timer::isStopped () {
  return !_running;
}

bool Timer::isFinished() {
  _millisRead = millis();
  
  if (_running && _millisRead > _startTime + _timerDelay) {
    Serial.print("Timer -> finished: ");
    Serial.println(_millisRead);
    
    _running = false;
    return true;
  } else {
    return false;
  }
}

cardCreator.pde

Processing
Punch card creator made in Processing 3
import processing.pdf.*;

int character = 0; // A
String _charSetMode0[] = {
  "DEL", "Y", "E", "I", "A", "U", "P", "O",
  "SPC", "B", "G", "F", "J", "C", "H", "D",
  " ", "S", "X", "W", "-", "T", "Z", "V",
  ".", "R", "M", "N", "K", "Q", "L", "RESET"
};

String alphabet[] = {
	"A", "B", "C", "D", "E", "F", "G", "H",
	"I", "J", "K", "L", "M", "N", "O", "P",
	"Q", "R", "S", "T", "U", "V", "W", "X",
	"Y", "Z", ".", "-", " ", "DEL", "SPC"
};

PFont theFont;
PGraphics buffer;

// put in the material size in here
PVector materialSize = new PVector(594, 420);
// PVector materialSize = new PVector(300, 220);

int bits = 5; // how many bits are we encoding
PVector cardSize = new PVector(300,72);
PVector tabSize = new PVector(9, 12);
PVector binaryHoles = new PVector(30 , 20);
float offSetSides = 1.315;
float downOffSetSides = 15; // in mm
int howManyCards = 8;

float binaryStopSides = 6;
ArrayList<Punchcard> punchcards = new ArrayList<Punchcard>();

int qqq = 0;

int globalCounter = 24;

Punchcard card;

void setup(){
	// size(mm2pixel(materialSize.x), mm2pixel(materialSize.y));
	size(500, 500);
	buffer = createGraphics(
		mm2pixel(materialSize.x), mm2pixel(materialSize.y), 
		PDF, "tabLow_output"+ globalCounter +".pdf");
	theFont = createFont("DIN Next LT Pro", 18);
	// buffer.beginDraw();
	buffer.beginDraw();
    buffer.textFont(theFont);
	buffer.textAlign(CENTER);
	// start top-left corner
	buffer.stroke(#ff0000);
	buffer.noFill();
	buffer.endDraw();
	
	for(int i = 0; i<alphabet.length; i++) {
		punchcards.add(new Punchcard(i));	
	}
	card = punchcards.get(0);
}

void draw(){
	buffer.beginDraw();
	// buffer.background(255);
	
	for(int i = 0; i<howManyCards; i++) {
		buffer.resetMatrix();
		buffer.translate(mm2pixel(5), mm2pixel(5));
		// pushMatrix();
			if(i < (howManyCards-3)) {
				buffer.translate(0, mm2pixel(cardSize.y*i)+mm2pixel(i*3));

			} else {

				buffer.translate(mm2pixel(cardSize.y*(i-1))+mm2pixel(i*3), mm2pixel(cardSize.x));
				buffer.rotate(radians(-90));
				// buffer.translate(mm2pixel(72*i)+mm2pixel(i*1),0);
				
				
			}
			if(globalCounter < punchcards.size()) {
		card = punchcards.get(globalCounter);
		card.display(buffer);

		globalCounter++;
		}
		else {
			buffer.dispose();
			exit();
		}
		// popMatrix();

	}
	// Punchcard card = punchcards.get(0);
	// card.display();
	// translate(0,mm2pixel(75));
	// card = punchcards.get(1);
	// card.display();
	// delay(500);
	// card.setCharacter(qqq);
	// qqq++;
	// if(qqq > 29) qqq = 0;
	
	// for (Punchcard card : punchcard) {
 	//	card.display();
	// }
	
	noLoop();
	buffer.dispose();
	exit();
	// buffer.endDraw();
}

int inch2pixel(float f) {
	return int(f*72);
}

int mm2pixel(float mm) {
	// 72 = dpi
	return int(round((mm/25.4)*72));
}

int getKey(int n) {
	int c = 0;
	for(int i = 0; i<_charSetMode0.length; i++) {
		if(_charSetMode0[i].equals(alphabet[n])) {
			break;
		}
		c++;
	}
	return c;
}

String getBinary(int i) {
	String b = binary(i,bits);
	return b;
}

String reverseString(String s) {
	char[] c = new char[s.length()];
	for(int i = 0; i<s.length(); i++) {
	    c[i] = s.charAt(i);
	}
	return new String(reverse(c));
}

Punchcard.pde

Processing
Punch card class for the Processing sketch
class Punchcard {
	// PVector cardPosition;
	int character;
	String bin;
	
	Punchcard (int character) {
		// this.cardPosition =  new Pvector(x, y);
		this.character = character;

		// this.character = 12;

		this.bin = getBinary(getKey(this.character));
		// print(this.bin);
		// println(" - " + _charSetMode0[getKey(this.character)]);
		this.character++;

	}

	void display() {
		beginShape();
			vertex(mm2pixel(0),mm2pixel(0));
			// draw tab
			for(int i = 0; i<_charSetMode0.length; i++) {			

				if(i == character) {
				    if(i != 1) {
						vertex(mm2pixel(offSetSides+tabSize.x),mm2pixel(0));
						vertex(mm2pixel(offSetSides+tabSize.x),mm2pixel(tabSize.y));
						vertex(mm2pixel(offSetSides+((tabSize.x)*2)),mm2pixel(tabSize.y));
						vertex(mm2pixel(offSetSides+((tabSize.x*i))),mm2pixel(tabSize.y)); // not for A
					}
					vertex(mm2pixel(offSetSides+((tabSize.x*i))),0);
					vertex(mm2pixel(offSetSides+((tabSize.x*i)+tabSize.x)),mm2pixel(0));
					if(i != _charSetMode0.length-1) {
						vertex(mm2pixel(offSetSides+(((tabSize.x*i)+tabSize.x))),mm2pixel(tabSize.y));
						vertex(mm2pixel((offSetSides*2)+(tabSize.x*_charSetMode0.length-2)), mm2pixel(tabSize.y));
						vertex(mm2pixel((offSetSides*2)+(tabSize.x*_charSetMode0.length-1)), mm2pixel(tabSize.y));
					}
					vertex(mm2pixel((offSetSides*2)+(tabSize.x*_charSetMode0.length-1)), mm2pixel(0));
				break;
				}				
			}
			// draw top-right corner
			vertex(mm2pixel(cardSize.x), mm2pixel(0));

			


			// draw right-bottom corner
			vertex(mm2pixel(cardSize.x), mm2pixel(cardSize.y));
			String rev = reverseString(bin);
			for(int i = 0; i<bits; i++) {
				int b = rev.charAt(i);
			
				// 1 gate
				if(b == 49) {
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y-binaryHoles.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y-binaryHoles.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y));
				} else if(b == 48) {
					// 0 gate
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y-binaryHoles.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryStopSides), mm2pixel(cardSize.y-binaryHoles.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryStopSides), mm2pixel(cardSize.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-(binaryHoles.x-(binaryStopSides))), mm2pixel(cardSize.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-(binaryHoles.x-(binaryStopSides))), mm2pixel(cardSize.y-binaryHoles.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y-binaryHoles.y));
					vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y));
				}
			}
			


			// draw left-bottom corner
			vertex(0, mm2pixel(cardSize.y));



		endShape(CLOSE);
		pushStyle();
			fill(0);
			text(_charSetMode0[getKey(character-1)], mm2pixel(offSetSides+( tabSize.x*character ))+13, mm2pixel(tabSize.y));
		popStyle();

	}
	void display(PGraphics buffer) {
		buffer.beginShape();
			buffer.vertex(mm2pixel(0),mm2pixel(0));
			// draw tab
			for(int i = 0; i<_charSetMode0.length; i++) {			

				if(i == character) {
				    if(i != 1) {
						buffer.vertex(mm2pixel(offSetSides+tabSize.x),mm2pixel(0));
						buffer.vertex(mm2pixel(offSetSides+tabSize.x),mm2pixel(tabSize.y));
						buffer.vertex(mm2pixel(offSetSides+((tabSize.x)*2)),mm2pixel(tabSize.y));
						buffer.vertex(mm2pixel(offSetSides+((tabSize.x*i))),mm2pixel(tabSize.y)); // not for A
					}
					buffer.vertex(mm2pixel(offSetSides+((tabSize.x*i))),0);
					buffer.vertex(mm2pixel(offSetSides+((tabSize.x*i)+tabSize.x)),mm2pixel(0));
					if(i != _charSetMode0.length-1) {
						buffer.vertex(mm2pixel(offSetSides+(((tabSize.x*i)+tabSize.x))),mm2pixel(tabSize.y));
						buffer.vertex(mm2pixel((offSetSides*2)+(tabSize.x*_charSetMode0.length-2)), mm2pixel(tabSize.y));
						buffer.vertex(mm2pixel((offSetSides*2)+(tabSize.x*_charSetMode0.length-1)), mm2pixel(tabSize.y));
					}
					buffer.vertex(mm2pixel((offSetSides*2)+(tabSize.x*_charSetMode0.length-1)), mm2pixel(0));
				break;
				}				
			}
			// draw top-right corner
			buffer.vertex(mm2pixel(cardSize.x), mm2pixel(0));

			


			// draw right-bottom corner
			buffer.vertex(mm2pixel(cardSize.x), mm2pixel(cardSize.y));
			buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(0*2))), mm2pixel(cardSize.y));
			String rev = reverseString(bin);
			for(int i = 0; i<bits; i++) {
				int b = rev.charAt(i);
			
				// 1 gate
				if(b == 49) {
					// buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y-binaryHoles.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y-binaryHoles.y));
					// buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y));
				} else if(b == 48) {
					// 0 gate
					// buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))), mm2pixel(cardSize.y-binaryHoles.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryStopSides), mm2pixel(cardSize.y-binaryHoles.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryStopSides), mm2pixel(cardSize.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-(binaryHoles.x-(binaryStopSides))), mm2pixel(cardSize.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-(binaryHoles.x-(binaryStopSides))), mm2pixel(cardSize.y-binaryHoles.y));
					buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y-binaryHoles.y));
					// buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*(i*2))-binaryHoles.x), mm2pixel(cardSize.y));
				}
			}
			
			buffer.vertex(mm2pixel((cardSize.x-downOffSetSides)-(binaryHoles.x*((bits-1)*2))-binaryHoles.x), mm2pixel(cardSize.y));

			// draw left-bottom corner
			buffer.vertex(0, mm2pixel(cardSize.y));



		buffer.endShape(CLOSE);
		buffer.pushStyle();
		buffer.fill(0);
		buffer.text(_charSetMode0[getKey(character-1)], mm2pixel(offSetSides+( tabSize.x*character ))+12, mm2pixel(tabSize.y)-10);
		buffer.popStyle();
	}

	void setCharacter(int c) {
		this.character = character;

		// this.character = 12;

		this.bin = getBinary(getKey(this.character));
		// print(this.bin);
		// println(" - " + _charSetMode0[getKey(this.character)]);
		this.character++;
	}

}

Credits

Julian Hespenheide

Julian Hespenheide

2 projects • 16 followers
Creative Technologist since 2009

Comments