add safeguards for virtual device assignment

Disallow assignment of invalid virtual or real devices
Disallow assignment of a real devices that have already been assigned.
add unit test cases for virtual devices
This commit is contained in:
David Fenyes 2020-03-11 01:52:47 -05:00
parent 73e2760d94
commit 72a84f0363
2 changed files with 203 additions and 24 deletions

View File

@ -28,6 +28,7 @@
//
#include <stdint.h>
#include <stdio.h>
#include "asdf_virtual.h"
#include "asdf_keymap_defs.h"
#include "asdf_config.h"
@ -65,9 +66,9 @@ static void (*const vout_set[])(uint8_t) = {
[VMAP_OUT1_OC] = &asdf_arch_out1_hi_z_set, //
[VMAP_OUT2_OC] = &asdf_arch_out2_hi_z_set, //
[VMAP_OUT3_OC] = &asdf_arch_out3_hi_z_set, //
[VMAP_LED1] = &asdf_arch_led1_set, //
[VMAP_LED2] = &asdf_arch_led2_set, //
[VMAP_LED3] = &asdf_arch_led3_set //
[VMAP_LED1] = &asdf_arch_led1_set, //
[VMAP_LED2] = &asdf_arch_led2_set, //
[VMAP_LED3] = &asdf_arch_led3_set //
};
// virtual_out[] contains all the virtual outputs. An asdf_virtual_output_t
@ -213,6 +214,74 @@ void asdf_virtual_activate(asdf_virtual_output_t virtual_out)
asdf_virtual_action(virtual_out, virtual_device_table[virtual_out].function);
}
// PROCEDURE: valid_virtual_device
// INPUTS: (asdf_virtual_output_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_virtual_device(asdf_virtual_output_t device)
{
return (device > V_NULL && device < NUM_VIRTUAL_OUTPUTS);
}
// PROCEDURE: valid_real_device
// INPUTS: (asdf_virtual_real_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_real_device(asdf_virtual_real_dev_t device)
{
return (device > VMAP_NO_OUT && device < NUM_REAL_OUTPUTS);
}
// PROCEDURE: real_device_is_available
// INPUTS: asdf_virtual_real_dev_t requiested_device
// OUTPUTS: returns VMAP_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 VMAP_NO_OUT.
//
// SIDE EFFECTS: none
//
// NOTES:
//
// SCOPE: private
//
// COMPLEXITY: 3
//
static uint8_t real_device_is_available(asdf_virtual_real_dev_t device)
{
asdf_virtual_real_dev_t current_out = VMAP_NO_OUT;
asdf_virtual_real_dev_t next_out = real_device_table[current_out].next;
while (next_out != VMAP_NO_OUT && next_out != device) {
current_out = next_out;
next_out = real_device_table[current_out].next;
}
return (VMAP_NO_OUT == next_out) ? NUM_REAL_OUTPUTS : current_out;
}
// PROCEDURE: asdf_virtual_assign
// INPUTS: (asdf_vout_t) virtual_out
// (uint8_t) real_out
@ -223,7 +292,8 @@ void asdf_virtual_activate(asdf_virtual_output_t virtual_out)
//
// SIDE EFFECTS: see above.
//
// NOTES:
// NOTES: if the virtual device is invalid, or the real device is invalid, or
// the real device is already assigned, then nothing happens.
//
// SCOPE: private
//
@ -232,16 +302,25 @@ void asdf_virtual_activate(asdf_virtual_output_t virtual_out)
static void asdf_virtual_assign(asdf_virtual_output_t virtual_out, asdf_virtual_real_dev_t real_out,
asdf_virtual_function_t function, uint8_t initial_value)
{
virtual_device_table[virtual_out].function = function;
asdf_virtual_real_dev_t predecessor = real_device_is_available(real_out);
// add real device to the list associated with the virtual device:
if (valid_virtual_device(virtual_out)
&& valid_real_device(real_out)
&& (NUM_REAL_OUTPUTS != predecessor)) {
virtual_device_table[virtual_out].function = function;
real_device_table[real_out].next = virtual_device_table[virtual_out].real_device;
virtual_device_table[virtual_out].real_device = real_out;
// remove from available list:
real_device_table[predecessor].next = real_device_table[real_out].next;
// The real device shadow value is set here. The shadow values are asserted to
// the outputs only after all the assignments have been performed.
real_device_table[real_out].shadow = initial_value;
// add real device to the list associated with the virtual device:
real_device_table[real_out].next = virtual_device_table[virtual_out].real_device;
virtual_device_table[virtual_out].real_device = real_out;
// The real device shadow value is set here. The shadow values are asserted to
// the outputs only after all the assignments have been performed.
real_device_table[real_out].shadow = initial_value;
}
}
// PROCEDURE: asdf_virtual_init

View File

