Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 5 | ||||
| × | 1 | ||||
| × | 5 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
| ||||||
| ||||||
|
émile is a philosophical writing machine using the Baudot code – a binary 5-bit code, predecessor of ASCII and EBCDID – intended for telecommunication and electronic devices, representing the entire alphabet.
Visualizing how electronic signals work can be difficult. A physical model can be useful in overcoming that difficulty. At a workshop entitled “Unboxing Black Boxes” the group of Interaction Designers (Irena, Jasna, David and Julian) created a device to show Baudot code in operation. This amalgam of wood and Arduino was dubbed émile in honor of Émile Baudot (1845-1903).
Baudot developed his code to transmit telegraph signals from one machine to another, in contrast to Morse code which was principally for human communication. Both codes were used throughout the 20th century. For example, those big clattering, mechanical teletype machines use a minor variation of Baudot code.
Baudot is a fixed length code of 5 bits, as opposed to Morse’s variable length code. Morse has a separate code for each characters while Baudot uses “shift’ codes to change between alphabet and figure characters. For instance, a binary 11 would represent either an ‘A’ or a ‘-‘ depending on the shift state. If the shift code was missed the receiver would get gibberish.
In émile the Baudot code is sent by five marbles - one for each bit in the Baudot code. Each marble rolls in a track toward the Arduino. How does the machine know which marbles to send?
Punch cards!Each card represents a code. Each position in the card has a gap to allow a marble to pass (a set bit), or no gap to block the marble (an unset bit). The operator loads 5 marbles and a punch card and launches the marbles via a spring mechanism.
émile runs on Arduino Uno with a standard LCD display to show the letters.
From the interview:
The machine was built in six days with four people. In our group we came to the conclusion, that not every process in a computer is really transparent and it already starts when you type a simple letter on a keyboard. To unwrap this “black box” of data transmission, we set our goal to build a small writing machine where you can literally see bits rolling around. After some research we got back to the beginnings of Telefax machines and data transmission using Baudot-code. We then quickly designed punchcards and mapped them to a slightly altered baudot code table and cut them with a laser cutter from 5mm plywood. Whenever a marble hits a switch, a short timer goes off and waits for input on the other switches. If no other marbles are hitting those switches, we finally translate the switches that have been hit into the corresponding letter.
Take a look at the machine in action:
Arduino Blog feature: https://blog.arduino.cc/2015/08/20/a-tribute-to-5-bit-baudot-code
#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();
}
}
#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
//#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;
}
#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
#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(" ]");
}
#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;
//#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;
}
}
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));
}
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++;
}
}
Comments