mirror of
https://github.com/osiweb/unified_retro_keyboard.git
synced 2024-12-13 07:29:07 +00:00
first commit
This commit is contained in:
commit
784805adc7
26
README.md
Normal file
26
README.md
Normal 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
126
firmware/asdf/README.md
Normal 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.
|
||||
|
1
firmware/asdf/build/README.md
Normal file
1
firmware/asdf/build/README.md
Normal file
@ -0,0 +1 @@
|
||||
This directory contains the files resulting from the build process
|
448
firmware/asdf/src/Arch/asdf_arch_atmega328p.c
Normal file
448
firmware/asdf/src/Arch/asdf_arch_atmega328p.c
Normal 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.
|
||||
//
|
267
firmware/asdf/src/Arch/asdf_arch_atmega328p.h
Normal file
267
firmware/asdf/src/Arch/asdf_arch_atmega328p.h
Normal 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.
|
43
firmware/asdf/src/Arch/asdf_arch_test.h
Normal file
43
firmware/asdf/src/Arch/asdf_arch_test.h
Normal 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.
|
||||
|
||||
|
||||
|
128
firmware/asdf/src/Keymaps/asdf_keymaps_ascii.h
Normal file
128
firmware/asdf/src/Keymaps/asdf_keymaps_ascii.h
Normal 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.
|
131
firmware/asdf/src/Keymaps/asdf_keymaps_test.h
Normal file
131
firmware/asdf/src/Keymaps/asdf_keymaps_test.h
Normal 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.
|
21
firmware/asdf/src/Makefile
Normal file
21
firmware/asdf/src/Makefile
Normal 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
|
||||
|
157
firmware/asdf/src/Makefile.app
Normal file
157
firmware/asdf/src/Makefile.app
Normal 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)
|
||||
|
||||
|
21
firmware/asdf/src/Makefile.deps
Normal file
21
firmware/asdf/src/Makefile.deps
Normal 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))
|
155
firmware/asdf/src/Makefile.test
Normal file
155
firmware/asdf/src/Makefile.test
Normal 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
|
125
firmware/asdf/src/Templates/template.c
Normal file
125
firmware/asdf/src/Templates/template.c
Normal 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>
|
||||