@ -46,7 +46,7 @@ void test_single_virtual_output_is_initialized(void)
void test_uninitialized_virtual_out_is_default(void)
{
TEST_ASSERT_EQUAL_INT32(ASDF_VIRTUAL_OUT_DEFAULT_VALUE, asdf_arch_check_output(VMAP_LED1));
TEST_ASSERT_EQUAL_INT32(ASDF_VIRTUAL_OUT_DEFAULT_VALUE, asdf_arch_check_output(VMAP_LED2));
}
void test_set_virtual_output(void)
@ -107,7 +107,8 @@ void test_pulse_low_virtual_output(void)
// output.
void test_toggle_triple_output(void)
{
asdf_keymaps_select_keymap(1);
asdf_keymaps_select_keymap(TRIPLE_TESTS_KEYMAP);
// check that initial values have been set:
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_OUT1));
TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_OUT2));
@ -128,7 +129,8 @@ void test_toggle_triple_output(void)
// output high and low
void test_set_triple_output(void)
{
asdf_keymaps_select_keymap(1);
asdf_keymaps_select_keymap(TRIPLE_TESTS_KEYMAP);
// check that initial values have been set:
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_OUT1));
TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_OUT2));
@ -149,7 +151,7 @@ void test_set_triple_output(void)
// output high and low
void test_pulse_triple_output(void)
{
asdf_keymaps_select_keymap(1);
asdf_keymaps_select_keymap(TRIPLE_TESTS_KEYMAP);
// check that initial values have been set:
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_OUT1));
TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_OUT2));
@ -173,16 +175,111 @@ void test_pulse_triple_output(void)
TEST_ASSERT_EQUAL_INT32(PD_ST_TRANSITION_LOW, asdf_arch_check_pulse(VMAP_OUT1));
TEST_ASSERT_EQUAL_INT32(PD_ST_TRANSITION_LOW, asdf_arch_check_pulse(VMAP_OUT2));
TEST_ASSERT_EQUAL_INT32(PD_ST_TRANSITION_LOW, asdf_arch_check_pulse(VMAP_OUT3));
// asdf_virtual_activate(VOUT1); // funtion is set to toggle
//TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_OUT1));
//TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_OUT2));
//TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_OUT3));
}
//asdf_virtual_action(VOUT1, V_TOGGLE);
//TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_OUT1));
//TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_OUT2));
//TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_OUT3));
uint8_t *output_array(void)
{
static uint8_t outputs[NUM_REAL_OUTPUTS] = {};
for (uint8_t i = 0; i < NUM_REAL_OUTPUTS; i++) {
outputs[i] = asdf_arch_check_output(i);
printf("output %d: %d\n", i, outputs[i]);
}
return outputs;
}
uint8_t *all_set_array(void)
{
static uint8_t outputs[NUM_REAL_OUTPUTS] = {};
for (uint8_t i = 0; i < NUM_REAL_OUTPUTS; i++) {
outputs[i] = 1;
}
return outputs;
}
uint8_t *all_zero_array(void)
{
static uint8_t outputs[NUM_REAL_OUTPUTS] = {};
for (uint8_t i = 0; i < NUM_REAL_OUTPUTS; i++) {
outputs[i] = 0;
}
return outputs;
}
uint8_t *single_zero_array(asdf_virtual_real_dev_t set_element)
{
static uint8_t outputs[NUM_REAL_OUTPUTS] = {};
for (uint8_t i = 0; i < NUM_REAL_OUTPUTS; i++) {
outputs[i] = 1;
}
outputs[set_element] = 0;
return outputs;
}
void test_virtual_capslock_indicator(void)
{
asdf_keymaps_select_keymap(VCAPS_TEST_KEYMAP);
// CAPS LED output should be initialized to zero:
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED1));
// emulate capslock press and release. Should set LED1
asdf_modifier_capslock_activate();
asdf_modifier_capslock_deactivate();
TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_LED1));
// emulate capslock press and release. clear LED1
asdf_modifier_capslock_activate();
asdf_modifier_capslock_deactivate();
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED1));
}
void test_virtual_shiftlock_indicator(void)
{
asdf_keymaps_select_keymap(VSHIFT_TEST_KEYMAP);
// CAPS LED output should be initialized to zero:
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED2));
// emulate shiftlock press and release. Should set LED2
asdf_modifier_shiftlock_activate();
asdf_modifier_shiftlock_deactivate();
TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_LED2));
// emulate shift press and release. clear LED2
asdf_modifier_shift_activate();
asdf_modifier_shift_deactivate();
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED2));
}
void test_cant_assign_real_output_twice(void)
{
asdf_keymaps_select_keymap(DOUBLE_ASSIGN_TEST_KEYMAP);
// initial value should be set to 0:
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED1));
// set LED1 high from valid VOUT4
asdf_virtual_action(VOUT4, V_SET_HI);
TEST_ASSERT_EQUAL_INT32(1, asdf_arch_check_output(VMAP_LED1));
// set LED1 low from valid VOUT4
asdf_virtual_action(VOUT4, V_SET_LO);
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED1));
// set LED1 high from invalid VOUT5
asdf_virtual_action(VOUT5, V_SET_HI);
// Should not have changed.
TEST_ASSERT_EQUAL_INT32(0, asdf_arch_check_output(VMAP_LED1));
}
int main(void)
@ -198,5 +295,8 @@ int main(void)
RUN_TEST(test_toggle_triple_output);
RUN_TEST(test_set_triple_output);
RUN_TEST(test_pulse_triple_output);
RUN_TEST(test_virtual_capslock_indicator);
RUN_TEST(test_virtual_shiftlock_indicator);
RUN_TEST(test_cant_assign_real_output_twice);
return UNITY_END();
}