first commit

This commit is contained in:
Dave 2019-12-12 14:46:29 -06:00
commit 784805adc7
80 changed files with 33351 additions and 0 deletions

26
README.md Normal file
View File

@ -0,0 +1,26 @@
## Universal ASCII Keyboard
This project aims to provide a (near) universal ASCII keyboard for vintage computers. Home computers of the 1970's typically either polled a switch matrix, or interfaced to a parallel ASCII keyboard via a parallel port.
The keyboard will allow use of Cherry MX keys, or Futaba MD-4PCS keys.
The keyboard supports diodes per-switch for true N-key rollover, or
per-row (like the OSI).
The keyboard is designed using KiCad in order to be the most useful for anybody wishing to modify the keyboard for more specific uses, or to add to the project.
Goals for the keyboard:
- Drop in replacement for Ohio Scientific polled keyboards
-- Done: drop in for OSI 542 (untested).
-- Done: keycap set available
-- To do: module for advanced 542B/C features
- Drop in replacement for Apple II keyboard
--To do: Add-in ASCII module required
--To do: Add power light and power light cover
--To do: Special Apple keycaps needed.
- Standard ASCII parallel keyboard
-- Done: Keycap set available
-- To do: Add-in ASCII keyboard

126
firmware/asdf/README.md Normal file
View File

