Skip to content

Instantly share code, notes, and snippets.

@omaskery
Last active August 29, 2015 14:05
Show Gist options
  • Save omaskery/7bb96a1ad9126ec332a3 to your computer and use it in GitHub Desktop.
Save omaskery/7bb96a1ad9126ec332a3 to your computer and use it in GitHub Desktop.
Simple Arduino sketch that takes a table of 'mappings' that monitor input pins, with specific combinations triggering events to either momentarily or persistently assert output and/or press keyboard keys.
//! structure describing a mapping from input values to output events
typedef struct sMappingInfo
{
// sensing
uint64_t InputMask; //!< what digital inputs must be high to trigger this mapping
// actuating
uint64_t AssertMask; //!< what digital outputs must be asserted when mapping is triggered
uint8_t AssertKey; //!< what key is pressed when mapping is triggered
// mapping configuration
uint8_t bToggleActuation; //!< whether mapping remains asserted until input event occurs again
} tMappingInfo;
//! structure describing a mapping with its current state
typedef struct sLiveMapping
{
tMappingInfo Mapping; //!< the mapping used in this event
uint8_t bTriggered; //!< whether this mapping is currently being asserted
} tLiveMapping;
const uint8_t MaxDigitalPins = 54; //!< number of digital IO pins
const uint8_t MaxMappings = 1; //!< max number of input/output mappings
static tLiveMapping g_Mappings[MaxMappings]; //!< mappings list
static uint64_t g_InputMask = 0; //!< mask of all input pins
static uint64_t g_AssertMask = 0; //!< mask of all output pins
static uint64_t g_PersistantOutputs = 0; //!< all toggled outputs
static uint64_t g_Outputs = 0; //!< last outputs asserted
static uint64_t g_LastInput = 0; //!< last inputs measured
void setup()
{
Serial.begin(115200);
Serial.print("Configuring mappings (");
Serial.print(MaxMappings);
Serial.println("):");
// some hardcoded mappings
g_Mappings[0].Mapping.InputMask = 1 << 2;
g_Mappings[0].Mapping.AssertMask = 1 << 13;
g_Mappings[0].Mapping.AssertKey = KEY_LEFT_SHIFT;
g_Mappings[0].Mapping.bToggleActuation = 1;
// find all input and output pins
for(uint8_t Index = 0; Index < MaxMappings; Index++)
{
g_InputMask |= g_Mappings[Index].Mapping.InputMask;
g_AssertMask |= g_Mappings[Index].Mapping.AssertMask;
}
// configure all input and output pins
for(uint8_t Index = 0; Index < MaxDigitalPins; Index++)
{
if((g_InputMask >> Index) == 1)
{
Serial.print("\tPin ");
Serial.print(Index);
Serial.println(" is an input");
pinMode(Index, INPUT);
}
else if((g_AssertMask >> Index) == 1)
{
Serial.print("\tPin ");
Serial.print(Index);
Serial.println(" is an output");
pinMode(Index, OUTPUT);
}
}
// enable keyboard HID support
Keyboard.begin();
}
void loop()
{
uint64_t Outputs = 0;
uint64_t Inputs = 0;
// read all input pins
for(uint8_t Index = 0; Index < MaxDigitalPins; Index++)
{
if((g_InputMask >> Index) == 1)
{
if(digitalRead(Index))
{
Inputs |= 1 << Index;
}
}
}
// if a key is pressed, check the mappings
if(Inputs != 0)
{
for(uint8_t Index = 0; Index < MaxMappings; Index++)
{
const uint64_t Mask = g_Mappings[Index].Mapping.InputMask;
// skip if this mapping has a null mask
if(Mask == 0) continue;
// skip if the inputs don't match the mapping's mask
if((Inputs & Mask) != Mask) continue;
// if this mapping is a "active while held"
if(g_Mappings[Index].Mapping.bToggleActuation == 0)
{
Outputs |= g_Mappings[Index].Mapping.AssertMask;
if(g_Mappings[Index].Mapping.AssertKey != 0)
{
Serial.print("Tapping key ");
Serial.println(g_Mappings[Index].Mapping.AssertKey, HEX);
Keyboard.press(g_Mappings[Index].Mapping.AssertKey);
Keyboard.release(g_Mappings[Index].Mapping.AssertKey);
}
}
// if this mapping is a "toggle when pressed" and the key was just pressed
else if((g_LastInput >> Index) == 0)
{
// toggle assertion state
g_Mappings[Index].bTriggered = !g_Mappings[Index].bTriggered;
// if toggled to active assert outputs and press keys
if(g_Mappings[Index].bTriggered)
{
g_PersistantOutputs |= g_Mappings[Index].Mapping.AssertMask;
if(g_Mappings[Index].Mapping.AssertKey != 0)
{
Serial.print("Pressing key ");
Serial.println(g_Mappings[Index].Mapping.AssertKey, HEX);
Keyboard.press(g_Mappings[Index].Mapping.AssertKey);
}
}
// if toggled to inactive deassert outputs and release keys
else
{
g_PersistantOutputs &= ~(g_Mappings[Index].Mapping.AssertMask);
if(g_Mappings[Index].Mapping.AssertKey != 0)
{
Serial.print("Releasing key ");
Serial.println(g_Mappings[Index].Mapping.AssertKey, HEX);
Keyboard.release(g_Mappings[Index].Mapping.AssertKey);
}
}
}
}
}
// incorporate toggled outputs into the outputs for this update
Outputs |= g_PersistantOutputs;
// see if the 'new' outputs are different to the last outputs written
if((Outputs ^ g_Outputs) != 0)
{
Serial.println("Updating outputs.");
/*
Serial.print("\t");
Serial.println((unsigned long) Outputs, BIN);
Serial.print("\t");
Serial.println((unsigned long) g_Outputs, BIN);
*/
// update all output pins
for(uint8_t Index = 0; Index < MaxDigitalPins; Index++)
{
if((g_AssertMask >> Index) == 1)
{
const bool Value = (Outputs >> Index) == 1;
Serial.print("Setting output ");
Serial.print(Index);
Serial.println(Value ? " high" : " low");
digitalWrite(Index, Value ? HIGH : LOW);
}
}
// remember what outputs we asserted
g_Outputs = Outputs;
}
// remember what inputs we saw this update
g_LastInput = Inputs;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment