OrganProject

Check-in [ac332e3e60]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added serial communications (over a PS/2 [IBM AT] keyboard cable) between the LED control module and the terminal
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ac332e3e6089d85d1fc13c11eb550bb96d97092c
User & Date: 200002852 2009-08-23 03:03:41
Context
2009-08-24
02:45
Added the code to fire the LED's. Breadboard now demonstrates stop selection end-to-end check-in: 41508259dd user: 200002852 tags: trunk
2009-08-23
03:03
Added serial communications (over a PS/2 [IBM AT] keyboard cable) between the LED control module and the terminal check-in: ac332e3e60 user: 200002852 tags: trunk
2009-08-20
03:42
Added wavetables and quick presets check-in: 9970a88933 user: 200002852 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added ledcontrol/Makefile.























































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# Arduino 0015 Makefile
# Arduino adaptation by mellis, eighthave, oli.keller
#
# This makefile allows you to build sketches from the command line
# without the Arduino environment (or Java).
#
# Detailed instructions for using the makefile:
#
#  1. Copy this file into the folder with your sketch. There should be a
#     file with the same name as the folder and with the extension .pde
#     (e.g. foo.pde in the foo/ folder).
#
#  2. Modify the line containg "INSTALL_DIR" to point to the directory that
#     contains the Arduino installation (for example, under Mac OS X, this
#     might be /Applications/arduino-0012).
#
#  3. Modify the line containing "PORT" to refer to the filename
#     representing the USB or serial connection to your Arduino board
#     (e.g. PORT = /dev/tty.USB0).  If the exact name of this file
#     changes, you can use * as a wildcard (e.g. PORT = /dev/tty.usb*).
#
#  4. Set the line containing "MCU" to match your board's processor. 
#     Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth
#     or Diecimila have the atmega168.  If you're using a LilyPad Arduino,
#     change F_CPU to 8000000.
#
#  5. At the command line, change to the directory containing your
#     program's file and the makefile.
#
#  6. Type "make" and press enter to compile/verify your program.
#
#  7. Type "make upload", reset your Arduino board, and press enter to
#     upload your program to the Arduino board.
#
# $Id$

TARGET = $(notdir $(CURDIR))
INSTALL_DIR = /d/Distributions/arduino-0016
PORT = COM1:
UPLOAD_RATE = 19200
AVRDUDE_PROGRAMMER = stk500v1
MCU = atmega168
F_CPU = 16000000

############################################################################
# Below here nothing should be changed...

ARDUINO = $(INSTALL_DIR)/hardware/cores/arduino
AVR_TOOLS_PATH = $(INSTALL_DIR)/hardware/tools/avr/bin
# kbk owns both pieces
#SRC =  $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
#$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
#$(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \
#$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c
# kbk owns both pieces
SRC =  $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
$(ARDUINO)/wiring_pulse.c \
$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c
CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp \
$(ARDUINO)/Print.cpp
FORMAT = ihex


# Name of this Makefile (used for "make depend").
MAKEFILE = Makefile

# Debugging format.
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
DEBUG = stabs

OPT = s

# Place -D or -U options here
CDEFS = -DF_CPU=$(F_CPU)
CXXDEFS = -DF_CPU=$(F_CPU)

# Place -I options here
CINCS = -I$(ARDUINO)
CXXINCS = -I$(ARDUINO)

# Compiler flag to set the C Standard level.
# c89   - "ANSI" C
# gnu89 - c89 plus GCC extensions
# c99   - ISO C99 standard (not yet fully implemented)
# gnu99 - c99 plus GCC extensions
CSTANDARD = -std=gnu99
CDEBUG = -g$(DEBUG)
CWARN = -Wall -Wstrict-prototypes
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)

CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT)
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs 
LDFLAGS = -lm