@ -0,0 +1,126 @@
-*- text -*-
- asdf Keyboard scanning firmware
The ASDF (Auto Scan by DF) firmware is a key matrix scanner that can detect and
debounce keypress and release events on a key matrix and either send codes or
perform actions on keypress or release. Keymaps are defined per application and
may, for example, generate ASCII codes, special keyscan codes, etc. The code is
modular and may be integrated into a larger system easily.
By default, the code supports any number of rows by 8 columns, which will give
the bestperformance on an 8-bit microcontroller. For more than 8 columns per
row, the row datatype would need to be changed to uint16_t to support 16
columns, etc.
The first supported application is a parallel ASCII output keyboard. If you want
serial or USB output, you can supply your own routines.
ASDF supports basic keyboard functionality and is configurable via a few
boolean variables, and via the key maps. The key maps are organized in
row,column format, with separate keymaps shift, capslock, and control-key modes.
Features:
* modifiers: A set of modifier keys may be specified. When only a few modifiers
are used, this mechanism is a low-overhead alternative to a keymap overlay for
keyboard states that only change the key value, such as SHIFT, CAPS LOCK, CONTROL,
etc. The state of each modifier key is kept in a state variable. In most
cases, pressing the key will set the value to a "pressed" state, and releasing
will reset the value to an "unpressed" state. However some functions interact.
For example, Shift Lock is sticky, so pressing Shift Lock toggles the Shift
Lock state, and Releasing Shift Lock does nothing; but pressing "Shift" will
reset the "Shift Lock" state.
All modifier state variables are kept in a modifier state variable array. On a
regular keypress, all of the modifier state variables are OR'ed together to
produce an index into a value array for the standard key, to determine the
value sent by the standard keypress.
* DIP switches: DIP switches are implemented by adding them into the key
matrix, and providing activate() and deactivate() functions for the on and off
positions.
* Spinners/rotary encoders: Rotary encoders can be implemented by adding the
encoder switches into the matrix, and driving the encoder state machine via
the activate() and deactivate() functions.
* sticky keys: Stick keys remain active until another key is pressed. This
functionality is supported by the per-key activate() and deactivate() functions.
For example, for sticky "control", replace control_deactivate() with
null_deactivate() as the deactivate function for the control key, and add a
call to "control_deactivate()" in the "standard_keypress_postprocess_hook()" function.
* Indicators: Controlled via activate() and deactivate() functions for the various keys.
* Debounce and Repeat functions: The main keyscan logic implements key
debouncing. Multiple keys may be debounced simultaneously using a separate
debounce counter for each key in the matrix.
* Repeat key and Autorepeat: This is provided by the repeat module. Autorepeat
may be disabled or enabled either by configuration, by activate()/deactivate()
functions, or other keyboard logic. Repeat and autorepeat only apply to the
most recently pressed key.
* (Future feature) NVRAM: For architectures that support EEPROM or other non-volatile storage,
configuration parameters are stored in non-volatile storage to survive a power
cycle.
* ASCII output - supported via output_value function.
* (Future feature) Serial, USB CDC, USB HID interfaces - supportable via output_value function.
* Indicator LEDs and other direct logic-level hardware controls: supported via
per-key activate/deactivate functions, and also via hooks to standard key
functions.
Compiling and configuration
The source files are in the ./src directory. The final build files go in the ./build directory.
To build, enter the ./src directory. You should be able to build a binary and
hex file suitable for programming a microcontroller by typing "Make". You may
edit the Makefile to specify your target platform (default is Atmega328P ASCII
controller). You may also wish to edit your preferences in "asdf_config.h" to
specify repeat timings, optimize the debounce setting (if you have very bounce
keys), and specify the character output buffer size (if you are implementing
macros, etc.)
Porting
This firmware was written in modular, portable C99, to be compiled with GCC
(avr-gcc for the Atmega). The hardware-sepecific files are in Arch/*.[ch]. To
adapt the Atmega port for additional hardware, enter the ./src/Arch directory,
and copy the files asdf_arch_atmega328p.c and asdf_arch_astmega328p.h to new
filenames, and edit them to suit the hardware changes.
The firmware is designed to run from ROM on a slow vintage processor, with a
small RAM footprint, and is not re-entrant. It is designed to compile on small
architectures, or to be hand-translated to assembly on small processors, or to
an HDL for a CPLD or FPGA.
The code was written to favor readability over cleverness. While tempted to
optimize bit testing via bithacks, I opted for code simplicity since the
performance benefit was not there for 8-bit values.
To port to a new processor architecture, you may use the atmega328p files as an
example, and create a pair of architecture-specific .c and .h files for the new
hardware, exporting the following functions:
- asdf_arch_init: initializes the CPU and hardware
- asdf_arch_read_row: given a row number, output the row to the matrix, and read
all the columns on that row asdf_arch_send_code
- asdf_arch_send_code: given a key code, output the code to the computer, via
serial, parallel, I2C, whatever is appropriate.
- asdf_arch_tick: true once every 1ms. This tests a flag set in an interrupt
routine that is triggered every 1ms. The function return value is polled and a
keyscan initiated when true. An alternative, if you have an RTOS, or even just
a scheduler, would be to schedule the keyscan every 1 ms, rather than poll. In
that case, this function is not needed, and the "superloop" in main.c would
contain a call to the scheduler.

View File

@ -0,0 +1 @@
This directory contains the files resulting from the build process

View File

@ -0,0 +1,448 @@
// -*- mode: C; tab-width: 2 ; indent-tabs-mode: nil -*-
//
// Universal Keyboard Project
// ASDF keyboard firmware
//
// asdf_arch.c
//
// This file contains all the architecture dependent code, including register
// setup, I/O, timers, etc.
//
// Copyright 2019 David Fenyes
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
// Wiring Information:
// Chip: {Microcontroller type and version}
//
// Example:
// PIN NAME FUNCTION
// 14-19,9,10 PORTB COLUMN inputs (1 bit per column)
// 23-25 PORTC0-2 ROW outputs (row number)
// 27 PORTC4
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>
#include "asdf_arch.h"
static volatile uint8_t tick = 0;
static uint8_t data_polarity = 0; // normally positive polarity
static uint8_t strobe_polarity = 0; // normally positive polarity
// PROCEDURE: ISR for Timer 0 overflow
// INPUTS: none
// OUTPUTS:none
//
// DESCRIPTION: Occurs every 1 ms. Set tick flag, kick watchdog.
//
// SIDE EFFECTS:
//
// NOTES:
//
// SCOPE:
//
// COMPLEXITY:
//
ISR(TIMER0_COMPA_vect)
{
tick = 1;
}
// PROCEDURE: set_bit
// INPUTS: port: pointer to a (uint8) port
// bit: bit position to be set
// OUTPUTS: none
//
// DESCRIPTION: Give a port address and bit position, set the bit position.
//
// SIDE EFFECTS: See DESCRIPTION
//
// NOTES: Declared inline. Will only be inlined for functions in this module, so
// also declared static.
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static inline void set_bit(volatile uint8_t *port, uint8_t bit)
{
*port |= (1 << bit);
}
// PROCEDURE: clear_bit
// INPUTS: port: pointer to a (uint8) port
// bit: bit position to be cleared
// OUTPUTS: none
//
// DESCRIPTION: Give a port address and bit position, clear the bit position.
//
// SIDE EFFECTS: See DESCRIPTION
//
// NOTES: Declared inline. Will only be inlined for functions in this module, so
// also declared static.
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static inline void clear_bit(volatile uint8_t *port, uint8_t bit)
{
*port &= ~(1 << bit);
}
// PROCEDURE: arch_timer0_config
//
// INPUTS: bits: a 4 byte field containing the configuration values for the
// 8-bit timer0 A and B control registers, and the interrupt mask register.
//
// OUTPUTS: none
//
// DESCRIPTION: Takes a 4 byte value with settings for all the control
// registers for the 8-bit counter/timer (timer 0), and writes them all
// to the respective registers.
//
// SIDE EFFECTS: see above
//
// NOTES: Setting all the bits together, and writing all the registers from a
// single word permits more clear initialization of control fields that are
// spread across more than one word.
//
// COMPLEXITY: 1
//
// SCOPE: private
//
static void arch_timer0_config(uint32_t bits)
{
TCCR0B = 0; // first turn off timer.
TCCR0A = (bits >> TMR0A_POS) & 0xff;
TIMSK0 = (bits >> TMR0IMSK_POS) & 0xff;
TCCR0B = (bits >> TMR0B_POS) & 0xff; // Set the mode (and turn on timer) last
}
// PROCEDURE: arch_tick_timer_init
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Sets up 1ms tick timer.
//
// SIDE EFFECTS:
//
// NOTES: Set up Timer 0 in CTC mode for 1 ms overflow.
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static void asdf_arch_tick_timer_init(void)
{
tick = 0;
// set compare register first, so timer can operate correctly as soon as it is
// enabled.
OCR0A = TICK_COUNT;
// operate in CTC mode to overflow at exactly 1 ms
// prescaler = 64 and output compare value is 250
arch_timer0_config(TIMER0_WFM_CTC | TIMER0_DIV64 | TIMER0_INT_ON_COMA);
}
// PROCEDURE: asdf_arch_tick
// INPUTS: none
// OUTPUTS: returns a 1 if the 1ms timer timed out, 0 otherwise
//
// DESCRIPTION: See Outputs.
//
// SIDE EFFECTS: Zeroes out the 1 ms timer flag.
//
// NOTES:
//
// SCOPE: public
//
// COMPLEXITY: 1
//
uint8_t asdf_arch_tick(void)
{
uint8_t retval = tick;
tick = 0;
return retval;
}
// PROCEDURE: asdf_arch_init_timers
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Sets up timer for 1 ms intervals
//
// SIDE EFFECTS: See DESCRIPTION
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static void asdf_arch_init_clock(void)
{
CLKPR = (CLKPCE | SYSCLK_DIV1);
}
// PROCEDURE: asdf_arch_init_special_outputs
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Sets up special output lines for LED indicator(s), System RESET
// and SCREEN CLEAR, etc.
//
// SIDE EFFECTS: See DESCRIPTION
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static void asdf_arch_init_special_outputs(void)
{
// initialize CAPS LED to OFF
clear_bit(&ASDF_CAPS_LED_PORT, ASDF_CAPS_LED_BIT);
set_bit(&ASDF_CAPS_LED_DDR, ASDF_CAPS_LED_BIT);
// initialize SCREEN_CLEAR output line to LOW (inactive)
clear_bit(&ASDF_SCREEN_CLEAR_PORT, ASDF_SCREEN_CLEAR_BIT);
set_bit(&ASDF_SCREEN_CLEAR_DDR, ASDF_SCREEN_CLEAR_BIT);
// initialize /SYS_RESET output line to HIGH (inactive)
set_bit(&ASDF_SYS_RESET_PORT, ASDF_SYS_RESET_BIT);
set_bit(&ASDF_SYS_RESET_DDR, ASDF_SYS_RESET_BIT);
// initialize /STROBE output to inactive. Must test before set/clear to avoid spurious strobe
if (strobe_polarity) {
set_bit(&ASDF_STROBE_PORT, ASDF_STROBE_BIT);
}
else {
clear_bit(&ASDF_STROBE_PORT, ASDF_STROBE_BIT);
}
set_bit(&ASDF_STROBE_DDR, ASDF_STROBE_BIT);
}
// PROCEDURE: asdf_arch_init_ascii_output
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Sets up output port for ASCII output
//
// SIDE EFFECTS: See DESCRIPTION
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static void asdf_arch_init_ascii_output(void)
{
// set all outputs
ASDF_ASCII_PORT = 0;
ASDF_ASCII_DDR = ALL_OUTPUTS;
}
// PROCEDURE: asdf_arch_init_column_inputs
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: configure the shift register control lines. The MODE control is
// LOW for shift and HIGH for load. Shift or Load occurs when CLK goes high.
//
// SIDE EFFECTS: Cont
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static void asdf_arch_init_column_control(void)
{
// COLCLK is output and initialized LOW
clear_bit(&ASDF_COLCLK_PORT, ASDF_COLCLK_BIT);
set_bit(&ASDF_COLCLK_DDR, ASDF_COLCLK_BIT);
// COLMODE is output and initialized HIGH
set_bit(&ASDF_COLMODE_PORT, ASDF_COLMODE_BIT);
set_bit(&ASDF_COLMODE_DDR, ASDF_COLMODE_BIT);
// COL is input, no weak pullup.
clear_bit(&ASDF_COL_DDR, ASDF_COL_BIT);
clear_bit(&ASDF_COL_PORT, ASDF_COL_BIT);
}
// PROCEDURE: asdf_arch_init_row_outputs
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Sets up output port to latch keyboard matrix row for scanning.
//
// SIDE EFFECTS: See DESCRIPTION
//
// SCOPE: private
//
// COMPLEXITY: 1
//
static void asdf_arch_init_row_outputs(void)
{
ASDF_ROW_PORT &= ~ASDF_ROW_MASK;
ASDF_ROW_DDR |= ASDF_ROW_MASK;
}
// PROCEDURE: asdf_arch_init
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: sets up all the hardware for the keyboard
//
// SIDE EFFECTS: see DESCRIPTION
//
// SCOPE: public
//
// COMPLEXITY: 1
//
void asdf_arch_init(void)
{
// disable interrupts:
cli();
// clear the 1ms timer flag;
tick = 0;
// set up timers for 1 msec intervals
asdf_arch_init_clock();
asdf_arch_tick_timer_init();
// set up ASCII output port
asdf_arch_init_ascii_output();
// initialize keyboard data and strobe to positive polairy
data_polarity = 0;
strobe_polarity = 0;
// set up strobe output
// set up indicator output
// set up RESET output
// set up CLEAR output
asdf_arch_init_special_outputs();
// set up row output port
asdf_arch_init_row_outputs();
// set up column control lines
asdf_arch_init_column_control();
// enable interrupts:
sei();
}
// PROCEDURE: asdf_arch_read_row
// INPUTS: (uint8_t) row: the row number to be scanned
// OUTPUTS: returns a word containing the active (pressed) columns
//
// DESCRIPTION: Outputs the argument to the ROW port, then reads the column port
// and returns the value. The value is a binary representation of the keys
// pressed within the row, with 1=pressed, 0=released.
//
// SIDE EFFECTS: Sets ROW output port.
//
// NOTES:
//
// 1) The keymap represents an unpressed key as a "0" and a pressed key as a
// "1". So, if a keypress pulls the column line low, then the reading of the
// physical bits must be inverted.
//
// SCOPE: public
//
// COMPLEXITY: 1
//
asdf_cols_t asdf_arch_read_row(uint8_t row)
{
asdf_cols_t cols = 0;
// first, output the new row value:
ASDF_ROW_PORT = (ASDF_ROW_PORT & ~ASDF_ROW_MASK) | row << ASDF_ROW_OFFSET;
// read in the columns. Set LOAD mode and pulse clock.
clear_bit(&ASDF_COLMODE_PORT, ASDF_COLMODE_BIT);
set_bit(&ASDF_COLCLK_PORT, ASDF_COLCLK_BIT);
clear_bit(&ASDF_COLCLK_PORT, ASDF_COLCLK_BIT);
// set back to SHIFT mode
set_bit(&ASDF_COLMODE_PORT, ASDF_COLMODE_BIT);
// After the load operation, the LSB is already at the output pin, so there
// will be one fewer read than clock pulse. Continue reading the bits until
// the leader bit is in the boundary position.
for (uint8_t i = 0; i < ASDF_NUM_COLS; i++) {
// invert the bits as they are read (see note 1)
cols |= (((~(ASDF_COL_PIN) >> ASDF_COL_BIT) & 1) << i);
set_bit(&ASDF_COLCLK_PORT, ASDF_COLCLK_BIT);
clear_bit(&ASDF_COLCLK_PORT, ASDF_COLCLK_BIT);
}
return cols;
}
// PROCEDURE: asdf_arch_send_code
// INPUTS: (keycode_t) code - the 7-bit ASCII code to be output by the keyboard
// OUTPUTS: none
//
// DESCRIPTION: Takes a character code and outputs the code on a parallel ASCII
// port, with a strobe. This routine could be replaced with UART, I2C, USB, or
// other output mechanism, of course.
//
// SIDE EFFECTS: See above.
//
// NOTES: The strobe is set by the ASDF_STROBE_LENGTH definition. The data
// output and strobe polarity are set by the static data_polarity and static
// strobe_polarity variables.
//
// SCOPE:
//
// COMPLEXITY:
//
void asdf_arch_send_code(asdf_keycode_t code)
{
ASDF_ASCII_PORT = (code ^ data_polarity);
// toggle strobe. Must test before setting to avoid spurious strobe
set_bit(&ASDF_STROBE_PINS, ASDF_STROBE_BIT);
_delay_us(ASDF_STROBE_LENGTH_US);
set_bit(&ASDF_STROBE_PINS, ASDF_STROBE_BIT);
}
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.
//

View File

@ -0,0 +1,267 @@
// -*- mode: C; tab-width: 4 ; indent-tabs-mode: nil -*-
//
// Universal Keyboard Project
// ASDF keyboard firmware
//
// asdf_arch_atmega328p.h
//
// Contains architecture-specific definitions for the atmega 328p.
//
//
// Copyright 2019 David Fenyes
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
#if !defined(ASDF_ARCH_H)
#define ASDF_ARCH_H
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "asdf.h"
// ASDF keyboard definitions:
#define ASDF_STROBE_LENGTH_US 10 // strobe length in microseconds
// Clock definitions:
#define SYSCLK_DIV1 0
#define SYSCLK_DIV2 (CLKPS0)
#define SYCCLK_DIV4 (CLKPS1)
#define SYSCLK_DIV8 (CLKPS1 | CLKPS0)
#define SYSCLK_DIV16 (CLKPS2)
#define SYSCLK_DIV32 (CLKPS2 | CLKPS0)
#define SYSCLK_DIV64 (CLKPS2 | CLKPS1)
#define SYSCLK_DIV128 (CLKPS2 | CLKPS1 | CLKPS0)
#define SYSCLK_DIV256 (CLKPS3)
// Define fields for register A, B, interrupt mask as 8-bit masks, and
// as masks offset into a combined config word
#define TMR0A_POS 0
#define TMR0B_POS 8
#define TMR0IMSK_POS 16
#define TMR0A (1L << TMR0A_POS)
#define TMR0B (1L << TMR0B_POS)
#define TMR0IMSK (1L << TMR0IMSK_POS)
#define TIMER0_COM_A_DISCONNECTED 0
#define TIMER0_COM_B_DISCONNECTED 0
#define TIMER0_WFM_CTC (TMR0A << WGM01)
#define TIMER0_DIV64 ((TMR0B << CS01) | (TMR0B << CS00))
#define TIMER0_INT_ON_COMA (TMR0IMSK << OCIE0A)
#define TIMER0_INT_ON_COMB (TMR0IMSK << OCIE0B)
#define TIMER0_INT_OV_ENABLE (TMR0IMSK << TOIE0)
// Macros for 16-bit timer 1. ATmega328P datasheet section 15, p. 108
//
// Define fields for Registers A, B, C, INT Mask registers as 8-bit
// masks, and as masks offset into a 32-bit combined config word.
//
// Macro definitions for individual registers are named TMR1A_*,
// TMR1B_*, and TMR1C_*.
//
// Macros for the one-step combined timer config functions are named
// TMR1_*.
//
//
// Examples:
// // Use TMR1B_* definition to set TCCR1B register
// TCCR1B |= TMR1B_DIV1;
//
// // Use TMR1_* definitions to configure timer with config function
// timer1_config(TMR1_WFM_CTC | TMR1_INT_ON_CMPA);
//
#define TMR1A_POS 0
#define TMR1B_POS 8
#define TMR1C_POS 16
#define TMR1IMSK_POS 24
#define TMR1A (1L << TMR1A_POS)
#define TMR1B (1L << TMR1B_POS)
#define TMR1C (1L << TMR1C_POS)
#define TMR1IMSK (1L << TMR1IMSK_POS)
// 16-bit timer reg A - Datasheet 17.11.1, p. 154
#define TMR1A_CMPA_CLR_MATCH_SET_BOTTOM (1 << COM1A1)
#define TMR1A_CMPB_CLR_MATCH_SET_BOTTOM (1 << COM1B1)
#define TMR1A_CMPC_CLR_MATCH_SET_BOTTOM (1 << COM1C1)
#define TMR1_CMPA_CLR_MATCH_SET_BOTTOM (TMR1A << COM1A1)
#define TMR1_CMPB_CLR_MATCH_SET_BOTTOM (TMR1A << COM1B1)
#define TMR1_CMPC_CLR_MATCH_SET_BOTTOM (TMR1A << COM1C1)
// 16-bit timer reg B - Datasheet 17.11.6, p. 156
#define TMR1B_IN_CAP_POS 0x40L
#define TMR1B_IN_CAP_NEG 0L
#define TMR1B_IN_CAP_NOISE_CANCEL 0x80L
// 16-bit timer reg C -- see datasheet, 17.11.9, p. 157
#define TMR1C_FOCA 0x80L
#define TMR1C_FOCB 0x40L
#define TMR1C_FOCC 0x20L
// 16-bit timer int mask -- see datasheet 17.11.33, p. 161.
#define TMR1IM_INT_CMP_MATCH_A (1L << OCIE1A)
#define TMR1IM_INT_CMP_MATCH_B (1L << OCIE1B)
#define TMR1IM_INT_CMP_MATCH_C (1L << OCIE1C)
// 16-bit timer all registers:
#define TMR1_CMPA_DISCONNECTED 0L
#define TMR1_CMPB_DISCONNECTED 0L
#define TMR1_CMPC_DISCONNECTED 0L
#define TMR1_INT_ON_CMPA (TMR1IM_INT_CMP_MATCH_A << TMR1IMSK_POS)
// 16-bit timer clock modes - see Datasheet table 17-6, p. 157
#define TMR1B_OFF 0
#define TMR1_OFF 0
#define TMR1B_DIV1 (0x01L << CS10)
#define TMR1B_DIV8 (0x02L << CS10)
#define TMR1B_DIV64 (0x03L << CS10)
#define TMR1B_DIV256 (0x04L << CS10)
#define TMR1B_DIV1024 (0x05L << CS10)
#define TMR1B_EXT_FALLING_EDGE (0x06L << CS10)
#define TMR1B_EXT_RISING_EDGE (0x07L << CS10)
#define TMR1B_CLK_MASK 0x07L
#define TMR1_DIV1 (TMR1B_DIV1 << TMR1B_POS)
#define TMR1_DIV8 (TMR1B_DIV8 << TMR1B_POS)
#define TMR1_DIV64 (TMR1B_DIV64 << TMR1B_POS)
#define TMR1_DIV256 (TMR1B_DIV256 << TMR1B_POS)
#define TMR1_DIV1024 (TMR1B_DIV1024 << TMR1B_POS)
#define TMR1_EXT_FALLING_EDGE (TMR1B_EXT_FALLING_EDGE << TMR1B_POS)
#define TMR1_EXT_RISING_EDGE (TMR1B_EXT_RISING_EDGE << TMR1B_POS)
#define TMR1B_EDGE_SEL_POSITIVE (1 << ICES1)
#define TMR1B_EDGE_SEL_NEGATIVE 0L
#define TMR1_EDGE_SEL_POSITIVE (TMR1B << ICES1)
#define TMR1_EDGE_SEL_NEGATIVE 0L
// 16-bit waveform modes (across reg A and B) Datasheet Table 17.2, p 145
#define TMR1_WFM_NORMAL 0L
#define TMR1_WFM_PWM_PC8 (TMR1A << WGM10) // PWM Phase Correct 8-bit
#define TMR1_WFM_PWM_PC9 (TMR1A << WGM11) // PWM Phase COrrect 9-bit
#define TMR1_WFM_PWM_PC10 ((TMR1A << WGM11) | (TMR1A << WGM10)) // PWM Phase Correct 10-bit
#define TMR1_WFM_CTC (TMR1B << WGM12) // CTC
#define TMR1_WFM_PWM_FAST8 ((TMR1B << WGM12) | (TMR1A << WGM10)) // PWM Fast 8-bit
#define TMR1_WFM_PWM_FAST9 ((TMR1B << WGM12) | (TMR1A << WGM11)) // PWM Fast 9-bit
#define TMR1_WFM_PWM_FAST10 \
((TMR1B << WGM12) | (TMR1A << WGM11) | (TMR1A << WGM10)) // PWM Fast 10-bit
#define TMR1_WFM_PWM_PFC_ICR (TMR1B << WGM13) // PWM Phase and Freq Correct, TpOP=ICR
#define TMR1_WFM_PWM_PFC_OCRA \
((TMR1B << WGM13) | (TMR1A << WGM10)) // PWM Phase and Freq Correct, TOP = OCRA
#define TMR1_WFM_PWM_PC_ICR ((TMR1B << WGM13) | (TMR1A << WGM11)) // PWM PhaseCorrect, TOP = ICR
#define TMR1_WFM_PWM_PC_OCRA \
((TMR1B << WGM13) | (TMR1A << WGM11) | (TMR1A << WGM12)) // PWM PhaseCorrect, TOP=OCRA
#define TMR1_WFM_CTC_ICR ((TMR1B << WGM13) | (TMR1B << WGM12)) // CTC, TOP = ICR
#define TMR1_WFM_PWM_FAST_ICR \
((TMR1B << WGM13) | (TMR1B << WGM12) | (TMR1A << WGM11)) // PWM Fast, TOP = ICR
#define TMR1_WFM_PWM_FAST_OCRA \
((TMR1B << WGM13) | (TMR1B << WGM12) | (TMR1A << WGM11) \
| (TMR1A << WGM10)) // PWM Fast, TOP = OCRA
// I/O port definitions:
#define PIN_INPUT 0
#define PIN_OUTPUT 1
#define ALL_INPUTS 0
#define ALL_OUTPUTS 0xff
#define ASDF_ROW_PORT PORTC
#define ASDF_ROW_DDR DDRC
#define ASDF_ROW_MASK 0x07
#define ASDF_ROW_OFFSET 0
#define ASDF_COL_PORT PORTB
#define ASDF_COL_PIN PINB
#define ASDF_COL_DDR DDRB
#define ASDF_COL_BIT 0
#define ASDF_COL_PULLUPS 0 // disable weak pullup
#define ASDF_COLCLK_PORT PORTB
#define ASDF_COLCLK_PINS PINB
#define ASDF_COLCLK_DDR DDRB
#define ASDF_COLCLK_BIT 2
#define ASDF_COLMODE_PORT PORTB
#define ASDF_COLMODE_PINS PINB
#define ASDF_COLMODE_DDR DDRB
#define ASDF_COLMODE_BIT 1
#define ASDF_ASCII_PORT PORTD
#define ASDF_ASCII_DDR DDRD
#define ASDF_CAPS_LED_PORT PORTC
#define ASDF_CAPS_LED_DDR DDRC
#define ASDF_CAPS_LED_BIT 3
#define ASDF_SCREEN_CLEAR_PORT PORTC
#define ASDF_SCREEN_CLEAR_DDR DDRC
#define ASDF_SCREEN_CLEAR_BIT 4
#define ASDF_SYS_RESET_PORT PORTC
#define ASDF_SYS_RESET_DDR DDRC
#define ASDF_SYS_RESET_BIT 5
#define ASDF_STROBE_PORT PORTB
#define ASDF_STROBE_PINS PINB
#define ASDF_STROBE_DDR DDRB
#define ASDF_STROBE_BIT 6
#define FUSE_INTERNAL_8MHZ_OSC_0MS (FUSE_CKSEL0 | FUSE_CKSEL2 | FUSE_CKSEL3 | FUSE_SUT0 | FUSE_SUT1)
#define FUSE_INTERNAL_8MHZ_OSC_4MS (FUSE_CKSEL0 | FUSE_CKSEL2 | FUSE_CKSEL3 | FUSE_SUT1)
#define FUSE_INTERNAL_8MHZ_OSC_65MS (FUSE_CKSEL0 | FUSE_CKSEL2 | FUSE_CKSEL3 | FUSE_SUT0)
#define FLASH PROGMEM
// not implemented with do-while(0) because this is a function call that returns
// a value, and parameters are expanded inside the parameter list, so this will
// be valid when substituting for function-like syntax.
#define FLASH_READ (a) pgm_read_byte((a))
#define FLASH_READ_MATRIX_ELEMENT(matrix, row, col) pgm_read_byte(&((matrix)[(row)][(col)]))
// For 1 ms tick, (8000000 / 64(prescale)) / 1000(usec) - 1 = 124
#define TICK_COUNT 124
// PROCEDURE: asdf_arch_read_row
// INPUTS: (uint8_t) row: the row number to be scanned
// OUTPUTS: returns a word containing the active (pressed) columns
// DESCRIPTION: Outputs the argument to the ROW port, then reads the column port
// and returns the value. The value is a binary representation of the keys
// pressed within the row, with 1=pressed, 0=released.
asdf_cols_t asdf_arch_read_row(uint8_t row);
// PROCEDURE: asdf_arch_tick
// INPUTS: none
// OUTPUTS: returns a 1 if the 1ms timer timed out, 0 otherwise
uint8_t asdf_arch_tick(void);
// PROCEDURE: asdf_arch_send_code
// INPUTS: (keycode_t) code - the code to be output by the keyboard
// OUTPUTS: none
// DESCRIPTION: Takes a character code and outputs the code on a parallel ASCII
// port, with a strobe. This routine could be replaced with UART, I2C, USB, or
// other output mechanism, of course.
void asdf_arch_send_code(asdf_keycode_t code);
// PROCEDURE: asdf_arch_init
// INPUTS: none
// OUTPUTS: none
// DESCRIPTION: sets up all the hardware for the keyboard
void asdf_arch_init(void);
#endif /* !defined (ASDF_ARCH_H) */
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.

