In the past, we were using `Focus.handleHelp()` to see if we're handling a
`help` command, and print the commands supported by the handler. We also used
`strcmp_P` directly to compare (parts of) our input against command supported by
the handler. This approach works, but had multiple major disadvantages: it
duplicated strings between `handleHelp` and the `strcmp_P` calls, and it relied
on fragile substring pointers to save space.
To replace all that, this patch implements a different approach. Help handling
is split between a check (`Focus.inputMatchesHelp()`) and a
reply (`Focus.printHelp()`), the latter of which takes a list of `PSTR()`
strings, rather than one single string. This allows us to reuse the same
strings for comparing against the handler's input.
The new approach no longer uses the fragile substring pointers, nor does it use
`strcmp_P` directly, but goes through a wrapper (`Focus.inputMatchesCommand()`)
instead.
These changes lead to a more readable pattern. While we do use longer strings as
a result, there is less duplication, and the new patterns also require less
code, so we end up with saving space, at least on AVR devices.
The old methods are still available and usable, but they're deprecated.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
`Serial.read()` is unbuffered, and will return `-1` (which we cast to an
unsigned char, so 255) immediately if there is no data in the incoming buffer.
This is unlike every other kind of read we do, which use `parseInt()`, and are
thus buffered reads with a timeout.
The problem with returning `-1` immediately is that Chrysalis sends data in
chunks, so if we end up trying to read a char at a chunk boundary, we'll end up
reading -1s, which we treat as valid data, and cast it to an unsigned char,
completely throwing off the protocol in the process.
By using `readBytes()`, we have a one second window during which more data can
arrive, and as such, is consistent with the rest of our reads.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The new plugin enables configuring some aspects of SpaceCadet through Focus: the
current mode, and the global timeout. This is makes it possible to ship firmware
with SpaceCadet included, disabled by default, but still allow one to enable it
without having to map and tap the enable key.
The settings are also persisted into storage.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The example in the documentation was referring to a function that does not
exist. Correct it to use the one that does.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Fall back to `dash` on macOS, because `bash` randomly drops serial
input, causing the tool to hang.
Flush the command buffer before sending the requested command. A
failed upload session can cause characters to remain in the command
buffer.
Redirect stdin instead of using a separate file descriptor. Also do
this before running `stty`. This allows the `stty` settings to
actually take effect on macOS, which seems to reset the termios
state of serial devices upon the last close of the device.
Tested on macOS 10.15 and Ubuntu 20.04.
Signed-off-by: Taylor Yu <tlyu@mit.edu>
Previously, a newline that wasn't read with the rest of the command in
a single event would get appended to the command buffer instead of
remaining in the "peek" buffer, so the command dispatch would never
fire.
Stash a space delimiter instead of storing it in the buffer, only to
overwrite it later.
Fix an off-by-one error that could cause a buffered command to not be
null-terminated. This probably didn't cause a problem in practice,
because Focus plugins mostly did a `strcmp` against a fixed string that
is smaller than the command buffer size.
Signed-off-by: Taylor Yu <tlyu@mit.edu>
The new plugin provides a Focus-based interface for setting custom layer names.
The layer names aren't used internally, they're purely for use by host-side
applications.
This addresses the Kaleidoscope-side of keyboardio/Chrysalis#3.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
It was always intended to be public - it is even documented as such! -, but was
mistakenly left private.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of simply echoing "device.reset" into the device port, call
`bin/focus-send`, which sets the `raw` setting on the port, before writing into
it. Without that, the command is not recognised by the firmware.
We could do the stty call in the makefile directly, but to support macOS, we'd
need to treat that specially, and at that point, it's easier to just call
`bin/focus-send`. The sketch relies on having the Kaleidoscope repo available
anyway, so we can safely rely on `bin/focus-send` being there, too.
Because we're now using the tool in the makefiles, `focus-test` was renamed to
`focus-send`.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
A number of devices declared the bootloader in their device properties as
`BootLoader`, while the base class, and anything using it, was looking for
`Bootloader`. This resulted in these devices using the default, dummy
bootloader, rather than the one we intended to set.
This patch corrects that, and everything's using `Bootloader` now, including the
documentation.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This simple plugin does nothing more than provide a `version` focus command,
which will print the firmware version configured at build-time (defaulting to
"0.0.0").
This is a header-only plugin, so that Arduino compiles it in the same
compilation unit as the main sketch, allowing us to set the version from the
sketch, if so desired.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The Model100 has a lot more space available compared to the Model01, so we can
have more layers in EEPROM. While we could have more than 8, 8 is the limit that
OneShot and dual-use keys support via Chrysalis, so to avoid potential
confusion, lets have 8 layers only.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This enables the IdleLEDs, Qukeys, OneShot, Escape-OneShot and DynamicMacros
plugins for the Model100 sketch. None of these - apart from IdleLEDs - cause any
change in behavior unless first configured so.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This new plugin lets us store a default palette and colormap in PROGMEM.
Rather than teaching Colormap to pull from either EEPROM or PROGMEM, this
implements an entirely separate plugin, `DefaultColormap`, which is able
to *push* a palette and colormaps into Colormap.
When `DefaultColormap.setup()` is called, it checks if Colormap's storage area
is empty (both palette and the map must be empty), and if so, copies the
built-in palette and colormap over, and forces a refresh, and it has done its
job.
It does provide an additional Focus command too, `colormap.install`, which will
forcibly copy both palette and colormaps over. Useful for resetting back to a
factory setting.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
To be able to set a theme from the firmware itself, we need a couple of helper
methods. First, we need to be able to update the palette without using Focus,
and we also need to be able to update a single LED without committing it. On top
of that, we'll likely want to know if the theme is initialized.
To this end, we introduce `updatePaletteColor()`, which updates an entry in the
palette, but does not commit it, and `isThemeUninitialized()` which does as the
name suggests: it checks if the palette and the theme slices are all uninitialized.
We also change `updateColorIndexAtPosition()` to not commit. The single user of
it was FingerPainter, and we update that to do an explicit commit after.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This test verifies that PrefixLayer doesn't clear held non-modifier keys from
the report before sending the prefix sequence.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This new plugin provides a way to set a default (but configurable, via Focus)
led mode, or use a specific one if EEPROM is uninitialized.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>