# Programming support using avrdude. Settings and variables.
AVRDUDE_PORT = $(PORT)
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
AVRDUDE_FLAGS = -V -F -C $(INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf \
-p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
-b $(UPLOAD_RATE)

# Program settings
CC = $(AVR_TOOLS_PATH)/avr-gcc
CXX = $(AVR_TOOLS_PATH)/avr-g++
OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy
OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump
AR  = $(AVR_TOOLS_PATH)/avr-ar
SIZE = $(AVR_TOOLS_PATH)/avr-size
NM = $(AVR_TOOLS_PATH)/avr-nm
AVRDUDE = $(AVR_TOOLS_PATH)/avrdude
REMOVE = rm -f
MV = mv -f

# Define all object files.
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) 

# Define all listing files.
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)

# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)


# Default target.
all: applet_files build sizeafter

build: elf hex 

applet_files: $(TARGET).pde
	# Here is the "preprocessing".
	# It creates a .cpp file based with the same name as the .pde file.
	# On top of the new .cpp file comes the WProgram.h header.
	# At the end there is a generic main() function attached.
	# Then the .cpp file will be compiled. Errors during compile will
	# refer to this new, automatically generated, file. 
	# Not the original .pde file you actually edit...
	test -d applet || mkdir applet
	echo '#include "WProgram.h"' > applet/$(TARGET).cpp
	cat $(TARGET).pde >> applet/$(TARGET).cpp
	cat $(ARDUINO)/main.cxx >> applet/$(TARGET).cpp

elf: applet/$(TARGET).elf
hex: applet/$(TARGET).hex
eep: applet/$(TARGET).eep
lss: applet/$(TARGET).lss 
sym: applet/$(TARGET).sym

# Program the device.  
upload: applet/$(TARGET).hex
	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)


	# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex
ELFSIZE = $(SIZE)  applet/$(TARGET).elf
sizebefore:
	@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi

sizeafter:
	@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi


# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000 


coff: applet/$(TARGET).elf
	$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf $(TARGET).cof


extcoff: $(TARGET).elf
	$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof


.SUFFIXES: .elf .hex .eep .lss .sym

.elf.hex:
	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@

.elf.eep:
	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
	--change-section-lma .eeprom=0 -O $(FORMAT) $< $@

# Create extended listing file from ELF output file.
.elf.lss:
	$(OBJDUMP) -h -S $< > $@

# Create a symbol table from ELF output file.
.elf.sym:
	$(NM) -n $< > $@

	# Link: create ELF output file from library.
applet/$(TARGET).elf: $(TARGET).pde applet/core.a 
	$(CC) $(ALL_CFLAGS) -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS)

applet/core.a: $(OBJ)
	@for i in $(OBJ); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done



# Compile: create object files from C++ source files.
.cpp.o:
	$(CXX) -c $(ALL_CXXFLAGS) $< -o $@ 

# Compile: create object files from C source files.
.c.o:
	$(CC) -c $(ALL_CFLAGS) $< -o $@ 


# Compile: create assembler files from C source files.
.c.s:
	$(CC) -S $(ALL_CFLAGS) $< -o $@
.cpp.s:
	$(CC) -S $(ALL_CFLAGS) $< -o $@


# Assemble: create object files from assembler source files.
.S.o:
	$(CC) -c $(ALL_ASFLAGS) $< -o $@