View File

@ -0,0 +1,43 @@
// -*- mode: C; tab-width: 4 ; indent-tabs-mode: nil -*-
//
// Universal Keyboard Project
// ASDF keyboard firmware
//
// asdf_arch_test.h
//
// Architecture-dependent definitions for the unit-testing ASDF software.
//
// Copyright 2019 David Fenyes
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
#if !defined (ASDF_ARCH_H)
#define ASDF_ARCH_H
#define FLASH
#define FLASH_READ (a) (*(a))
#define FLASH_READ_MATRIX_ELEMENT(mat,row,col) (mat)[(row)][(col)]
void asdf_arch_init(void);
void asdf_arch_tick(void);
uint8_t asdf_arch_read_row(uint8_t row);
#endif // !defined (ASDF_ARCH_H)
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.

View File

@ -0,0 +1,128 @@
// -*- mode: C; tab-width: 4 ; indent-tabs-mode: nil -*-
//
// Universal Keyboard Project
// ASDF keyboard firmware
//
// asdf_keymaps.h
//
// Copyright 2019 David Fenyes
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
#if !defined(ASDF_KEYMAPS_H)
#define ASDF_KEYMAPS_H
#include "asdf.h"
#include "asdf_ascii.h"
#include "asdf_modifiers.h"
#define ASCII_PLAIN_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, ASCII_BACKSLASH }, \
{ ASCII_DEL, 'p', ';', '/', ASCII_SPACE, 'z', 'a', 'q' }, \
{ ACTION_BREAK, ASCII_COMMA, 'm', 'n', 'b', 'v', 'c', 'x' }, \
{ ACTION_NOTHING, 'k', 'j', 'h', 'g', 'f', 'd', 's' }, \
{ ACTION_CLEAR, 'i', 'u', 'y', 't', 'r', 'e', 'w' }, { ACTION_REPEAT, \
ACTION_HERE_IS, \
ACTION_SHIFT_LOCK, \
ASCII_CR, \
ASCII_LF, \
'o', \
'l', \
ASCII_PERIOD }, \
{ ASCII_TILDE, ASCII_RT_SQUARE_BRACE, ASCII_LT_SQUARE_BRACE, '-', ':', '0', '9', '8' }, \
{ \
ASCII_AT, '7', '6', '5', '4', '3', '2', '1' \
} \
}
#define ASCII_CAPS_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, ASCII_BACKSLASH }, \
{ ASCII_DEL, 'P', ';', '/', ASCII_SPACE, 'Z', 'A', 'Q' }, \
{ ACTION_BREAK, ASCII_COMMA, 'M', 'N', 'B', 'V', 'C', 'X' }, \
{ ACTION_NOTHING, 'K', 'J', 'H', 'G', 'F', 'D', 'S' }, \
{ ACTION_CLEAR, 'I', 'U', 'Y', 'T', 'R', 'E', 'W' }, { ACTION_REPEAT, \
ACTION_HERE_IS, \
ACTION_SHIFT_LOCK, \
ASCII_CR, \
ASCII_LF, \
'O', \
'L', \
ASCII_PERIOD }, \
{ ASCII_TILDE, ASCII_RT_SQUARE_BRACE, ASCII_LT_SQUARE_BRACE, '-', ':', '0', '9', '8' }, \
{ \
ASCII_AT, '7', '6', '5', '4', '3', '2', '1' \
} \
}
#define ASCII_SHIFT_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, ASCII_VERT_BAR }, \
{ ASCII_DEL, 'P', '+', '?', ASCII_SPACE, 'Z', 'A', 'Q' }, \
{ ACTION_BREAK, '>', 'M', 'N', 'B', 'V', 'C', 'X' }, \
{ ACTION_NOTHING, 'K', 'J', 'H', 'G', 'F', 'D', 'S' }, \
{ ACTION_CLEAR, 'I', 'U', 'Y', 'T', 'R', 'E', 'W' }, \
{ ACTION_REPEAT, ACTION_HERE_IS, ACTION_SHIFT_LOCK, ASCII_CR, ASCII_LF, 'O', 'L', '<' }, \
{ ASCII_TILDE, ASCII_RT_CURLY_BRACE, ASCII_LT_CURLY_BRACE, '=', '*', \
'0', ASCII_RT_PAREN, ASCII_LT_PAREN }, \
{ \
ASCII_GRAVE_ACCENT, ASCII_SINGLE_QUOTE, '&', '%', '$', '#', ASCII_DOUBLE_QUOTE, '!' \
} \
}
#define ASCII_CTRL_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, 0x1c }, \
{ ACTION_NOTHING, ASCII_CTRL_P, ACTION_NOTHING, ACTION_NOTHING, \
ASCII_SPACE, ASCII_CTRL_Z, ASCII_CTRL_A, ASCII_CTRL_Q }, \
{ ACTION_BREAK, ASCII_COMMA, ASCII_CTRL_M, ASCII_CTRL_N, \
ASCII_CTRL_B, ASCII_CTRL_V, ASCII_CTRL_C, ASCII_CTRL_X }, \
{ ACTION_CLEAR, ASCII_CTRL_I, ASCII_CTRL_U, ASCII_CTRL_Y, \
ASCII_CTRL_T, ASCII_CTRL_R, ASCII_CTRL_E, ASCII_CTRL_W }, \
{ ACTION_REPEAT, ACTION_HERE_IS, ACTION_SHIFT_LOCK, ASCII_CR, \
ASCII_LF, ASCII_CTRL_O, ASCII_CTRL_L, ACTION_NOTHING }, \
{ ACTION_NOTHING, 0x1d, ASCII_ESC, ACTION_NOTHING, \
ACTION_NOTHING, ACTION_FN_1, ACTION_FN_9, ACTION_FN_8 }, \
{ \
ACTION_NOTHING, ACTION_FN_7, ACTION_FN_6, ACTION_FN_5, ACTION_FN_4, ACTION_FN_3, \
ACTION_FN_2, ACTION_FN_2 \
} \
}
// PROCEDURE: asdf_keymaps_init
// INPUTS: none
// OUTPUTS: none
// DESCRIPTION: Assigns the keymaps to the indices specified by the modifier
// index, to avoid hard-coding constant index values.
void asdf_keymaps_init(void);
// PROCEDURE: asdf_keymaps_get_code
// INPUTS: row, col: row and column of key that has been pressed
// modifiers_index: index into the keymap array, based on modifier state
// OUTPUTS: returns a key code.
// DESCRIPTION: Given a key row and column, and an index based on modifier
// state, return the appropriate keycode.
asdf_keycode_t asdf_keymaps_get_code(uint8_t row, uint8_t col, uint8_t modifier_index);
#endif /* !defined (ASDF_KEYMAPS_H) */
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.

