Archived
1
0
This repo is archived. You can view files and clone it, but cannot push or open issues or pull requests.
keybrd/doc/keybrd_library_developer_guide.md
2016-07-14 18:52:16 -06:00

10 KiB

keybrd Library Developer's Guide

This guide if for maintaining and writing new classes for the keybrd library and its extension libraries. The most common reason for new classes are:

  • Port classes for micro controller or I/O expanders
  • custom layer schemes for multi-layer keyboards
  • experimental features

Who this guide is for

This guide is for the maintainers and developers of the keybrd library and it's extensions. It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. Debouncer and I/O expander use bit manipulation.

Custom Row classes

The keybrd library is flexible for designing custom Rows

  • Row functions can be overridden in a derived class
  • choice of Debouncers
  • choice of Scanners

this example illustrates the custom Row classes for a fictional keybrd_Ext extension library the keybrd_Ext library is for a split keyboard with a matrix on each hand

Row_Ext::keyWasPressed() overrides Row::keyWasPressed() Row_Ext::keyWasPressed() is used to unstick sticky keys

Row_Ext_uC scans the primary matrix Row_Ext_ShiftRegisters scans the secondary matrix Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock keybrd library classes

Class inheritance diagram


    	   Row
	         |
	       Row_Ext                                (override Row::keyWasPressed() )
          /      \
    Row_Ext_uC  Row_Ext_ShiftRegisters            (inherit Row_Ext::keyWasPressed() )


	Scanner_uC  Scanner_ShiftRegs74HC165

Dependency diagram


	         ________ Row_Ext_uC[1] _______________
	        /                     \                \
	Scanner_uC[1]  Debouncer_Samples[1]  Key[1..*]
	     /          \                               |
	strobePin[1]  readPins[1..*]                   Code[1..*]


                _____ Row_Ext_ShiftRegisters[1] ________
	           /                        \               \
    Scanner_ShiftRegs74HC165[1]  Debouncer_Samples[1]  Key[1..*]
	       /       \                                     |
    strobePin[1]  ROW_END[1]                           Code[1..*]

Class inheritance diagrams

Keybrd library class inheritance diagram

	     ________ Row ___________
	    /          |             \
	Row_uC  Row_ShiftRegisters  Row_IOE (to be added)


	Scanner_uC  Scanner_Port  Scanner_ShiftRegs74HC165


	PortIOE

	    PortWrite
	       |
	PortWrite_PCA9655E                         (one PortWrite class for each IOE type)
 
        PortRead
	       |
	PortRead_PCA9655E                           (one PortRead class for each IOE type)
 
	       ____ LED ____
	      /             \
	LED_PinNumber  LED_PCA9655E


	DebouncerInterface
	      |
	Debouncer_4Samples

    ScanDelay

	LayerStateInterface
	     |
	LayerState


	Key __
	 |    \
	 |   Key_LayeredKeysArray
	 |
	Code
	 |_____________________
	 |     \               \
	 |   Code_LayerLock  Code_LayerHold
	 |
	 |___________________________
	 |     \                     \
	 |   Code_LayeredScScBase  Code_LayeredCodeScBase
	 |      |                     |
	 |   Code_LayeredScSc      Code_LayeredCodeSc
	 |
	 |__________________________________________
	       \           \            \           \
	     Code_Sc  Code_Shift  Code_AutoShift  Code_LEDLock
	                         /      |      \
	                  Code_ScS  Code_ScNS  Code_ScNS_00

Dependency diagrams

Example single-layer dependency diagram with LEDs

	        _ Row_uC[1..*] _
	       /      |         \
	Scanner_uC  Debouncer  Keys[1..*] __
	                         |          \
	                       Code[1..*]  Code_LEDLock[1..*]
	                                     |
	                                   LED_PinNumber[1]

Example multi-layer dependency diagram with layer LEDs

	                                          LayerStates[1..*]
	         ________ Row_uC[1..*] ___________/__    |         \
	        /           |         \          /   \   |          \
	Scanner_uC[1]  Debouncer[1]  Keys[1..*] / Code_Layer[1..*]  LED_PinNumber[0..*]
	                               |       /
	                             Code[1..*]

