mirror of
https://github.com/osiweb/unified_retro_keyboard.git
synced 2024-10-03 23:54:44 +00:00
d6edb15734
(WARNING: WIP) Gathered Work-in-progress on alternate keymap defs Exploratory branch. Code is messy and untested. Examining creating a module for each keymap rather than header file.
318 lines
9.7 KiB
C
318 lines
9.7 KiB
C
// -*- mode: C; tab-width: 2 ; indent-tabs-mode: nil -*-
|
|
//
|
|
// Unified Keyboard Project
|
|
// ASDF keyboard firmware
|
|
//
|
|
// asdf_physical.c
|
|
//
|
|
// This file contains code to manage physical resources and serves as an API
|
|
// between the virtual layer and the architecture specific code.
|
|
//
|
|
// 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/>.
|
|
//
|
|
|
|
#include <stdint.h>
|
|
#include "asdf_physical.h"
|
|
#include "asdf_config.h"
|
|
#include "asdf_arch.h"
|
|
|
|
|
|
// For each physical resource, there is a handler and a "shadow" register for the output value.
|
|
//
|
|
// For line outputs, the shadow register permits machine independent
|
|
// implementations of the toggle and pulse functions to be implemented in this
|
|
// module, requiring only a "set" function for each physical resource in the
|
|
// architecture-dependent layer. This implementation is not as efficient, but
|
|
// the timing is not critical, and the events are so infrequent that the
|
|
// benefits of the refactoring far outweigh any performance penalty.
|
|
|
|
typedef struct {
|
|
void (*handler)(uint8_t);
|
|
uint8_t shadow;
|
|
asdf_physical_dev_t next;
|
|
} physical_device_table_entry_t;
|
|
|
|
|
|
// physical_handler[] contains the set() function for each real output device.
|
|
static physical_device_table_entry_t physical_device_table[ASDF_PHYSICAL_NUM_RESOURCES] = {
|
|
[PHYSICAL_NO_OUT] = {.handler = &asdf_arch_null_output,},
|
|
[PHYSICAL_OUT1] = {.handler = &asdf_arch_out1_set,},
|
|
[PHYSICAL_OUT2] = {.handler = &asdf_arch_out2_set,},
|
|
[PHYSICAL_OUT3] = {.handler = &asdf_arch_out3_set,},
|
|
[PHYSICAL_OUT1_OPEN_HI] = {.handler = &asdf_arch_out1_open_hi_set,},
|
|
[PHYSICAL_OUT2_OPEN_HI] = {.handler = &asdf_arch_out2_open_hi_set,},
|
|
[PHYSICAL_OUT3_OPEN_HI] = {.handler = &asdf_arch_out3_open_hi_set,},
|
|
[PHYSICAL_OUT1_OPEN_LO] = {.handler = &asdf_arch_out1_open_lo_set,},
|
|
[PHYSICAL_OUT2_OPEN_LO] = {.handler = &asdf_arch_out2_open_lo_set,},
|
|
[PHYSICAL_OUT3_OPEN_LO] = {.handler = &asdf_arch_out3_open_lo_set,},
|
|
[PHYSICAL_LED1] = {.handler = &asdf_arch_led1_set,},
|
|
[PHYSICAL_LED2] = {.handler = &asdf_arch_led2_set,},
|
|
[PHYSICAL_LED3] = {.handler = &asdf_arch_led3_set,},
|
|
};
|
|
|
|
|
|
// PROCEDURE: asdf_physical_set
|
|
// INPUTS: (asdf_physical_dev_t) physical_out: which real output to set or clear
|
|
// INPUTS: (uint8_t) value
|
|
// OUTPUTS: none
|
|
//
|
|
// DESCRIPTION: If the physical resource is valid, set to high if value is true, low
|
|
// if false.
|
|
//
|
|
// SIDE EFFECTS: see above
|
|
//
|
|
// NOTES: No bounds checking. The caller must ensure a valid device
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
void asdf_physical_set(asdf_physical_dev_t physical_out, uint8_t value)
|
|
{
|
|
physical_device_table[physical_out].handler(value);
|
|
physical_device_table[physical_out].shadow = value;
|
|
}
|
|
|
|
// PROCEDURE: asdf_physical_on
|
|
// INPUTS: (asdf_physical_dev_t) physical_out: which real output to set to ON
|
|
// OUTPUTS: none
|
|
//
|
|
// DESCRIPTION: If the physical resource is valid, set to high
|
|
//
|
|
// SIDE EFFECTS: see above
|
|
//
|
|
// NOTES: No bounds checking. The caller must ensure a valid device
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
void asdf_physical_on(asdf_physical_dev_t physical_out)
|
|
{
|
|
physical_device_table[physical_out].handler(1);
|
|
physical_device_table[physical_out].shadow = 1;
|
|
}
|
|
|
|
// PROCEDURE: asdf_physical_off
|
|
// INPUTS: (asdf_physical_dev_t) physical_out: which real output to set to OFF
|
|
// OUTPUTS: none
|
|
//
|
|
// DESCRIPTION: If the physical resource is valid, set to low
|
|
//
|
|
// SIDE EFFECTS: see above
|
|
//
|
|
// NOTES: No bounds checking. The caller must ensure a valid device
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
void asdf_physical_off(asdf_physical_dev_t physical_out)
|
|
{
|
|
physical_device_table[physical_out].handler(0);
|
|
physical_device_table[physical_out].shadow = 0;
|
|
}
|
|
|
|
|
|
// PROCEDURE: asdf_physical_assert
|
|
// INPUTS: (asdf_physical_dev_t) physical_out: which physical resource to set or clear
|
|
// INPUTS: none
|
|
// OUTPUTS: none
|
|
//
|
|
// DESCRIPTION: Assert the value of the physical resource shadow register on the output.
|
|
//
|
|
// SIDE EFFECTS: see above
|
|
//
|
|
// NOTES: No bounds checking. Only called from initialization code.
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
void asdf_physical_assert(asdf_physical_dev_t physical_out)
|
|
{
|
|
uint8_t value = physical_device_table[physical_out].shadow;
|
|
physical_device_table[physical_out].handler(value);
|
|
}
|
|
|
|
// PROCEDURE: asdf_physical_toggle
|
|
// INPUTS: (asdf_physical_dev_t) physical_out: which physical resource to toggle
|
|
// INPUTS: none
|
|
// OUTPUTS: none
|
|
//
|
|
// DESCRIPTION: Toggle the value of the physical resource.
|
|
//
|
|
// SIDE EFFECTS: see above
|
|
//
|
|
// NOTES: No bounds checking. Only called from initialization code.
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
void asdf_physical_toggle(asdf_physical_dev_t physical_out)
|
|
{
|
|
uint8_t value = physical_device_table[physical_out].shadow;
|
|
|
|
asdf_physical_set(physical_out, !value);
|
|
}
|
|
|
|
// PROCEDURE: valid_physical_device
|
|
// INPUTS: (asdf_physical_dev_t) device
|
|
// OUTPUTS: returns true (1) if the device is valid, false (0) if not valid.
|
|
//
|
|
// DESCRIPTION: test to see if device is a valid device value.
|
|
//
|
|
// SIDE EFFECTS:
|
|
//
|
|
// NOTES:
|
|
//
|
|
// SCOPE: private
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
static uint8_t valid_physical_device(asdf_physical_dev_t device)
|
|
{
|
|
return (device > PHYSICAL_NO_OUT && device < ASDF_PHYSICAL_NUM_RESOURCES);
|
|
}
|
|
|
|
// PROCEDURE: physical_device_is_available
|
|
// INPUTS: asdf_physical_dev_t requiested_device
|
|
// OUTPUTS: returns PHYSICAL_NO_OUT if device is alreay allocated. If not yet allocated,
|
|
// returns the index of the device in the available list before the requested
|
|
// device.
|
|
//
|
|
// DESCRIPTION: iterates through the linked list of available devices. If the
|
|
// requested_device is encountered, return the element before the requested
|
|
// device in the list. If the end of the list is reached, return PHYSICAL_NO_OUT.
|
|
//
|
|
// SIDE EFFECTS: none
|
|
//
|
|
// NOTES:
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 3
|
|
//
|
|
uint8_t physical_device_is_available(asdf_physical_dev_t device)
|
|
{
|
|
asdf_physical_dev_t current_out = PHYSICAL_NO_OUT;
|
|
asdf_physical_dev_t next_out = physical_device_table[current_out].next;
|
|
|
|
while (next_out != PHYSICAL_NO_OUT && next_out != device) {
|
|
current_out = next_out;
|
|
next_out = physical_device_table[current_out].next;
|
|
}
|
|
return (PHYSICAL_NO_OUT == next_out) ? ASDF_PHYSICAL_NUM_RESOURCES : current_out;
|
|
}
|
|
|
|
// PROCEDURE: asdf_physical_next_device
|
|
// INPUTS: (asdf_physical_dev_t) device - the current physical resource attached
|
|
// to the virtual output being operated on
|
|
//
|
|
// OUTPUTS: (asdf_physical_dev_t) returns the next physical resource assigned to
|
|
// the virtual output.
|
|
//
|
|
// DESCRIPTION: See above.
|
|
//
|
|
// SIDE EFFECTS: None.
|
|
//
|
|
// NOTES:
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 1
|
|
//
|
|
asdf_physical_dev_t asdf_physical_next_device(asdf_physical_dev_t device)
|
|
{
|
|
return physical_device_table[device].next;
|
|
}
|
|
|
|
// PROCEDURE: asdf_physical_allocate
|
|
//
|
|
// INPUTS: (asdf_physical_out_t) physical_out - the desired physical resource to allocate.
|
|
// (asdf_physical_out_t) tail - the list of physical resources to tack on
|
|
// to the requested resource, if available.
|
|
//
|
|
// OUTPUTS: (asdf_physical_out_t) returns TRUE if the allocation is succesful,
|
|
// FALSE (0) otherwise.
|
|
//
|
|
// DESCRIPTION: Check that the requested physical resource is valid and
|
|
// available. If so, then remove the resource from the physical resource table
|
|
// and assign an initial value, then return a TRUE (1). Return FALSE (0) if
|
|
// allocation was not successful.
|
|
//
|
|
// SIDE EFFECTS: see above.
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 2
|
|
//
|
|
uint8_t asdf_physical_allocate(asdf_physical_dev_t physical_out, asdf_physical_dev_t tail,
|
|
uint8_t initial_value)
|
|
{
|
|
uint8_t success = 0;
|
|
asdf_physical_dev_t predecessor = physical_device_is_available(physical_out);
|
|
|
|
if (valid_physical_device(physical_out) && (ASDF_PHYSICAL_NUM_RESOURCES != predecessor)) {
|
|
|
|
// remove from available list:
|
|
physical_device_table[predecessor].next = physical_device_table[physical_out].next;
|
|
|
|
// tack the tail on to the physical resource
|
|
|
|
physical_device_table[physical_out].next = tail;
|
|
|
|
// The physical resource shadow value is set here. The shadow values are
|
|
// asserted to the outputs only after all the assignments have been
|
|
// performed.
|
|
physical_device_table[physical_out].shadow = initial_value;
|
|
|
|
success = 1;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
// PROCEDURE: asdf_physical_init
|
|
// INPUTS: none
|
|
// OUTPUTS: none
|
|
//
|
|
// DESCRIPTION: Initialize physical resource table
|
|
//
|
|
// SIDE EFFECTS: see above
|
|
//
|
|
// NOTES:
|
|
//
|
|
// SCOPE: public
|
|
//
|
|
// COMPLEXITY: 2
|
|
//
|
|
void asdf_physical_init(void)
|
|
{
|
|
// initialize the linked list of free devices
|
|
for (uint8_t i = 0; i < ASDF_PHYSICAL_NUM_RESOURCES; i++) {
|
|
physical_device_table[i].shadow = ASDF_VIRTUAL_OUT_DEFAULT_VALUE;
|
|
physical_device_table[i].next = i + 1; // initialize pointer to next in table
|
|
}
|
|
// The last item in the table is left with a bogus next pointer (beyond the
|
|
// end of the array) after the above loop. Make the last element point to
|
|
// PHYSICAL_NO_OUT.
|
|
physical_device_table[ASDF_PHYSICAL_NUM_RESOURCES - 1].next = PHYSICAL_NO_OUT; // end of list.
|
|
}
|
|
|
|
//-------|---------|---------+---------+---------+---------+---------+---------+
|
|
// Above line is 80 columns, and should display completely in the editor.
|