View File

@ -0,0 +1,131 @@
// -*- mode: C; tab-width: 4 ; indent-tabs-mode: nil -*-
//
// Universal Keyboard Project
// ASDF keyboard firmware
//
// asdf_keymaps.h
//
// Copyright 2019 David Fenyes
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
// While there is nothing preventing a standard keyboard from having both a
// "Shift Lock" key and a "Caps Lock" key, usually only one will be present. For
// testing, both must be present to test their functionality.
#if !defined(ASDF_KEYMAPS_H)
#define ASDF_KEYMAPS_H
#include "asdf.h"
#include "asdf_ascii.h"
#include "asdf_modifiers.h"
#define ASCII_PLAIN_MAP \
{ \
{ ACTION_CAPS, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, ASCII_BACKSLASH }, \
{ ACTION_NOTHING, 'p', ';', '/', ASCII_SPACE, 'z', 'a', 'q' }, \
{ ACTION_BREAK, ASCII_COMMA, 'm', 'n', 'b', 'v', 'c', 'x' }, \
{ ACTION_NOTHING, 'k', 'j', 'h', 'g', 'f', 'd', 's' }, \
{ ACTION_CLEAR, 'i', 'u', 'y', 't', 'r', 'e', 'w' }, { ACTION_REPEAT, \
ACTION_HERE_IS, \
ACTION_SHIFT_LOCK, \
ASCII_CR, \
ASCII_LF, \
'o', \
'l', \
ASCII_PERIOD }, \
{ ASCII_TILDE, ASCII_RT_SQUARE_BRACE, ASCII_LT_SQUARE_BRACE, '-', ':', '0', '9', '8' }, \
{ \
ACTION_NOTHING, '7', '6', '5', '4', '3', '2', '1' \
} \
}
#define ASCII_CAPS_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, ASCII_BACKSLASH }, \
{ ACTION_NOTHING, 'P', ';', '/', ASCII_SPACE, 'Z', 'A', 'Q' }, \
{ ACTION_BREAK, ASCII_COMMA, 'M', 'N', 'B', 'V', 'C', 'X' }, \
{ ACTION_NOTHING, 'K', 'J', 'H', 'G', 'F', 'D', 'S' }, \
{ ACTION_CLEAR, 'I', 'U', 'Y', 'T', 'R', 'E', 'W' }, { ACTION_REPEAT, \
ACTION_HERE_IS, \
ACTION_SHIFT_LOCK, \
ASCII_CR, \
ASCII_LF, \
'O', \
'L', \
ASCII_PERIOD }, \
{ ASCII_TILDE, ASCII_RT_SQUARE_BRACE, ASCII_LT_SQUARE_BRACE, '-', ':', '0', '9', '8' }, \
{ \
ACTION_NOTHING, '7', '6', '5', '4', '3', '2', '1' \
} \
}
#define ASCII_SHIFT_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, ASCII_VERT_BAR }, \
{ ACTION_NOTHING, 'P', '+', '?', ASCII_SPACE, 'Z', 'A', 'Q' }, \
{ ACTION_BREAK, '>', 'M', 'N', 'B', 'V', 'C', 'X' }, \
{ ACTION_NOTHING, 'K', 'J', 'H', 'G', 'F', 'D', 'S' }, \
{ ACTION_CLEAR, 'I', 'U', 'Y', 'T', 'R', 'E', 'W' }, \
{ ACTION_REPEAT, ACTION_HERE_IS, ACTION_SHIFT_LOCK, ASCII_CR, ASCII_LF, 'O', 'L', '<' }, \
{ ASCII_TILDE, ASCII_RT_CURLY_BRACE, ASCII_LT_CURLY_BRACE, '=', '*', \
'0', ASCII_RT_PAREN, ASCII_LT_PAREN }, \
{ \
ACTION_NOTHING, ASCII_SINGLE_QUOTE, '&', '%', '$', '#', ASCII_DOUBLE_QUOTE, '!' \
} \
}
#define ASCII_CTRL_MAP \
{ \
{ ACTION_NOTHING, ACTION_SHIFT, ACTION_SHIFT, ACTION_NOTHING, \
ACTION_NOTHING, ASCII_ESC, ACTION_CTRL, 0x1c }, \
{ ACTION_NOTHING, ASCII_CTRL_P, ACTION_NOTHING, ACTION_NOTHING, \
ASCII_SPACE, ASCII_CTRL_Z, ASCII_CTRL_A, ASCII_CTRL_Q }, \
{ ACTION_BREAK, ASCII_COMMA, ASCII_CTRL_M, ASCII_CTRL_N, \
ASCII_CTRL_B, ASCII_CTRL_V, ASCII_CTRL_C, ASCII_CTRL_X }, \
{ ACTION_CLEAR, ASCII_CTRL_I, ASCII_CTRL_U, ASCII_CTRL_Y, \
ASCII_CTRL_T, ASCII_CTRL_R, ASCII_CTRL_E, ASCII_CTRL_W }, \
{ ACTION_REPEAT, ACTION_HERE_IS, ACTION_SHIFT_LOCK, ASCII_CR, \
ASCII_LF, ASCII_CTRL_O, ASCII_CTRL_L, ACTION_NOTHING }, \
{ ACTION_NOTHING, 0x1d, ASCII_ESC, ACTION_NOTHING, \
ACTION_NOTHING, ACTION_FN_1, ACTION_FN_9, ACTION_FN_8 }, \
{ \
ACTION_NOTHING, ACTION_FN_7, ACTION_FN_6, ACTION_FN_5, ACTION_FN_4, ACTION_FN_3, \
ACTION_FN_2, ACTION_FN_2 \
} \
}
// PROCEDURE: asdf_keymaps_init
// INPUTS: none
// OUTPUTS: none
// DESCRIPTION: Assigns the keymaps to the indices specified by the modifier
// index, to avoid hard-coding constant index values.
void asdf_keymaps_init(void);
// PROCEDURE: asdf_keymaps_get_code
// INPUTS: row, col: row and column of key that has been pressed
// modifiers_index: index into the keymap array, based on modifier state
// OUTPUTS: returns a key code.
// DESCRIPTION: Given a key row and column, and an index based on modifier
// state, return the appropriate keycode.
asdf_keycode_t asdf_keymaps_get_code(uint8_t row, uint8_t col, uint8_t modifier_index);
#endif /* !defined (ASDF_KEYMAPS_H) */
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.

View File

@ -0,0 +1,21 @@
ARCH ?= atmega328p
KEYMAP ?= ascii
BUILD_DIR = ../build
all: app
app:
make -f Makefile.app
test:
make -f Makefile.test
clean:
make -f Makefile.app clean
make -f Makefile.test clean
cleanall:
make -f Makefile.app cleanall
make -f Makefile.test cleanall

View File

@ -0,0 +1,157 @@
ARCH ?= atmega328p
KEYMAP ?= ascii
ARCH_TOKEN = _Arch_$(ARCH)
TARGET = asdf
TEST_DIR = ../test
UNITY_DIR = $(TEST_DIR)/unity
BUILD_DIR = ../build
DEP_DIR := ./.deps
TARGET_BIN := $(BUILD_DIR)/$(TARGET).elf
TARGET_HEX := $(BUILD_DIR)/$(TARGET).hex
TARGET_MAP := $(BUILD_DIR)/$(TARGET).map
UNITY_SCRIPTS = $(UNITY_DIR)/auto
ARCH_DIR = Arch
KEYMAPS_DIR = Keymaps
VERSION =
RELEASE=
SIZE_COMMAND = avr-size
CLOCK = 8000000L
CLEAN_FILES =
CLEANALL_FILES =
CC = avr-gcc
CFLAGS = -std=c99
CFLAGS += -Wall
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -O2
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wpointer-arith
CFLAGS += -Wcast-align
CFLAGS += -Wwrite-strings
CFLAGS += -Wswitch-default
CFLAGS += -Wunreachable-code
CFLAGS += -Winit-self
CFLAGS += -Wmissing-field-initializers
CFLAGS += -Wno-unknown-pragmas
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
CFLAGS += -Wold-style-definition
CFLAGS += -mmcu=$(ARCH)
CFLAGS += -DF_CPU=$(CLOCK)
LDFLAGS = -Wl,-Map=$(TARGET_MAP)
LDFLAGS += -Wl,--start-group
LDFLAGS += -Wl,-lm
LDFLAGS += -Wl,--end-group
LDFLAGS += -Wl,--gc-sections
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
MAKEDEPEND = $(CPP) $(DEPFLAGS) $(CPPFLAGS) $< \
| sed -n 's,^\# *[0-9][0-9]* *"\([^"<]*\)".*,$@: \1\n\1:,p' \
| sort -u > $*.d
SRC_FILES = main.c asdf.c asdf_modifiers.c asdf_repeat.c asdf_keymaps.c asdf_buffer.c asdf_arch.c
OBJ_FILES := $(SRC_FILES:.c=.o)
DEP_FILES := $(SRC_FILES:%.c=$(DEP_DIR)/%.d)
MAP_FILE = $(TARGET).map
CLEAN_FILES += $(MAP_FILE)
CLEAN_FILES += $(TARGET_BIN)
CLEAN_FILES += $(TARGET_MAP)
CLEANALL_FILES += $(TARGET_HEX)
MAKEFILES = Makefile
GENERATED_FILES = conventions.h machine.h
ALL_FILES = $(MAKEFILES) $(SRC_FILES) $(TXTFILES) $(GENERATED_FILES)
.SUFFIXES:
.SUFFIXES: .c .o .bin .hex
all: $(TARGET_HEX)
%.d : %.c $(DEP_DIR)/%.d | $(DEP_DIR)
@$(MAKEDEPEND)
$(DEP_DIR): ; @mkdir -p $@
$(DEPFILES):
include $(wildcard $(DEPFILES))
%.o: %.c $(DEP_DIR)/%.d | $(DEP_DIR)
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEPFLAGS) $<
asdf_keymaps.h: $(KEYMAPS_DIR)/asdf_keymaps_$(KEYMAP).h $(KEYMAP_H_TOKEN)
cp $< $@
GENERATED_FILES += asdf_keymaps.h
asdf_arch.c: $(ARCH_DIR)/asdf_arch_$(ARCH).c $(ARCH_C_TOKEN)
cp $< $@
GENERATED_FILES += asdf_arch.c
asdf_arch.h: $(ARCH_DIR)/asdf_arch_$(ARCH).h $(ARCH_H_TOKEN)
cp $< $@
GENERATED_FILES += asdf_arch.h
$(ARCH_H_TOKEN):
touch $@
$(ARCH_C_TOKEN):
touch $@
$(KEYMAP_H_TOKEN):
touch $@
size:
$(SIZE_COMMAND) $(TARGET_BIN)
$(TARGET_HEX): $(TARGET_BIN)
avr-objcopy -j .text -j .data -j .fuses -O ihex $< $@
$(TARGET_BIN): $(OBJ_FILES)
$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $^
$(SIZE_COMMAND) $(TARGET_BIN)
asdf_keymaps.o: asdf_keymaps.c asdf.h asdf_ascii.h asdf_modifiers.h asdf_arch.h asdf_keymaps.h
main.o: main.c asdf.h asdf_arch.h
asdf.o: asdf.c asdf.h asdf_arch.h asdf_keymaps.h asdf_config.h
asdf_repeat.o: asdf_repeat.c asdf_repeat.h asdf_config.h
asdf_buffer.o: asdf_buffer.c asdf.h asdf_config.h
asdf_modifiers.o: asdf_modifiers.c asdf_modifiers.h
tags: $(SRC_FILES)
etags $(SRC_FILES)
CLEAN_FILES += $(TEST_BUILD_FILES) _Arch_* *.o
CLEAN_FILES += ~* *\#
CLEANALL_FILES += $(GENERATED_FILES) $(TARGET_BUILD_FILES) $(TEST_BUILD_FILES)
.PHONY: clean
clean:
rm -f $(CLEAN_FILES)
.PHONY: cleanall
cleanall:
rm -f $(CLEAN_FILES) $(CLEANALL_FILES)