Example secondary matrix with shift registers dependency diagram

	              Row_ShiftRegisters[1..*]
	             /              \         \
	RowScanner_ShiftRegisters  Debouncer  Keys[1..*]
	                                       |
	                                      Code[1..*]

Example secondary matrix with I/O Expander dependency diagram with LEDs

	                 ___ Row_IOE[1..*] _________
	                /             \             \
	       _ Scanner_Port[1] _   Debouncer[1]  Keys[1..*] __
	      /          |        \                  |          \
	PortWrite[1]   RowPin[1]  PortRead[1]      Code[1..*]  Code_LEDLock[1..*]
	      \                   /   \                          |
	       \                 /   ColPins[1..*]             LED[1]
	        \               /
	          PortIOE[0..*]

Class naming conventions

Class names start with upper case letter. Most derived-class names start with the base class name followed by "_" and a name e.g.

	Code
	  |
	Code_LayerLock

This convention leads to class names that convey information about the classes inheritance. Underscore delineates base class name and sub-class name. Capital letters delineate words.

Layer-class naming conventions

Code_Layer class names are concatenations of "Code_", "Layer" or layer name, and persistence. Example persistences are:

  • "Lock" - layer remains active after the layer key is released
  • "Hold" - layer is active for as long as layer key is held down

Example Code_Layer class names:

  • Code_LayerHold
  • Code_LayerLock

LayerState class names start with "LayerState" and end with a descriptive name. Example LayerState class names:

  • LayerState - basic LayerState class in keybrd library
  • LayerState_DH - main LayerState for the keybrd_DH library
  • LayerState_MF - LayerState for Mouse Function sub-layers in the keybrd_DH library

Code_Layered class names start with "Code_Layered" and end with a descriptive name. Example Code_Layered class names:

  • Code_LayeredScSc
  • Key_LayeredKeysArray

Style guide

Following the style guide makes it easier for the next programmer to understand your code.

  • For class names, see above section "Class naming conventions".
  • Member names use camelCase starting with lowercase letter.
  • Use constants rather than macros, except for header guards.
  • Global const names and static const names use ALL_CAPS_AND_UNDERSCORE.
  • Macros use ALL_CAPS_AND_UNDERSCORE and have _MACRO suffix e.g. SAMPLE_COUNT_MACRO
  • Header guards have _H suffix e.g. #ifndef FILE_NAME_H
  • Pointer names are prefixed with "ptr" e.g. ptrRow = &row;
  • Arrays names use the plural of element name e.g. Row* const = ptrsRows { &row0, &row1 };
  • Pass arrays using array notation rather than pointer notation:
        void printArray(char[] array);
    not
        void printArray( char* array);
  • In constructor's initialization list, use same names for fields and constructor parameters.

  • Do not use new or malloc (making memory leaks impossible).

  • Document class interface in .h file, above the class declaration.

  • Code should be self-documenting. A simple function with a good name needs no comment.

  • Code is automatically formatted before being pushed to the keybrd repository. The astyle_cpp file specifies the format:

    • Allman style indentation
    • indent 4 spaces
    • replace tabs with spaces
    • maximum code width of 100 columns

Trace of keybrd scan

Arduino does not have a debugger. So here is the next best thing; a list of functions in the order that they are called. The trace is of a single-layer keybrd scan (no LEDs and no I/O expander). Refer to it like a table of contents while reading the keybrd library.

    loop()                                      for each row
        Row::process()
            Scanner_uC::scan()            strobe row on
                                                        for each readPin
                                                            set rowState bit
                                                    strobe row off
            Debouncer_4Samples::debounce()          debounce
            Row::send()                         for each key in row
                                                        if falling edge
                Key_*::release()                            scanCode->release()
                    Code_*::release()                           Keyboard.release(scancode)
                                                        if rising edge
                Key_*::press()                              scanCode->press()
                    Code_*::press()                             Keyboard.press(scancode)
        scanDelay.delay();
         

The Arduino libraries

The keybrd libraries compile on the Arduino IDE and make extensive use of the following Arduino libraries:

#include <Arduino.h>
#include <Wire.h>
#include <Keyboard.h>
#include <Mouse.h>

Creative Commons License
keybrd guide by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new.