Add apple 2 caps, printing, bug fixes

- Added the apple 2 CAPS map

- auto-generate a function to check validity of a keymap index

- Added buffered message printing. This is different from keycode
buffering, since an extra delay is added for each message character to
allow polling hosts to keep up. Keycodes are generated at human speeds
and need no further slowdown.

- Added a message character delay to the arch-* modules

- enlarged the buffer pool, and created a buffer for messages

- bumped version number
This commit is contained in:
Dave 2021-11-29 16:26:08 -06:00
parent 233cda3e25
commit 562b859540
20 changed files with 239 additions and 51 deletions

View File

@ -25,7 +25,7 @@ elseif(ARCH MATCHES atmega2560)
endif()
project("asdf"
VERSION 1.6.1
VERSION 1.6.2
DESCRIPTION "A customizable keyboard matrix controller for retrocomputers"
LANGUAGES C)

View File

@ -2,7 +2,7 @@ list(APPEND keymap_list
"<classic:0>"
"<classic_caps:1>"
"<apple2:2>"
# "<apple2_caps:3>"
"<apple2_caps:3>"
"<sol:4>"
)

View File

@ -681,6 +681,26 @@ void asdf_arch_pulse_delay_long(void)
_delay_ms(ASDF_PULSE_DELAY_LONG_MS);
}
// PROCEDURE: asdf_arch_character_delay
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Delays a fixed amount of time after each character of a system
// message, to allow polled systems to catch up.
//
// SIDE EFFECTS: see above.
//
// NOTES: Set ASDF_PULSE_DELAY_US in asdf_config.h
//
// SCOPE: public
//
// COMPLEXITY: 1
//
void asdf_arch_character_delay(void)
{
_delay_ms(ASDF_MESSAGE_CHARACTER_DELAY);
}
// PROCEDURE: asdf_arch_init
// INPUTS: none
// OUTPUTS: none

View File

@ -475,6 +475,13 @@ void asdf_arch_pulse_delay_short(void);
// ASDF_PULSE_DELAY_LONG_MS
void asdf_arch_pulse_delay_long(void);
// PROCEDURE: asdf_arch_character_delay
// INPUTS: none
// OUTPUTS: none
// DESCRIPTION: Delays a fixed amount of time after each character of a system
// message, to allow polled systems to catch up.
// NOTES: Set ASDF_CHARACTER_DELAY_US in asdf_config.h
void asdf_arch_character_delay(void);
// PROCEDURE: asdf_arch_tick
// INPUTS: none

View File

@ -677,6 +677,26 @@ void asdf_arch_pulse_delay_long(void)
_delay_ms(ASDF_PULSE_DELAY_LONG_MS);
}
// PROCEDURE: asdf_arch_character_delay
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION: Delays a fixed amount of time after each character of a system
// message, to allow polled systems to catch up.
//
// SIDE EFFECTS: see above.
//
// NOTES: Set ASDF_PULSE_DELAY_US in asdf_config.h
//
// SCOPE: public
//
// COMPLEXITY: 1
//
void asdf_arch_character_delay(void)
{
_delay_ms(ASDF_MESSAGE_CHARACTER_DELAY);
}
// PROCEDURE: asdf_arch_init
// INPUTS: none
// OUTPUTS: none

View File

@ -376,6 +376,13 @@ void asdf_arch_pulse_delay_short(void);
// DESCRIPTION: Delays a fixed amount of time for keyboard output pulses specified by ASDF_PULSE_DELAY_LONG_MS
void asdf_arch_pulse_delay_long(void);
// PROCEDURE: asdf_arch_character_delay
// INPUTS: none
// OUTPUTS: none
// DESCRIPTION: Delays a fixed amount of time after each character of a system
// message, to allow polled systems to catch up.
// NOTES: Set ASDF_CHARACTER_DELAY_US in asdf_config.h
void asdf_arch_character_delay(void);
// PROCEDURE: asdf_arch_tick
// INPUTS: none

View File

@ -8,6 +8,14 @@ function(create_keymap_setups keymaps keymap_table)
set(${keymap_table} "${temp_list}" PARENT_SCOPE)
endfunction(create_keymap_setups)
function(create_keymap_valid keymaps keymap_valid)
list(TRANSFORM keymaps REPLACE "<\(.+\):\(.+\)>" "\n case \\2:" OUTPUT_VARIABLE temp_list)
# we can keep the ';' cmake list separators as the C statement separators.
# However, we need to append an extra ';' at the end.
string(APPEND temp_list ";")
set(${keymap_valid} "${temp_list}" PARENT_SCOPE)
endfunction(create_keymap_setups)
function(create_keymap_declarations keymaps keymap_decl)
list(TRANSFORM keymaps REPLACE "<\(.+\):\(.+\)>" "\n void setup_\\1_keymap(void)" OUTPUT_VARIABLE temp_list)
# we can keep the ';' cmake list separators as the C statement separators.
@ -25,6 +33,7 @@ endfunction(create_keymap_report)
include(../keymap_list.cmake)
create_keymap_setups("${keymap_list}" keymap_table)
create_keymap_valid("${keymap_list}" keymap_valid)
create_keymap_report("${keymap_list}" keymap_report)
create_keymap_declarations("${keymap_list}" keymap_declarations)
@ -87,6 +96,7 @@ list (APPEND SOURCES
Keymaps/asdf_keymap_classic_caps.c
Keymaps/asdf_keymap_classic_add_map.c
Keymaps/asdf_keymap_apple2.c
Keymaps/asdf_keymap_apple2_caps.c
Keymaps/asdf_keymap_apple2_add_map.c
Keymaps/asdf_keymap_sol.c
main.c

View File

@ -24,6 +24,7 @@
//
#include "asdf_print.h"
#include "asdf_keymaps.h"
#include "asdf_virtual.h"
#include "asdf_modifiers.h"
@ -45,6 +46,9 @@
//
void setup_apple2_keymap(void)
{
asdf_print("[Keymap: Apple 2 (u/l case)]");
apple_add_map(APPLE_PLAIN_MAP, MOD_PLAIN_MAP);
apple_add_map(APPLE_CAPS_MAP, MOD_CAPS_MAP);
apple_add_map(APPLE_SHIFT_MAP, MOD_SHIFT_MAP);

View File

@ -3,9 +3,9 @@
// Unified Keyboard Project
// ASDF keyboard firmware
//
// asdf_keymap_classic.c
// asdf_keymap_apple2_caps.c
//
// Implements the "classic" ADM 3A style keymaps
// set up keymaps for ALL CAPS Apple II keyboards
//
// Copyright 2019 David Fenyes
//
@ -23,47 +23,54 @@
// this program. If not, see <https://www.gnu.org/licenses/>.
//
#include "asdf_keymap_classic.h"
#include "asdf_keymap_classic_add_map.h"
// PROCEDURE:
// INPUTS:
// OUTPUTS:
#include "asdf_print.h"
#include "asdf_keymaps.h"
#include "asdf_virtual.h"
#include "asdf_modifiers.h"
#include "asdf_keymap_apple2_add_map.h"
// PROCEDURE: setup_apple2_caps_keymap
// INPUTS: none
// OUTPUTS: none
//
// DESCRIPTION:
// DESCRIPTION: Set up keymaps for ALL CAPS apple 2 keyboard
//
// SIDE EFFECTS:
// SIDE EFFECTS: See DESCRIPTION
//
// NOTES:
//
// SCOPE:
// SCOPE: public
//
// COMPLEXITY:
// COMPLEXITY: 1
//
void setup_classic_caps_keymap(void)
void setup_apple2_caps_keymap(void)
{
// for the ALL CAPS keymap, the "plain" mode is the same as "all caps" mode:
classic_add_map(classic_caps_map, MOD_PLAIN_MAP);
classic_add_map(classic_caps_map, MOD_CAPS_MAP);
classic_add_map(classic_shift_map, MOD_SHIFT_MAP);
classic_add_map(classic_ctrl_map, MOD_CTRL_MAP);
asdf_print("[Keymap: Apple 2 CAPS]");
apple_add_map(APPLE_CAPS_MAP, MOD_PLAIN_MAP);
apple_add_map(APPLE_CAPS_MAP, MOD_CAPS_MAP);
apple_add_map(APPLE_CAPS_SHIFT_MAP, MOD_SHIFT_MAP);
apple_add_map(APPLE_CTRL_MAP, MOD_CTRL_MAP);
asdf_virtual_init();
// Assign power LED to virtual power LED, and initialize to ON
asdf_virtual_assign(CLASSIC_VIRTUAL_POWER_LED, CLASSIC_POWER_LED, V_NOFUNC, CLASSIC_POWER_LED_INIT_VALUE);
// Because the virtual power LED never changes, also assign the CAPSLOCK
// physical LED to the virtual Power LED, and intialize to OFF (or can change
// to ON depending on preference)
asdf_virtual_assign(CLASSIC_VIRTUAL_POWER_LED, CLASSIC_CAPS_LED, V_NOFUNC, CLASSIC_CAPS_LED_INIT_VALUE);
// Attach the physical POWER LED as the CAPS LED. Assign no triggered
// function, and initialize to initial state of the CAPS logic. The CAPS LED
// will be controlled by the state of the CAPSLOCK logic.
asdf_virtual_assign(VCAPS_LED, APPLE_POWER_LED, V_NOFUNC, APPLE_POWER_LED_INIT_VALUE);
// Assign CAPS LED to off (disabled)
asdf_virtual_assign(APPLE_VIRTUAL_DISABLED_LED, APPLE_DISABLED_LED, V_NOFUNC, APPLE_DISABLED_INIT_VALUE);
// assign RESET output to the virtual RESET output, configure to produce a short pulse when activated
asdf_virtual_assign(CLASSIC_VIRTUAL_RESET, CLASSIC_RESET_OUTPUT, V_PULSE_SHORT, !CLASSIC_RESET_ACTIVE_VALUE);
asdf_virtual_assign(APPLE_VIRTUAL_RESET, APPLE_RESET_OUTPUT, V_PULSE_SHORT, !APPLE_RESET_ACTIVE_VALUE);
// assign the CLRSCR output to the virtual CLRSCR output, configure to produce a long pulse when activated
asdf_virtual_assign(CLASSIC_VIRTUAL_CLR_SCR, CLASSIC_CLR_SCR_OUT, V_PULSE_LONG, !CLASSIC_CLR_SCR_ACTIVE_VALUE);
asdf_virtual_assign(APPLE_VIRTUAL_CLR_SCR, APPLE_CLR_SCR_OUTPUT, V_PULSE_LONG, !APPLE_CLR_SCR_ACTIVE_VALUE);
}

View File

@ -26,6 +26,7 @@
#include "asdf_keymaps.h"
#include "asdf_virtual.h"
#include "asdf_modifiers.h"
#include "asdf_print.h"
#include "asdf_keymap_classic.h"
#include "asdf_keymap_classic_add_map.h"
@ -46,6 +47,8 @@
void setup_classic_keymap(void)
{
asdf_print("[Keymap: classic]\n");
classic_add_map(CLASSIC_PLAIN_MAP, MOD_PLAIN_MAP);
classic_add_map(CLASSIC_CAPS_MAP, MOD_CAPS_MAP);
classic_add_map(CLASSIC_SHIFT_MAP, MOD_SHIFT_MAP);
@ -66,7 +69,7 @@ void setup_classic_keymap(void)
// assign the CLRSCR output to the virtual CLRSCR output, configure to produce a long pulse when activated
asdf_virtual_assign(CLASSIC_VIRTUAL_CLR_SCR, CLASSIC_CLR_SCR_OUT, V_PULSE_LONG, !CLASSIC_CLR_SCR_ACTIVE_VALUE);
asdf_put_code('[');asdf_put_code('c');asdf_put_code(']');
}

View File

@ -24,6 +24,7 @@
//
#include "asdf_keymaps.h"
#include "asdf_print.h"
#include "asdf_virtual.h"
#include "asdf_modifiers.h"
#include "asdf_keymap_classic.h"
@ -46,6 +47,8 @@
void setup_classic_caps_keymap(void)
{
asdf_print("[Keymap: classic CAPS]");
// for the ALL CAPS keymap, the "plain" mode is the same as "all caps" mode:
classic_add_map(CLASSIC_CAPS_MAP, MOD_PLAIN_MAP);
classic_add_map(CLASSIC_CAPS_MAP, MOD_CAPS_MAP);

View File

@ -30,6 +30,7 @@
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
#include <stdio.h>
#include <stdint.h>
#include "asdf.h"
#include "asdf_ascii.h"
@ -63,6 +64,9 @@ static asdf_keycode_t last_key;
// This is the handle for the char output buffer
static asdf_buffer_handle_t asdf_keycode_buffer;
// This is the handle for the message output buffer
static asdf_buffer_handle_t asdf_message_buffer;
// PROCEDURE: asdf_put_code
// INPUTS: (asdf_keycode_t) code: code to be buffered for output
@ -83,23 +87,62 @@ void asdf_put_code(asdf_keycode_t code)
asdf_buffer_put(asdf_keycode_buffer, code);
}
// PROCEDURE: asdf_next_code
// INPUTS: none
// OUTPUTS: (asdf_keycode_t) returns next value in buffer.
// PROCEDURE: asdf_putc
// INPUTS: (char) c: character to be buffered for output
// (FILE *) stream - only used to match prototype.
// OUTPUTS: none
//
// DESCRIPTION: Takes a keycode argument and buffers for output.
// DESCRIPTION: Takes a character generated by the system and buffers for
// output.
//
// SIDE EFFECTS: modifies buffer state.
//
// NOTES: If the buffer is empty, the code ASDF_INVALID_CODE is returned.
// NOTES: If buffer is full, silently drop the code.
//
// SCOPE: public
//
// COMPLEXITY: 1
//
int asdf_putc(char c, FILE *stream)
{
// for messages, add CR to LF:
if ('\n' == c) {
asdf_putc('\r', stream);
}
asdf_buffer_put(asdf_message_buffer, (asdf_keycode_t) c);
return (int) c;
}
// PROCEDURE: asdf_next_code
// INPUTS: none
//
// OUTPUTS: (asdf_keycode_t) returns next value in buffer. If both buffers are
// empty, the code ASDF_INVALID_CODE is returned.
//
// DESCRIPTION: Checks the message buffer, and returns a character
// if present. Otherwise, return the next code in the keycode
// buffer.
//
// SIDE EFFECTS: modifies buffer state.
//
// NOTES: A delay is enforced for system messages, to reduce the risk of dropped
// characters with unbuffered polling hosts. No delay is needed for typed
// keycodes, as these are generated at human speeds.
//
// SCOPE: public
//
// COMPLEXITY: 2
//
asdf_keycode_t asdf_next_code(void)
{
return asdf_buffer_get(asdf_keycode_buffer);
asdf_keycode_t code = asdf_buffer_get(asdf_message_buffer);
if (ASDF_INVALID_CODE == code) {
code = asdf_buffer_get(asdf_keycode_buffer);
} else {
// for system message
asdf_arch_character_delay();
}
return code;
}
// PROCEDURE: asdf_lookup_keycode
@ -397,6 +440,8 @@ void asdf_init(void)
// key states.
// reserve a buffer for the ASCII output:
asdf_keycode_buffer = asdf_buffer_new(ASDF_KEYCODE_BUFFER_SIZE);
asdf_message_buffer = asdf_buffer_new(ASDF_MESSAGE_BUFFER_SIZE);
// Initialize all the keys to the unpressed state, and initialze the debounce
// counters.
for (uint8_t row = 0; row < ASDF_MAX_ROWS; row++) {

View File

@ -24,6 +24,7 @@
#if !defined(ASDF_H)
#define ASDF_H
#include <stdio.h>
#include <stdint.h>
// Define the code at which keyboard actions begin. Codes below this value are
@ -125,10 +126,25 @@ void asdf_keyscan(void);
// NOTES: If buffer is full, silently drop the code.
void asdf_put_code(asdf_keycode_t code);
// PROCEDURE: asdf_putc
// INPUTS: (char) c: character to be buffered for output
// (FILE*) stream: only for prototype matching
// OUTPUTS: none
// DESCRIPTION: Takes a character generated by the system and buffers for
// output.
// NOTES: If buffer is full, silently drop the code.
int asdf_putc(char c, FILE *stream);
// PROCEDURE: asdf_next_code
// INPUTS: none
// OUTPUTS: (asdf_keycode_t) returns next value in buffer.
// DESCRIPTION: Takes a keycode argument and buffers for output.
// OUTPUTS: (asdf_keycode_t) returns next value in buffer. If both buffers are
// empty, the code ASDF_INVALID_CODE is returned.
// DESCRIPTION: Checks the message buffer, and returns a character
// if present. Otherwise, return the next code in the keycode
// buffer.
// NOTES: A delay is enforced for system messages, to reduce the risk of dropped
// characters with unbuffered polling hosts. No delay is needed for typed
// keycodes, as these are generated at human speeds.
asdf_keycode_t asdf_next_code(void);
#endif // !defined (ASDF_H)

View File

@ -193,7 +193,7 @@ void asdf_buffer_put(asdf_buffer_handle_t handle, asdf_keycode_t code)
asdf_keycode_t asdf_buffer_get(asdf_buffer_handle_t handle)
{
asdf_keycode_t code = ASDF_INVALID_CODE;
if (buffers[handle].count) {
if (handle < next_handle && buffers[handle].count) {
code = buffers[handle].buf[buffers[handle].tail];
buffers[handle].tail = (buffers[handle].tail + 1) % buffers[handle].size;
buffers[handle].count--;

View File

@ -26,18 +26,16 @@
#if !defined(ASDF_BUFFER_H)
#define ASDF_BUFFER_H
// ASDF_BUFFER_POOL_SIZE is defined in asdf_config.h
#include "asdf_config.h"
// The total space available for all buffers used in the application
#define ASDF_BUFFER_POOL_SIZE ASDF_KEYCODE_BUFFER_SIZE
// Used to designate an invalid buffer.
#define ASDF_BUFFER_INVALID -1
// Setting the number of handles to 1 will work if only one buffer is requrired,
// and will save a few bytes of RAM. But the test code needs at least 2 buffer
// handles to test the module, so we leave it at 2.
#define ASDF_BUFFER_NUM_HANDLES 2
#define ASDF_BUFFER_NUM_HANDLES 4
// The buffer handle type should be able to handle the expected number of buffers.

View File

@ -50,7 +50,11 @@
// Data structure sizes:
// size of the keycode output buffer.
#define ASDF_KEYCODE_BUFFER_SIZE 64
#define ASDF_KEYCODE_BUFFER_SIZE 16
#define ASDF_MESSAGE_BUFFER_SIZE 128
#define ASDF_BUFFER_POOL_SIZE (ASDF_MESSAGE_BUFFER_SIZE + ASDF_KEYCODE_BUFFER_SIZE)
// key debounce period (in msec)
#define ASDF_DEBOUNCE_TIME_MS 10
@ -59,6 +63,11 @@
// Set to REPEAT_OFF for default no autorepeat by default.
#define ASDF_DEFAULT_REPEAT_STATE REPEAT_AUTO
// time to wait before sending consecutive message characters to the host, to
// ensure that messages are intact on hosts that poll the port without
// buffering. (in msec)
#define ASDF_MESSAGE_CHARACTER_DELAY 16 //msec
// time to hold down a key in milliseconds before autorepeat starts
#define ASDF_AUTOREPEAT_TIME_MS 525 // 525 msec.

View File

@ -49,14 +49,45 @@
//
// COMPLEXITY: 1
//
void asdf_keymap_setup(uint8_t index) {
switch(index) {
@keymap_table@
default:
break;
}
};
}
// PROCEDURE: asdf_keymap_valid
//
// INPUTS: (uint8_t) index - index of the keymap setup function to check
// OUTPUTS: (uintu_t) returns TRUE (nonzero) if valid, FALSE (0) otherwise
////
// DESCRIPTION: This function returns TRUE if the index corresponds to
// a valid keymap.
//
// SIDE EFFECTS: none
//
// NOTES:
//
// SCOPE: public
//
// COMPLEXITY: 1
//
uint8_t asdf_keymap_valid(uint8_t index) {
uint8_t valid = 0;
switch(index) {
@keymap_valid@
valid= 1;
break;
default:
break;
}
return valid;
}
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.

View File

@ -37,6 +37,13 @@
// SIDE EFFECTS: See Description
void asdf_keymap_setup(uint8_t index);
// PROCEDURE: asdf_keymap_valid
// INPUTS: (uint8_t) index - index of the keymap setup function to check
// OUTPUTS: (uintu_t) returns TRUE (nonzero) if valid, FALSE (0) otherwise
// DESCRIPTION: This function returns TRUE if the index corresponds to
// a valid keymap.
uint8_t asdf_keymap_valid(uint8_t index);
//-------|---------|---------+---------+---------+---------+---------+---------+
// Above line is 80 columns, and should display completely in the editor.

View File

@ -161,16 +161,17 @@ static void asdf_keymaps_reset(void)
//
void asdf_keymaps_select(uint8_t index)
{
if (index < ASDF_NUM_KEYMAPS) {
// we set the current keymap index in order to track the state of the DIP
// switches, but only switch to a valid map
current_keymap_index = index;
if (asdf_keymap_valid(index)) {
asdf_arch_init();
asdf_keymaps_reset();
current_keymap_index = index;
asdf_print("\r\nIndex is %d.", index);
asdf_keymap_setup(index);
asdf_print("\r\nAfter setup function\n");
}
}

View File

@ -27,10 +27,10 @@
//
#include <stdio.h>
#include <avr/io.h>
#include "asdf_arch.h"
#include "asdf.h"
static FILE ascii_port = FDEV_SETUP_STREAM(asdf_arch_send_code, NULL,
static FILE ascii_port = FDEV_SETUP_STREAM(asdf_putc, NULL,
_FDEV_SETUP_WRITE);
//