View File

@ -0,0 +1,21 @@
# -*- makefile -*-
DEP_DIR := .deps
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
MAKEDEPEND = $(CPP) $(DEPFLAGS) $(CPPFLAGS) $< \
| sed -n 's,^\# *[0-9][0-9]* *"\([^"<]*\)".*,$@: \1\n\1:,p' \
| sort -u > $*.d
%.d : %.c $(DEP_DIR)/%.d | $(DEPDIR)
@$(MAKEDEPEND)
$(DEP_DIR): ; @mkdir -p $@
DEPFILES := $(SRC_FILES:%.c=$(DEP_DIR)/%.d)
$(DEPFILES):
include $(wildcard $(DEPFILES))

View File

@ -0,0 +1,155 @@
ARCH = test
ARCH = test
KEYMAP = test
ARCH_TOKEN = _Arch_$(ARCH)
TEST_DIR = ../test
UNITY_DIR = $(TEST_DIR)/unity
BUILD_DIR = ../build
UNITY_SCRIPTS = $(UNITY_DIR)/auto
ARCH_DIR = ./Arch
KEYMAPS_DIR = ./Keymaps
CC = gcc
VERSION =
RELEASE=
CLEAN_FILES =
CLEANALL_FILES =
CFLAGS=-std=c99
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wpointer-arith
CFLAGS += -Wcast-align
CFLAGS += -Wwrite-strings
CFLAGS += -Wswitch-default
CFLAGS += -Wunreachable-code
CFLAGS += -Winit-self
CFLAGS += -Wmissing-field-initializers
CFLAGS += -Wno-unknown-pragmas
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
CFLAGS += -Wold-style-definition
SRC_FILES = main.c asdf.c asdf_modifiers.c asdf_repeat.c asdf_keymaps.c asdf_buffer.c asdf_arch.c
OBJ_FILES = $(SRC_FILES:.c=.o)
ARCH_FILES = asdf_arch.c asdf_arch.h
CLEAN_FILES += ARCH_FILES
TESTS = repeat modifiers keymaps interface keyscan
TEST1 = asdf_repeat
TEST1_SRC = $(TEST_DIR)/test_$(TEST1).c
TEST1_DEPS = ./$(TEST1).c $(UNITY_DIR)/unity.c
TEST1_BUILD = $(BUILD_DIR)/test_$(TEST1)
TEST2 = asdf_modifiers
TEST2_SRC = $(TEST_DIR)/test_$(TEST2).c
TEST2_DEPS = ./$(TEST2).c $(UNITY_DIR)/unity.c
TEST2_BUILD = $(BUILD_DIR)/test_$(TEST2)
TEST3 = asdf_keymaps
TEST3_SRC = $(TEST_DIR)/test_$(TEST3).c
TEST3_DEPS = ./$(TEST3).c $(UNITY_DIR)/unity.c
TEST3_BUILD = $(BUILD_DIR)/test_$(TEST3)
TEST4 = asdf_buffer
TEST4_SRC = $(TEST_DIR)/test_$(TEST4).c
TEST4_DEPS = ./$(TEST4).c $(UNITY_DIR)/unity.c
TEST4_BUILD = $(BUILD_DIR)/test_$(TEST4)
TEST5 = asdf
TEST5_SRC = $(TEST_DIR)/test_$(TEST5).c
TEST5_DEPS = ./$(TEST5).c $(UNITY_DIR)/unity.c ./$(TEST1).c $(TEST2).c $(TEST3).c $(TEST4).c
TEST5_BUILD = $(BUILD_DIR)/test_$(TEST5)
.SUFFIXES:
.SUFFIXES: .c .o .bin .hex
%.o: %.c
$(TARGET_CC) -c $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $<
all: test
asdf_keymaps.h: Keymaps/asdf_keymaps_$(KEYMAP).h
cp $< $@
GENERATED_FILES += asdf_keymaps.h
asdf_arch.c: $(ARCH_DIR)/asdf_arch_$(ARCH).c _Arch_$(ARCH)
cp $< $@
GENERATED_FILES += asdf_arch.c
asdf_arch.h: $(ARCH_DIR)/asdf_arch_$(ARCH).h _Arch_$(ARCH)
cp $< $@
GENERATED_FILES += asdf_arch.h
$(ARCH_TOKEN):
touch $(ARCH_TOKEN)
asdf_keymaps.c: asdf.h asdf_ascii.h asdf_modifiers.h asdf_arch.h asdf_keymaps.h
tags: $(SRC_FILES)
etags $(SRC_FILES)
.PHONY: test
test: test1 test2 test3 test4 test5
.PHONY: test1
test1: $(TEST1_BUILD)
$(TEST1_BUILD)
.PHONY: test2
test2: $(TEST2_BUILD)
$(TEST2_BUILD)
.PHONY: test3
test3: $(TEST3_BUILD)
$(TEST3_BUILD)
.PHONY: test4
test4: $(TEST4_BUILD)
$(TEST4_BUILD)
.PHONY: test5
test5: $(TEST5_BUILD)
$(TEST5_BUILD)
$(TEST1_BUILD): $(TEST1_SRC) $(TEST1_DEPS)
$(CC) -o $@ -I. -I$(TEST_DIR) -I$(UNITY_DIR) $(CFLAGS) $(TEST1_SRC) $(TEST1_DEPS)
$(TEST2_BUILD): $(TEST2_SRC) $(TEST2_DEPS)
$(CC) -o $@ -I. -I$(TEST_DIR) -I$(UNITY_DIR) $(CFLAGS) $(TEST2_SRC) $(TEST2_DEPS)
$(TEST3_BUILD): $(TEST3_SRC) $(TEST3_DEPS)
$(CC) -o $@ -I. -I$(TEST_DIR) -I$(UNITY_DIR) $(CFLAGS) $(TEST3_SRC) $(TEST3_DEPS)
$(TEST4_BUILD): $(TEST4_SRC) $(TEST4_DEPS)
$(CC) -o $@ -I. -I$(TEST_DIR) -I$(UNITY_DIR) $(CFLAGS) $(TEST4_SRC) $(TEST4_DEPS)
$(TEST5_BUILD): $(TEST5_SRC) $(TEST5_DEPS)
$(CC) -o $@ -I. -I$(TEST_DIR) -I$(UNITY_DIR) $(CFLAGS) $(TEST5_SRC) $(TEST5_DEPS)
TEST_BUILD_FILES += $(TEST1_BUILD) $(TEST2_BUILD) $(TEST3_BUILD) $(TEST4_BUILD) $(TEST5_BUILD)
CLEAN_FILES += $(TEST_BUILD_FILES) _Arch_* *.o
CLEAN_FILES += ~* *\#
CLEANALL_FILES += $(GENERATED_FILES) $(TARGET_BUILD_FILES) $(TEST_BUILD_FILES)
.PHONY: clean
clean:
rm -f $(CLEAN_FILES)
.PHONY: cleanall
cleanall:
rm -f $(CLEAN_FILES) $(CLEANALL_FILES)
include Makefile.deps

View File

@ -0,0 +1,125 @@
// -*- mode: C; tab-width: 2 ; indent-tabs-mode: nil -*-
//
// Universal Keyboard Project
// ASDF keyboard firmware
//
// <FIXME-filename>.c
//
// Copyright 2019 David Fenyes
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
//
//iring Information:
// Chip: {Microcontroller type and version}
//
// Example:
// PIN NAME FUNCTION
// 3 AN1 ADC INPUT: Line sense analog input
//
// 6 A4 INPUT: (T0CK) COUNT DOWN from quadrature decoder.
// configured to count on rising edge, synced with xtal
//
//
// Headers
//
#include <version.h>