# Automatic dependencies
%.d: %.c
	$(CC) -M $(ALL_CFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@

%.d: %.cpp
	$(CXX) -M $(ALL_CXXFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@


# Target: clean project.
clean:
	$(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \
	applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/core.a \
	$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)

.PHONY:	all build elf hex eep lss sym program coff extcoff clean applet_files sizebefore sizeafter

include $(SRC:.c=.d)
include $(CXXSRC:.cpp=.d)

Added ledcontrol/ledcontrol.pde.























































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

extern "C" void __cxa_pure_virtual() {
  while (1) {}
}

volatile unsigned long now;

/******************************************************************************
 *                                                                            *
 *                                  PS/2 PORT                                 *
 *                                                                            *
 ******************************************************************************/

/* Definitions */

#define PS2_CLOCK_PIN	2	/* Clock pin */
#define PS2_DATA_PIN	3	/* Data pin */
#define PS2_CLOCK_INTR	0	/* Clock interrupt number */

#define PS2_RING_BUFFER_SIZE 64	/* Length of the input buffer */

#define PS2_MAX_FRAME_TIME 3

/* RAM */

typedef enum {
  PS2_IDLE,			/* Port is idle */
  PS2_READ_DATA_BIT = 0x1,	/* Port is expecting a data bit */
  PS2_READ_PARITY = 0x9,	/* Port is expecting the parity bit */
  PS2_READ_STOP_BIT = 0xA,	/* Port is expecting the stop bit */
} PS2State;

volatile byte ps2State;		/* State of the port */

volatile unsigned short ps2InputBuffer[PS2_RING_BUFFER_SIZE];
				/* Input characters awaiting processing */
volatile byte ps2InputPending;	/* Count of characters in buffer */
volatile byte ps2InputAddIndex;	/* Location in buffer where newly arrived
				 * characters will be added */
volatile byte ps2InputRemoveIndex;
				/* Location in buffer where just-processed
				 * characters will be removed */

volatile unsigned long ps2Timer;
				/* Time at which the current character began
				 * to be transmitted */
volatile byte ps2InputByte;	/* Input character being assembled */
volatile byte ps2Parity;	/* Parity of the partial input character */
byte ps2LastError;		/* Last error state of the port */

#define PS2_ERROR_PARITY 0x1	/* Parity error */
#define PS2_ERROR_FRAMING 0x2	/* Framing error (spacing stop bit) */
#define PS2_ERROR_OVERRUN 0x4	/* Data loss - input buffer overrun */
#define PS2_ERROR_TIMEOUT 0x8	/* Timeout - full data frame  not complete
				 * within required time */
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2GotInput --
 *
 *	Call made when input arrives on the PS/2 port.
 *
 * Parameters:
 *	input -- Byte that arrived in the current data frame. If an error
 *	         has occurred, the byte is ORed with one or more of the
 *		 PS2_ERROR_* flags (shown above) shifted left 8 bits.
 *
 * Side effects:
 *	The newly arrived byte is added to the ring buffer of bytes that
 *	are awaiting processing.
 *
 *-----------------------------------------------------------------------------
 */

void
ps2GotInput(unsigned short input) /* Input byte and error flags */
{

  /* Test for buffer overrun */
  if (ps2InputPending >= PS2_RING_BUFFER_SIZE) {
    byte p = ((int)ps2InputAddIndex - 1) % PS2_RING_BUFFER_SIZE;
    ps2InputBuffer[p] |= 0x400;	/* Overrun */
  } else {

    /* Add the byte to the buffer */

    ps2InputBuffer[ps2InputAddIndex] = input;
    ps2InputAddIndex = (ps2InputAddIndex + 1) % PS2_RING_BUFFER_SIZE;
    ++ps2InputPending;
  }
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2Interrupt --
 *
 *	Interrupt service routine for the PS/2 port.
 *
 * This procedure is called on every falling edge of the clock on the
 * PS/2 port.  It accumulates one data bit and adds any completed byte
 * to the buffer of bytes awaiting processing.
 *
 *-----------------------------------------------------------------------------
 */

void
ps2Interrupt()
{
  /* Read the data bit */
  byte inBit = digitalRead(PS2_DATA_PIN);

  if (ps2State == PS2_IDLE) {	

    /* Is there a start bit, or is the clock pulled low to seize the port? */
    if (inBit == LOW) {

      /* Start bit */
      ps2Timer = now;
      ps2State = PS2_READ_DATA_BIT;
      ps2Parity = 1;
      ps2InputByte = 0;
    }

  } else if (ps2State == PS2_READ_PARITY) {

    /* Parity bit */
    ps2State = PS2_READ_STOP_BIT;
    ps2Parity ^= inBit;

  } else if (ps2State == PS2_READ_STOP_BIT) {

    /* Stop bit */
    ps2GotInput(ps2InputByte 	/* Data payload */
		| ((ps2Parity & 1) << 8)
				/* 0x100 = parity error, 0=OK */
		| ((!inBit) << 9));
				/* 0x200 = framing error, 0=OK */
    ps2State = PS2_IDLE;
  } else {

    /* Data bit */
    ++ps2State;
    ps2InputByte = (ps2InputByte >> 1) | (inBit << 7);
    ps2Parity ^= inBit;
  }

}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2GetByte --
 *
 *	Requests one byte from the PS/2 keyboard port.
 *
 * Results:
 *	Returns TRUE if a byte has been read, and FALSE otherwise.
 *	The 'ps2LastError' variable will be zero if no byte is awaiting,
 *	and otherwise is an OR-ed combination of PS2_ERROR_* flags indicating
 *	what went wrong with the read.
 *
 * Side effects:
 *	The byte just read is stored in *b.
 *
 *-----------------------------------------------------------------------------
 */

byte
ps2GetByte(byte* b)		/* Pointer to the input byte */
{
  unsigned short data;		/* Byte and error flags */

  /* Disable interrupts so that we have atomic access to the buffer */
  noInterrupts();

  /* If there is data in the buffer, remove one frame of data */
  if (ps2InputPending > 0) {
    data = ps2InputBuffer[ps2InputRemoveIndex++];
    ps2InputRemoveIndex %= PS2_RING_BUFFER_SIZE;
    --ps2InputPending;
  } else {
    data = 0x1000;
  }

  /* Interrupts won't bother us again */
  interrupts();

  /* Return byte and error indications */
  *b = (data & 0xff);
  ps2LastError = (data >> 8) & 0xf;
  return ((data & 0x1f00) == 0);
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2Poll --
 *
 *	Routine called from the scan loop to service the PS/2 port.
 *
 * This routine checks if a data frame has taken an unacceptably long time
 * to transfer, and if so, queues a "timeout" indication and forces the
 * port back to the idle state.
 *
 *-----------------------------------------------------------------------------
 */

void
ps2Poll() {

  /* Disable interrupts for buffer manipulation */
  noInterrupts();

  /* 
   * If the port has been hung for too long, force it idle and report the
   * problem.
   */
  if (ps2State != PS2_IDLE 
      && (now - ps2Timer) > PS2_MAX_FRAME_TIME) {
    ps2GotInput(0x800);
    ps2State = PS2_IDLE;
  }

  /* Interrupts are OK again. */
  interrupts();
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2Init --
 *
 *	Routine called from 'setup' to initialize the PS/2 keyboard port.
 *
 * This routine sets the buffer's initial state to 'empty' and its clock
 * and data pins to be bidirectional open-collector digital I/O. It attaches
 * the interrupt service routine to the PS/2 clock.
 *
 *-----------------------------------------------------------------------------
 */

void
ps2Init() {

  /* Set the interface to 'idle' and the input buffer to 'empty'.

  ps2State = PS2_IDLE;
  ps2InputPending = 0;
  ps2InputAddIndex = 0;
  ps2InputRemoveIndex = 0;

  /* Set the pins to high impedance with a pull-up resistor. */

  pinMode(PS2_CLOCK_PIN, INPUT);
  digitalWrite(PS2_CLOCK_PIN, HIGH);
  pinMode(PS2_DATA_PIN, INPUT);
  digitalWrite(PS2_DATA_PIN, HIGH);

  /* Associate the interrupt service routine. */

  attachInterrupt(PS2_CLOCK_INTR, ps2Interrupt, FALLING);
}

void
setup(void)
{
  now = millis();
  Serial.begin(9600);
  ps2Init();
  delay(5);
  interrupts();
}

void
loop(void)
{
  byte b;
  now = millis();

  if (ps2GetByte(&b)) {
    Serial.print(b, BYTE);
  } else if (ps2LastError) {
    Serial.print("\nGot error: ");
    Serial.print((int) ps2LastError, HEX);
    Serial.print(" byte=");
    Serial.println((int)b, HEX);
  }
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 2
 * End:
 */

Changes to terminal/terminal.pde.

4
5
6
7
8
9
10











11
12
13
14
15
16
17
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
667
668
669
670
671
672
673









































































































































































































674
675
676
677
678
679
680
...
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
...
991
992
993
994
995
996
997
998
999
1000




1001
1002
1003


1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022




1023
1024
1025
1026
1027

1028
1029
1030

1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
#include <avr/eeprom.h>

void sendToOrgan(void);

extern "C" void __cxa_pure_virtual() {
  while (1) {}
}











 
/*---------------------------------------------------------------------------*
 *                                                                           *
 *			     	EEPROM LAYOUT				     *
 *									     *
 *---------------------------------------------------------------------------*/

................................................................................
/* Size of the keypad */

#define KP_ROWS 4		/* Number of rows in the keypad */
#define KP_COLS 3		/* Number of columns in the keypad */

/* Timings for polling the keypad */

#define KP_POLL_DELAY_MICROS	10	/* Delay, in microsecods, between 
					 * asserting a keypad row and reading 
					 * the columns */

#define KP_DEBOUNCE_MILLIS	20 	/* Time, in milliseconds, that
					 * keypad input must be stable to be
					 * considered "debounced" */

................................................................................
 */

byte
kpPoll() {

  byte thisState = kpState();	/* Current keyboard state */

  unsigned long now = millis();	/* Current time */

  if (thisState != kpLastState) {

    /*  
     * The keyboard state changed since the last poll.  Wind the debounce
     * timer and report KP_NOKEY
     */

................................................................................
void
dispClear() {
  digitalWrite(DISP_REG_SELECT_PIN, LOW);
  dispWriteByte(0x01);		/* Clear display */
  digitalWrite(DISP_REG_SELECT_PIN, HIGH);
  delayMicroseconds(DISP_CLEAR_DELAY_MICROS);
};









































































































































































































 
/******************************************************************************
 *                                                                            *
 *				MENU SYSTEM				      *
 *                                                                            *
 ******************************************************************************/

................................................................................
      /* Transition to the next menu */
      if (nextMenu != menuCurrent && nextMenu != NULL) {
	menuShow(nextMenu);
      }
    }

    /* Wind the clock */
    menuLastKeyMillis = millis();
  }
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * menuSelHandler --
................................................................................
  return &mainMenu;
}
 
/* TODO - UNSTUB THIS */

void
sendToOrgan(void) {
  dispClear();
  dispWriteStringPGM(PSTR("SEND"));
  delay(2000);




  menuShow(menuCurrent);
}
 


void
setup() {

  kpInit();			/* Initialize the keypad */

  dispInit();			/* Initialize the display */

  menuLastKeyMillis = millis();

#if 0
  Serial.begin(9600);		/* Initialize serial comms with the 
				 * programmer host */
  Serial.println("starting");
  dispMoveTo(0, 0); dispWriteStringPGM(PSTR("1\x01\x07\x08" "1\x03\x05\x08" "2\x02\x04 up^ dn\x06"));
  dispMoveTo(1, 7); dispWriteStringPGM(PSTR("Hello,"));
  dispMoveTo(2, 7); dispWriteStringPGM(PSTR("World!"));
  dispMoveTo(3, 0);
#endif
  menuShow(&mainMenu);




}

void
loop() {
  

  
#if 0
  byte state;


  Serial.print("Button: <");
  state = kpPoll();
  if (state != KP_NOKEY) {
    Serial.print((int)state, HEX);
    Serial.print(">");
    Serial.print((int) pgm_read_byte(brightness+state));
    Serial.println("!");
    dispMoveTo(3,0);
    dispWriteStringPGM(PSTR("Brightness = "));
    dispWriteByte(state/10 ? '1' : ' ');
    dispWriteByte(state%10 + '0');
    dispSetBrightness(state);
  }
#endif
  menuPoll();
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 2
 * End:
 */







>
>
>
>
>
>
>
>
>
>
>







 







|







 







<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|
|
|
>
>
>
>



>
>




|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>




|
>
|
<
|
>

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
..
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
...
248
249
250
251
252
253
254


255
256
257
258
259
260
261
...
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
....
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
....
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249

1250
1251
1252















1253
1254
1255
1256
1257
1258
1259
1260
#include <avr/eeprom.h>

void sendToOrgan(void);

extern "C" void __cxa_pure_virtual() {
  while (1) {}
}

#define FALSE 0
#define TRUE 1

const byte HexTable[] PROGMEM = {
  '0', '1', '2', '3', '4', '5', '6', '7',
  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

unsigned long now;		/* Time at which the scan loop started the
				 * current pass. */
 
/*---------------------------------------------------------------------------*
 *                                                                           *
 *			     	EEPROM LAYOUT				     *
 *									     *
 *---------------------------------------------------------------------------*/

................................................................................
/* Size of the keypad */

#define KP_ROWS 4		/* Number of rows in the keypad */
#define KP_COLS 3		/* Number of columns in the keypad */

/* Timings for polling the keypad */

#define KP_POLL_DELAY_MICROS	10	/* Delay, in microseconds, between 
					 * asserting a keypad row and reading 
					 * the columns */

#define KP_DEBOUNCE_MILLIS	20 	/* Time, in milliseconds, that
					 * keypad input must be stable to be
					 * considered "debounced" */

................................................................................
 */

byte
kpPoll() {

  byte thisState = kpState();	/* Current keyboard state */



  if (thisState != kpLastState) {

    /*  
     * The keyboard state changed since the last poll.  Wind the debounce
     * timer and report KP_NOKEY
     */

................................................................................
void
dispClear() {
  digitalWrite(DISP_REG_SELECT_PIN, LOW);
  dispWriteByte(0x01);		/* Clear display */
  digitalWrite(DISP_REG_SELECT_PIN, HIGH);
  delayMicroseconds(DISP_CLEAR_DELAY_MICROS);
};
 
/******************************************************************************
 *									      *
 *			    PS/2 KEYBOARD DEFINITIONS			      *
 *									      *
 ******************************************************************************/

/* Pin assignments */

#define PS2_CLOCK_PIN	2	/* Clock pin */
#define PS2_DATA_PIN	3	/* Data pin */

/* Timings */

#define PS2_HALF_BIT_MICROS 30 /* 1/2 a bit time on the serial interface */

/* Buffer sizes */

#define PS2_RING_BUFFER_SIZE 64

/* RAM */

byte ps2OutputBuffer[PS2_RING_BUFFER_SIZE];
				/* Buffer of bytes waiting to be written */
byte ps2OutputPending;		/* Count of bytes waiting to be written */
byte ps2OutputAddIndex;		/* Index where the next output byte should
				 * be placed in the buffer */
byte ps2OutputRemoveIndex;	/* Index where the next output byte should
				 * be removed from the buffer */

 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2WritePin --
 *
 *	Write a bit to a pin of the PS/2 keyboard connector, simulating
 *	an open collector output.
 *
 * Side effects:
 *	Output HIGH corresponds to the port being an "input" with a pull-up.
 *	Output LOW corresponds to the port being an "output" with value 0.
 *
 *-----------------------------------------------------------------------------
 */

void
ps2WritePin(byte pin,		/* Pin number */
	    byte value)		/* Value to write */
{
  if (value) {
    pinMode(pin, INPUT);
  } else {
    pinMode(pin, OUTPUT);
  }
  digitalWrite(pin, value);
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2Init --
 *
 *	Initialize the port where this Arduino simulates a PS/2 keyboard.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Configures both pins as inputs, pulled up.
 *
 *-----------------------------------------------------------------------------
 */

void
ps2Init(void)
{
  ps2OutputPending = 0;
  ps2OutputAddIndex = 0;
  ps2OutputRemoveIndex = 0;
  ps2WritePin(PS2_CLOCK_PIN, HIGH);
  ps2WritePin(PS2_DATA_PIN, HIGH);
  delay(5);
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2WriteBit --
 *
 *	Sends one bit of a data frame to the host over the PS/2 port
 *
 * Results:
 *	Returns TRUE if successful, FALSE if the host hass pulled the
 *	CLOCK line low.
 *
 *-----------------------------------------------------------------------------
 */

byte
ps2WriteBit(byte b) {
  if (!digitalRead(PS2_CLOCK_PIN)) {
    return FALSE;
  }
  ps2WritePin(PS2_DATA_PIN, b);
  delayMicroseconds(PS2_HALF_BIT_MICROS);
  if (!digitalRead(PS2_CLOCK_PIN)) {
    ps2WritePin(PS2_DATA_PIN, HIGH);
    return FALSE;
  }
  ps2WritePin(PS2_CLOCK_PIN, LOW);
  delayMicroseconds(PS2_HALF_BIT_MICROS);
  ps2WritePin(PS2_CLOCK_PIN, HIGH);
  return TRUE;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2WriteByte --
 *
 *	Sends an 11-bit frame containing a byte of payload over the PS/2 port
 *
 * Results:
 *	Returns TRUE if OK, FALSE if the other end interrupted the transfer or
 *	the port was not ready
 *
 *-----------------------------------------------------------------------------
 */

byte
ps2WriteByte(byte b) {
  byte parity = 1;		/* The interface uses odd parity */
  byte i;
  if (!ps2WriteBit(LOW)) return FALSE;
  				/* Start bit */
  for (i = 0; i < 8; ++i) {
    if (!ps2WriteBit(b & 1)) return FALSE;
				/* Data bit */
    parity ^= b;
    b >>= 1;
  }
  if (!ps2WriteBit(parity & 1)) return FALSE;
				/* Parity bit */
  if (!ps2WriteBit(HIGH)) return FALSE;
				/* Stop bit returns the interface to idle */
  return TRUE;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2SendByte --
 *
 *	Queues a byte to send to the PS/2 port.
 *
 * Results:
 *	Returns TRUE if there was space in the buffer, FALSE otherwise.
 *
 * Side effects:
 *	Character is transferred to buffer
 *
 *-----------------------------------------------------------------------------
 */

byte
ps2SendByte(byte b)
{
  if (ps2OutputPending == PS2_RING_BUFFER_SIZE) return FALSE;
  ++ps2OutputPending;
  ps2OutputBuffer[ps2OutputAddIndex] = b;
  ps2OutputAddIndex = (ps2OutputAddIndex + 1) % PS2_RING_BUFFER_SIZE;
  return TRUE;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ps2Poll --
 *
 *	Call from the scan loop to service the PS/2 port
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	If the port is ready and a character is pending in the buffer, the
 *	character is sent. 
 *
 *-----------------------------------------------------------------------------
 */

void
ps2Poll() {
  if (ps2OutputPending) {
    if (ps2WriteByte(ps2OutputBuffer[ps2OutputRemoveIndex])) {
      ps2OutputPending--;
      ps2OutputRemoveIndex = (ps2OutputRemoveIndex + 1) % PS2_RING_BUFFER_SIZE;
    }
  }
}
 
/******************************************************************************
 *                                                                            *
 *				MENU SYSTEM				      *
 *                                                                            *
 ******************************************************************************/

................................................................................
      /* Transition to the next menu */
      if (nextMenu != menuCurrent && nextMenu != NULL) {
	menuShow(nextMenu);
      }
    }

    /* Wind the clock */
    menuLastKeyMillis = now;
  }
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * menuSelHandler --
................................................................................
  return &mainMenu;
}
 
/* TODO - UNSTUB THIS */

void
sendToOrgan(void) {
  int i;
  ps2SendByte('S');
  for (i = 0; i < 16; ++i) {
    ps2SendByte(pgm_read_byte(HexTable + (selectedStop[i] >> 4)));
    ps2SendByte(pgm_read_byte(HexTable + (selectedStop[i] & 0xf)));
  }
  ps2SendByte('\n');
  menuShow(menuCurrent);
}
 
/* TEMP */

void
setup() {

  kpInit();			/* Initialize the keypad */
  dispInit();			/* Initialize the display */
  ps2Init();			/* Initialize the communication port */

  now = millis();
  menuLastKeyMillis = now;
  menuShow(&mainMenu);

  /* TEMP - Prime the PS/2 port with some test data */

  {
    char* p;
    byte c;
    for (p = PSTR("TEST U*U*U*U*U*U*U*U*U*U*U*U*\r\n");
	 (c = pgm_read_byte(p)) != '\0';
	 ++p) {
      ps2SendByte(c);
    }
  }
  
}

void
loop() {

  now = millis();


  menuPoll();			/* Service the keyboard and display */
  ps2Poll();			/* Service the communication port */
















}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 2
 * End:
 */