Compare commits
4 Commits
main
...
charshift/
Author | SHA1 | Date |
---|---|---|
|
0cc060e4a4 | 4 years ago |
|
ee36ed6929 | 4 years ago |
|
7d6ce8bf45 | 4 years ago |
|
f916c2c0d4 | 4 years ago |
@ -1,47 +0,0 @@
|
|||||||
# -*- mode: yaml -*-
|
|
||||||
---
|
|
||||||
BasedOnStyle: Google
|
|
||||||
---
|
|
||||||
Language: Cpp
|
|
||||||
|
|
||||||
AlignConsecutiveAssignments: Consecutive
|
|
||||||
## clang-format-15
|
|
||||||
# AlignConsecutiveAssignments:
|
|
||||||
# Enabled: true
|
|
||||||
# AlignCompound: true
|
|
||||||
# PadOperators: true
|
|
||||||
AlignConsecutiveDeclarations: None
|
|
||||||
AlignConsecutiveMacros: AcrossEmptyLines
|
|
||||||
AlignEscapedNewlines: Right
|
|
||||||
AllowShortBlocksOnASingleLine: Empty
|
|
||||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
AttributeMacros:
|
|
||||||
- __attribute__((weak))
|
|
||||||
- __attribute__((always_inline))
|
|
||||||
- __attribute__((noinline))
|
|
||||||
- __attribute__((packed))
|
|
||||||
- __attribute__((optimize(3)))
|
|
||||||
- __attribute__((unused))
|
|
||||||
BinPackArguments: false
|
|
||||||
BinPackParameters: false
|
|
||||||
# BraceWrapping:
|
|
||||||
# SplitEmptyFunction: false
|
|
||||||
# SplitEmptyRecord: true
|
|
||||||
# SplitEmptyNamespace: true
|
|
||||||
# BreakBeforeBraces: Custom
|
|
||||||
ColumnLimit: 0
|
|
||||||
ConstructorInitializerIndentWidth: 2
|
|
||||||
ContinuationIndentWidth: 2
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
IndentCaseLabels: false
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
MaxEmptyLinesToKeep: 2
|
|
||||||
# PackConstructorInitializers: CurrentLine
|
|
||||||
PointerAlignment: Right
|
|
||||||
# ReferenceAlignment: Right
|
|
||||||
ReflowComments: false
|
|
||||||
SortIncludes: false
|
|
||||||
SpaceAfterTemplateKeyword: false
|
|
@ -1,9 +0,0 @@
|
|||||||
set noparent
|
|
||||||
|
|
||||||
extensions=cpp,h,ino
|
|
||||||
|
|
||||||
filter=-build/include
|
|
||||||
filter=-legal/copyright
|
|
||||||
filter=-readability/namespace
|
|
||||||
filter=-runtime/references
|
|
||||||
filter=-whitespace
|
|
@ -1,9 +0,0 @@
|
|||||||
set noparent
|
|
||||||
|
|
||||||
extensions=cpp,h,ino
|
|
||||||
|
|
||||||
filter=-build/include
|
|
||||||
filter=-legal/copyright
|
|
||||||
filter=-readability/namespace
|
|
||||||
filter=-runtime/references
|
|
||||||
filter=-whitespace/line_length
|
|
@ -1,14 +0,0 @@
|
|||||||
examples
|
|
||||||
src/Kaleidoscope.h
|
|
||||||
src/Kaleidoscope-LEDControl.h
|
|
||||||
src/kaleidoscope/HIDTables.h
|
|
||||||
src/kaleidoscope/driver/bootloader/gd32/Base.h
|
|
||||||
src/kaleidoscope/driver/led/Base.h
|
|
||||||
src/kaleidoscope/driver/led/WS2812.h
|
|
||||||
src/kaleidoscope/driver/led/ws2812/config.h
|
|
||||||
src/kaleidoscope/driver/mcu/GD32.h
|
|
||||||
src/kaleidoscope/driver/storage/GD32Flash.h
|
|
||||||
plugins/Kaleidoscope-FirmwareDump/**
|
|
||||||
plugins/Kaleidoscope-HostOS/src/kaleidoscope/plugin/HostOS.h
|
|
||||||
plugins/Kaleidoscope-Hardware-EZ-ErgoDox/src/kaleidoscope/device/ez/ErgoDox/i2cmaster.h
|
|
||||||
testing/googletest
|
|
@ -0,0 +1,3 @@
|
|||||||
|
# -*- mode: sh -*-
|
||||||
|
|
||||||
|
DEFAULT_SKETCH=Kaleidoscope
|
@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
: "${KALEIDOSCOPE_DIR:=$(pwd)}"
|
|
||||||
cd "${KALEIDOSCOPE_DIR}" || exit 1
|
|
||||||
|
|
||||||
ERROR_COUNT=0
|
|
||||||
|
|
||||||
while read -r SCRIPT; do
|
|
||||||
shellcheck "${SCRIPT}"
|
|
||||||
(( ERROR_COUNT += $? ))
|
|
||||||
done < <(grep -E -n -r -l '(env (ba)?sh)|(/bin/(ba)?sh)' "${KALEIDOSCOPE_DIR}/bin")
|
|
||||||
|
|
||||||
exit $ERROR_COUNT
|
|
@ -1,110 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
|
||||||
|
|
||||||
# This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
# distribute this software, either in source code form or as a compiled
|
|
||||||
# binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
# means.
|
|
||||||
|
|
||||||
# In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
# of this software dedicate any and all copyright interest in the
|
|
||||||
# software to the public domain. We make this dedication for the benefit
|
|
||||||
# of the public at large and to the detriment of our heirs and
|
|
||||||
# successors. We intend this dedication to be an overt act of
|
|
||||||
# relinquishment in perpetuity of all present and future rights to this
|
|
||||||
# software under copyright law.
|
|
||||||
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
# For more information, please refer to <http://unlicense.org/>
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
"""Utilities shared by Kaleidoscope code maintenance tools."""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from contextlib import contextmanager
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
@contextmanager
|
|
||||||
def cwd(temp_wd):
|
|
||||||
"""Execute code in a different working directory
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
`temp_wd` (`str`): The name of a directory to (temporarily) change to
|
|
||||||
|
|
||||||
Change the current working directory, then automatically restore the previous working
|
|
||||||
directory when done. Invoke `cwd()` like this:
|
|
||||||
```py
|
|
||||||
with cwd(temp_wd):
|
|
||||||
...
|
|
||||||
```
|
|
||||||
"""
|
|
||||||
old_wd = os.getcwd()
|
|
||||||
os.chdir(temp_wd)
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
os.chdir(old_wd)
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def split_on_newlines(string):
|
|
||||||
"""Split the string using newlines as the separator."""
|
|
||||||
return string.splitlines()
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
def split_on_nulls(string):
|
|
||||||
"""Split the input string using NULL characters as the separator."""
|
|
||||||
targets = [_ for _ in string.split('\0') if _ != '']
|
|
||||||
return targets or []
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def setup_logging(loglevel):
|
|
||||||
"""Set up basic logging."""
|
|
||||||
logformat = "%(message)s"
|
|
||||||
logging.basicConfig(
|
|
||||||
level=loglevel,
|
|
||||||
stream=sys.stdout,
|
|
||||||
format=logformat,
|
|
||||||
datefmt="",
|
|
||||||
)
|
|
||||||
return logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def check_git_diff():
|
|
||||||
"""Check for unstaged changes with `git diff`
|
|
||||||
|
|
||||||
Returns: a list of the names of files with unstaged changes
|
|
||||||
|
|
||||||
This check isn't perfect, because it can give false positives (if there are unrelated
|
|
||||||
unstaged changes).
|
|
||||||
"""
|
|
||||||
git_diff_cmd = ['git', 'diff', '-z', '--exit-code', '--name-only']
|
|
||||||
|
|
||||||
changed_files = []
|
|
||||||
proc = subprocess.run(git_diff_cmd, capture_output=True)
|
|
||||||
if proc.returncode != 0:
|
|
||||||
changed_files = split_on_nulls(proc.stdout.decode('utf-8'))
|
|
||||||
return changed_files
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(1)
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Scan all USB devices to find the Model 01's modem device number.
|
||||||
|
#
|
||||||
|
my @output = qx(/usr/sbin/usbconfig show_ifdrv);
|
||||||
|
my $serial_port_number;
|
||||||
|
|
||||||
|
foreach my $line (@output) {
|
||||||
|
chomp $line;
|
||||||
|
|
||||||
|
next unless $line =~ m/umodem(\d+):.*Keyboardio Model 01/;
|
||||||
|
$serial_port_number = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "Can't find Model 01" unless defined($serial_port_number);
|
||||||
|
|
||||||
|
my $serial_port_name = "/dev/cuaU$serial_port_number";
|
||||||
|
die "Missing serial port at $serial_port_name" unless -e $serial_port_name;
|
||||||
|
print "$serial_port_name\n";
|
||||||
|
exit 0;
|
@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
# find-device-port-linux-udev - Kaleidoscope helper tool
|
||||||
|
# Copyright (C) 2017-2018 Keyboard.io, Inc.
|
||||||
|
#
|
||||||
|
# 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, version 3.
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use FindBin qw{$Bin};
|
||||||
|
|
||||||
|
die "Usage: $0 VID PID [-v]\n" unless @ARGV >= 2;
|
||||||
|
|
||||||
|
my $vid = shift @ARGV;
|
||||||
|
my $pid = shift @ARGV;
|
||||||
|
my $verbose = shift @ARGV if (@ARGV);
|
||||||
|
my $prefix = '/dev/serial/by-id/';
|
||||||
|
my @paths = `ls $prefix`;
|
||||||
|
my %devices;
|
||||||
|
my @log;
|
||||||
|
|
||||||
|
sub debug {
|
||||||
|
if ($verbose) {
|
||||||
|
print STDERR @_;
|
||||||
|
} else {
|
||||||
|
push @log, @_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_warning {
|
||||||
|
print STDERR @_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
debug "Looking for USB device with vid=$vid and pid=$pid\n";
|
||||||
|
|
||||||
|
for my $path (@paths) {
|
||||||
|
chomp($path);
|
||||||
|
debug "Examining $path\n";
|
||||||
|
debug " not symlink\n" unless -l $prefix . $path;
|
||||||
|
next unless -l $prefix . $path;
|
||||||
|
my @data = `udevadm info -q property --name=${prefix}${path}`;
|
||||||
|
for my $line (@data) {
|
||||||
|
chomp($line);
|
||||||
|
my ( $key, $val ) = split( /=/, $line, 2 );
|
||||||
|
$devices{$path}{$key} = $val;
|
||||||
|
}
|
||||||
|
if ( hex $devices{$path}{'ID_VENDOR_ID'} != hex $vid ) {
|
||||||
|
debug " ID_VENDOR_ID $devices{$path}{'ID_VENDOR_ID'} != $vid\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ( hex $devices{$path}{'ID_MODEL_ID'} != hex $pid ) {
|
||||||
|
debug " ID_MODEL_ID $devices{$path}{'ID_MODEL_ID'} != $pid\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug " Found keyboard!\n";
|
||||||
|
|
||||||
|
if ( $devices{$path}{'ID_MM_DEVICE_IGNORE'} ) {
|
||||||
|
debug " ID_MM_DEVICE_IGNORE is set - good!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $devices{$path}{'ID_MM_CANDIDATE'}) {
|
||||||
|
my $rules = "$Bin/../etc/60-kaleidoscope.rules";
|
||||||
|
print_warning <<EOWARN
|
||||||
|
|
||||||
|
WARNING: your udev rules are currently configured to suggest
|
||||||
|
that your keyboard is suitable for use by ModemManager. This
|
||||||
|
means that there is a risk of ModemManager interfering. To avoid
|
||||||
|
this, copy
|
||||||
|
|
||||||
|
$rules
|
||||||
|
|
||||||
|
to /etc/udev/rules.d
|
||||||
|
EOWARN
|
||||||
|
}
|
||||||
|
|
||||||
|
print $devices{$path}{DEVNAME};
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#debug("ERROR: I couldn't find a USB device matching the keyboard's USB Vendor and Device IDs\n");
|
||||||
|
#print_warning(join("\n",@log));
|
@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
# Based on listArduinos.pl from https://github.com/todbot/usbSearch (License: MIT)
|
||||||
|
# Original (C) 2012, Tod E. Kurt, http://todbot.com/blog/
|
||||||
|
# This version by Michael Richters <gedankenexperimenter@gmail.com> and Jesse Vincent <jesse@keyboard.io>
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
my $vid = shift @ARGV;
|
||||||
|
my $pid = shift @ARGV;
|
||||||
|
|
||||||
|
if (!defined $vid || !defined $pid) {
|
||||||
|
die "$0 has two required parameters, VID and PID";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ioreg might be more machine-readable than system_profiler, but I haven't been able to
|
||||||
|
# get it to produce useful output
|
||||||
|
my @output = qx(/usr/sbin/system_profiler SPUSBDataType 2> /dev/null);
|
||||||
|
|
||||||
|
my $serial = "";
|
||||||
|
my $location = "";
|
||||||
|
|
||||||
|
my $output = join('', @output);
|
||||||
|
|
||||||
|
my @stanzas = split(/\n\n/, $output);
|
||||||
|
foreach my $stanza (@stanzas) {
|
||||||
|
if ($stanza =~ /Product ID: ${pid}/ && $stanza =~ /Vendor ID: ${vid}/) {
|
||||||
|
if ($stanza =~ /Serial Number: (.*?)$/m) {
|
||||||
|
$serial = $1;
|
||||||
|
}
|
||||||
|
if ($stanza =~ /Location ID: (.*?)$/m) {
|
||||||
|
$location = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serial) {
|
||||||
|
try_for_raw_serialnum($serial);
|
||||||
|
}
|
||||||
|
if ($location) {
|
||||||
|
try_for_location_id($location);
|
||||||
|
}
|
||||||
|
if ($serial) {
|
||||||
|
try_for_sn_prefix($serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub try_for_raw_serialnum {
|
||||||
|
my $sn = shift;
|
||||||
|
|
||||||
|
my $serial_port_name = "/dev/cu.usbmodem" . $sn;
|
||||||
|
exit_with_port_if_exists($serial_port_name);
|
||||||
|
|
||||||
|
# High Sierra sometimes has a mismatch between the serial number and the device
|
||||||
|
# filename. I'm not sure why, but system_profiler has a serial number ending in "E",
|
||||||
|
# whereas the device filename ends in "1". In fact, when I change HID.getShortName()
|
||||||
|
# to return "kbio02", the final character is replaced with a "1".
|
||||||
|
|
||||||
|
if ($serial_port_name =~ /\d$/) {
|
||||||
|
chop $serial_port_name;
|
||||||
|
exit_with_port_if_exists($serial_port_name . "1");
|
||||||
|
} else {
|
||||||
|
# If the serial port name doesn't end with a digit, try -appending- rather than replacing
|
||||||
|
# the last character of the port name
|
||||||
|
exit_with_port_if_exists($serial_port_name . "1");
|
||||||
|
|
||||||
|
# and if that didn't work, try replacing the last character with a "1" anyway.
|
||||||
|
# Jason Koh reports that he saw this behavior as required on Catalina in May 2020.
|
||||||
|
|
||||||
|
chop $serial_port_name;
|
||||||
|
exit_with_port_if_exists($serial_port_name . "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub try_for_location_id {
|
||||||
|
my $location_id = shift;
|
||||||
|
|
||||||
|
# macOS truncates the string of "0"s from the right of the location id.
|
||||||
|
# Here, also, the final character is an appended "1", so if macOS ever stops doing that,
|
||||||
|
# this will need an update, as well.
|
||||||
|
if ($location_id =~ /0x(\d+?)0*\b/) {
|
||||||
|
my $loc = $1;
|
||||||
|
exit_with_port_if_exists("/dev/cu.usbmodem" . $loc . "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub try_for_sn_prefix {
|
||||||
|
my $sn = shift;
|
||||||
|
# If macOS has appended 'E', take it off to maximise our chances of a match.
|
||||||
|
$sn =~ s/E$//;
|
||||||
|
|
||||||
|
# If none of the above tests succeeds, just list the directory and see if there are any
|
||||||
|
# files that have the device shortname that we expect:
|
||||||
|
foreach my $line (qx(ls /dev/cu.usbmodem*)) {
|
||||||
|
if ($line =~ /${sn}/) {
|
||||||
|
chomp $line;
|
||||||
|
print $line;
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub exit_with_port_if_exists {
|
||||||
|
my $serial_port_name = shift;
|
||||||
|
|
||||||
|
if (-e $serial_port_name) {
|
||||||
|
print $serial_port_name;
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# > find-device-port-cygwin.ps1 '1209' '2300' -Format COM
|
||||||
|
# COM7
|
||||||
|
# > find-device-port-cygwin.ps1 '1209' '2300' -Format WSL
|
||||||
|
# /dev/ttyS7
|
||||||
|
# > find-device-port-cygwin.ps1 '1209' '2300' -Format Cygwin
|
||||||
|
# /dev/ttyS6
|
||||||
|
Param(
|
||||||
|
[string]$VendorID,
|
||||||
|
[string]$ProductID, # Careful; $PID is a different builtin
|
||||||
|
[ValidateSet('COM','Cygwin','WSL')][string]$Format
|
||||||
|
)
|
||||||
|
|
||||||
|
$DeviceParametersRegKey = @(Get-ChildItem -ErrorAction SilentlyContinue -Recurse 'HKLM:\SYSTEM\CurrentControlSet\Enum' |
|
||||||
|
Where-Object Name -match "VID_$VendorID&PID_$ProductID" |
|
||||||
|
Where-Object Property -eq PortName)
|
||||||
|
|
||||||
|
if ($DeviceParametersRegKey.Count -eq 0) {
|
||||||
|
throw "Could not find any devices matching VID $VendorID and PID $ProductID which were mapped to a COM port"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($DeviceParametersRegKey.Count -ge 2) {
|
||||||
|
throw "More than one devices matching VID $VendorID and PID $ProductID were found mapped to a COM port"
|
||||||
|
}
|
||||||
|
|
||||||
|
# This will be of form 'COM6'
|
||||||
|
$COMPortName = ($DeviceParametersRegKey | Get-ItemProperty).PortName
|
||||||
|
$COMPortNumber = [int]$COMPortName.Substring(3)
|
||||||
|
|
||||||
|
if ($Format -eq 'COM') {
|
||||||
|
$Output = $COMPortName
|
||||||
|
} elseif ($Format -eq 'WSL') {
|
||||||
|
$Output = "/dev/ttyS$COMPortNumber"
|
||||||
|
} elseif ($Format -eq 'Cygwin') {
|
||||||
|
$CygwinPortNumber = $COMPortNumber - 1
|
||||||
|
$Output = "/dev/ttyS$CygwinPortNumber"
|
||||||
|
}
|
||||||
|
|
||||||
|
# "-NoNewline" below is important to prevent bash from seeing an extra trailing '\r'
|
||||||
|
Write-Host -NoNewline $Output
|
@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# find-filename-conflicts - Finds cpp files with conflicting filenames
|
||||||
|
# Copyright (C) 2020 Keyboard.io, Inc.
|
||||||
|
#
|
||||||
|
# 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, version 3.
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
## When building Kaleidoscope, the compiled object files are linked together
|
||||||
|
## into a static archive. This static archive has a very simple structure, and
|
||||||
|
## only stores filenames, not paths, not even relative ones. As such, we can't
|
||||||
|
## have files with the same name, because they will conflict, and one will
|
||||||
|
## override the other.
|
||||||
|
##
|
||||||
|
## To avoid this situation, this script will find all cpp source files (we don't
|
||||||
|
## need to care about header-only things, those do not result in an object
|
||||||
|
## file), and will comb through them to find conflicting filenames.
|
||||||
|
##
|
||||||
|
## If a conflict is found, it will print all files that share the name, and will
|
||||||
|
## exit with an error at the end. It does not exit at the first duplicate, but
|
||||||
|
## will find and print all of them.
|
||||||
|
##
|
||||||
|
## If no conflict is found, the script just prints its status message and exits
|
||||||
|
## with zero.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
FILE_LIST="$(find src -name '*.cpp' | sed -e 's,\(\(.*\)/\([^/]*\)\),\3 \1,')"
|
||||||
|
|
||||||
|
exit_code=0
|
||||||
|
|
||||||
|
echo -n "Looking for conflicting filenames... "
|
||||||
|
|
||||||
|
for f in $(echo "${FILE_LIST}" | cut -f1 -d" "); do
|
||||||
|
count=$(echo "${FILE_LIST}" | grep -c "^${f}")
|
||||||
|
if [ "$count" -gt 1 ]; then
|
||||||
|
echo >&2
|
||||||
|
echo " Conflict found for ${f}: " >&2
|
||||||
|
echo "${FILE_LIST}" | grep "${f}" | cut -d" " -f2 | sed -e 's,^, ,' >&2
|
||||||
|
exit_code=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${exit_code}" -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit ${exit_code}
|
@ -1,96 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
|
||||||
|
|
||||||
# This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
# distribute this software, either in source code form or as a compiled
|
|
||||||
# binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
# means.
|
|
||||||
|
|
||||||
# In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
# of this software dedicate any and all copyright interest in the
|
|
||||||
# software to the public domain. We make this dedication for the benefit
|
|
||||||
# of the public at large and to the detriment of our heirs and
|
|
||||||
# successors. We intend this dedication to be an overt act of
|
|
||||||
# relinquishment in perpetuity of all present and future rights to this
|
|
||||||
# software under copyright law.
|
|
||||||
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
# For more information, please refer to <http://unlicense.org/>
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
"""When building Kaleidoscope, the compiled object files are linked together
|
|
||||||
into a static archive. This static archive has a very simple structure, and only
|
|
||||||
stores filenames, not paths, not even relative ones. As such, we can't have
|
|
||||||
files with the same name, because they will conflict, and one will override the
|
|
||||||
other.
|
|
||||||
|
|
||||||
To avoid this situation, this script will find all cpp source files (we don't
|
|
||||||
need to care about header-only things, those do not result in an object file),
|
|
||||||
and will comb through them to find conflicting filenames.
|
|
||||||
|
|
||||||
If a conflict is found, it will print all files that share the name, and will
|
|
||||||
exit with an error at the end. It does not exit at the first duplicate, but will
|
|
||||||
find and print all of them.
|
|
||||||
|
|
||||||
If no conflict is found, the script just prints its status message and exits
|
|
||||||
with zero."""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
cpp_regex = re.compile('.*\.cpp')
|
|
||||||
|
|
||||||
|
|
||||||
def find_duplicates(root):
|
|
||||||
"""Search for files with the same basename, but in different directories in
|
|
||||||
the tree under <root>. Prints a message for each conflict found, and
|
|
||||||
returns a count of the number of non-unique basenames."""
|
|
||||||
|
|
||||||
# Search the specified tree for matching basenames:
|
|
||||||
basenames = {}
|
|
||||||
for dir_path, dirs, files in os.walk(root):
|
|
||||||
for file_name in files:
|
|
||||||
if cpp_regex.match(file_name):
|
|
||||||
if file_name not in basenames:
|
|
||||||
basenames[file_name] = []
|
|
||||||
basenames[file_name].append(dir_path)
|
|
||||||
|
|
||||||
conflict_count = 0
|
|
||||||
for file_name, dirs in basenames.items():
|
|
||||||
# Prune unique basenames from the dict:
|
|
||||||
if len(dirs) <= 1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
conflict_count += 1
|
|
||||||
# Print info about basenames with conflicts:
|
|
||||||
print(f"Conflict found for file name '{file_name}':")
|
|
||||||
for root in dirs:
|
|
||||||
path = os.path.join(root, file_name)
|
|
||||||
print(f' -> {path}')
|
|
||||||
|
|
||||||
return conflict_count
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
print('Searching for conflicting filenames...')
|
|
||||||
exit_code = 0
|
|
||||||
for path in args:
|
|
||||||
exit_code += find_duplicates(path)
|
|
||||||
if exit_code != 0:
|
|
||||||
sys.exit(exit_code)
|
|
||||||
print('No filename conflicts found.')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main(sys.argv[1:])
|
|
@ -1,43 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# In case it hasn't been set, assume we're being run from the root of the local
|
|
||||||
# Kaleidoscope repository.
|
|
||||||
: "${KALEIDOSCOPE_DIR:=$(pwd)}"
|
|
||||||
|
|
||||||
# This variable is a git ref that should point to the current master branch of
|
|
||||||
# the primary Kaleidoscope repository. In most cases, this would be
|
|
||||||
# `origin/master`.
|
|
||||||
: "${KALEIDOSCOPE_MERGE_BASE:=origin/master}"
|
|
||||||
|
|
||||||
# Don't do anything if the working tree has unstaged changes, to avoid
|
|
||||||
# unintentional combining of contentful changes with formatting changes.
|
|
||||||
if ! git diff -z --exit-code --quiet; then
|
|
||||||
echo "Working tree has unstaged changes; aborting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run git-diff so we only run IWYU on files that differ from `master`. This
|
|
||||||
# isn't necessarily what we want, but if the current branch has been rebased, it
|
|
||||||
# shouldn't touch any extra files.
|
|
||||||
git diff -z --name-only "${KALEIDOSCOPE_MERGE_BASE}" -- src plugins \
|
|
||||||
| "${KALEIDOSCOPE_DIR}/bin/iwyu.py" -z -v
|
|
||||||
|
|
||||||
# After running it on Kaleidoscope source files, run it on the test simulator,
|
|
||||||
# which requires some additional include dirs.
|
|
||||||
git diff -z --name-only "${KALEIDOSCOPE_MERGE_BASE}" -- testing \
|
|
||||||
| "${KALEIDOSCOPE_DIR}/bin/iwyu.py" \
|
|
||||||
-z -v \
|
|
||||||
-I="${KALEIDOSCOPE_DIR}" \
|
|
||||||
-I="${KALEIDOSCOPE_DIR}/testing/googletest/googlemock/include" \
|
|
||||||
-I="${KALEIDOSCOPE_DIR}/testing/googletest/googletest/include"
|
|
||||||
|
|
||||||
# Always run clang-format after IWYU, because they have different indentation
|
|
||||||
# rules for comments added by IWYU.
|
|
||||||
git diff -z --name-only "${KALEIDOSCOPE_MERGE_BASE}" -- src plugins testing \
|
|
||||||
| "${KALEIDOSCOPE_DIR}/bin/format-code.py" \
|
|
||||||
-z -v \
|
|
||||||
--exclude-dir='testing/googletest' \
|
|
||||||
--exclude-file='generated-testcase.cpp' \
|
|
||||||
--force \
|
|
||||||
--check \
|
|
||||||
--verbose
|
|
@ -1,63 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# focus-send - Trivial Focus testing tool
|
|
||||||
# Copyright (C) 2018-2022 Keyboard.io, Inc.
|
|
||||||
#
|
|
||||||
# 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, version 3.
|
|
||||||
#
|
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
OS=$(uname -s)
|
|
||||||
|
|
||||||
# igncr absorbs CR from Focus CRLF line endings
|
|
||||||
# -echo is needed because raw doesn't turn it off on Linux
|
|
||||||
STTY_ARGS="9600 raw igncr -echo"
|
|
||||||
|
|
||||||
case ${OS} in
|
|
||||||
Linux)
|
|
||||||
DEVICE="${DEVICE:-/dev/ttyACM0}"
|
|
||||||
;;
|
|
||||||
Darwin)
|
|
||||||
# bash on macOS has a bug that randomly drops serial input
|
|
||||||
if [ -n "$BASH_VERSION" ] && [ -x /bin/dash ]; then
|
|
||||||
# Prevent loop in case someone exported it
|
|
||||||
export -n BASH_VERSION
|
|
||||||
exec /bin/dash "$0" "$@"
|
|
||||||
fi
|
|
||||||
DEVICE="${DEVICE:-/dev/cu.usbmodemCkbio01E}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Error Unknown OS : ${OS}" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Redirect prior to running stty, because macOS sometimes resets termios
|
|
||||||
# state upon last close of a terminal device.
|
|
||||||
exec < "${DEVICE}"
|
|
||||||
# shellcheck disable=SC2086 # intentional word splitting
|
|
||||||
stty $STTY_ARGS
|
|
||||||
|
|
||||||
read_reply () {
|
|
||||||
while read -r line; do
|
|
||||||
if [ "${line}" = "." ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
echo "${line}"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# Flush any invalid commands out of input buffer.
|
|
||||||
# This could happen after a failed upload.
|
|
||||||
echo ' ' > "${DEVICE}"
|
|
||||||
read_reply > /dev/null
|
|
||||||
echo "$@" >"${DEVICE}"
|
|
||||||
read_reply
|
|
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# focus-test - Trivial Focus testing tool
|
||||||
|
# Copyright (C) 2018 Keyboard.io, Inc.
|
||||||
|
#
|
||||||
|
# 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, version 3.
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OS=$(uname -s)
|
||||||
|
|
||||||
|
case ${OS} in
|
||||||
|
Linux)
|
||||||
|
DEVICE="${DEVICE:-/dev/ttyACM0}"
|
||||||
|
stty -F "${DEVICE}" 9600 raw -echo
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
DEVICE="${DEVICE:-/dev/cu.usbmodemCkbio01E}"
|
||||||
|
stty -f "${DEVICE}" 9600 raw -echo
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Error Unknown OS : ${OS}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
exec 3<"${DEVICE}"
|
||||||
|
echo "$@" >"${DEVICE}"
|
||||||
|
|
||||||
|
while read -r line <&3; do
|
||||||
|
line="$(echo -n "${line}" | tr -d '\r')"
|
||||||
|
if [ "${line}" == "." ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "${line}"
|
||||||
|
done
|
@ -1,275 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
|
||||||
|
|
||||||
# This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
# distribute this software, either in source code form or as a compiled
|
|
||||||
# binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
# means.
|
|
||||||
|
|
||||||
# In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
# of this software dedicate any and all copyright interest in the
|
|
||||||
# software to the public domain. We make this dedication for the benefit
|
|
||||||
# of the public at large and to the detriment of our heirs and
|
|
||||||
# successors. We intend this dedication to be an overt act of
|
|
||||||
# relinquishment in perpetuity of all present and future rights to this
|
|
||||||
# software under copyright law.
|
|
||||||
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
# For more information, please refer to <http://unlicense.org/>
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
"""This script runs clang-format on a Kaleidoscope repository."""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.dont_write_bytecode = True
|
|
||||||
|
|
||||||
from common import check_git_diff, setup_logging, split_on_newlines, split_on_nulls
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def parse_args(args):
|
|
||||||
"""Parse command line parameters
|
|
||||||
|
|
||||||
Args:
|
|
||||||
args (list[str]): command line parameters as list of strings
|
|
||||||
(for example ``["--help"]``).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`argparse.Namespace`: command line parameters namespace
|
|
||||||
"""
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="""
|
|
||||||
Recursively search specified directories and format source files with
|
|
||||||
clang-format. By default, it operates on Arduino C++ source files with
|
|
||||||
extensions: *.{cpp,h,hpp,inc,ino}.""")
|
|
||||||
parser.add_argument(
|
|
||||||
'-q',
|
|
||||||
'--quiet',
|
|
||||||
dest='loglevel',
|
|
||||||
action='store_const',
|
|
||||||
const=logging.ERROR,
|
|
||||||
default=logging.WARNING,
|
|
||||||
help="""
|
|
||||||
Suppress output except warnings and errors.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-v',
|
|
||||||
'--verbose',
|
|
||||||
action='store_const',
|
|
||||||
dest='loglevel',
|
|
||||||
const=logging.INFO,
|
|
||||||
help="""
|
|
||||||
Output verbose debugging information.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-d',
|
|
||||||
'--debug',
|
|
||||||
action='store_const',
|
|
||||||
dest='loglevel',
|
|
||||||
const=logging.DEBUG,
|
|
||||||
help="""
|
|
||||||
Save output from `include-what-you-use` for processed files beside the originals, with
|
|
||||||
a '.iwyu' suffix, for debugging purposes.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-X',
|
|
||||||
'--exclude-dir',
|
|
||||||
action='append',
|
|
||||||
dest='exclude_dirs',
|
|
||||||
default=[],
|
|
||||||
metavar="<path>",
|
|
||||||
help="""
|
|
||||||
Exclude dir from search (path relative to the pwd)""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-x',
|
|
||||||
'--exclude-file',
|
|
||||||
action='append',
|
|
||||||
dest='exclude_files',
|
|
||||||
default=[],
|
|
||||||
metavar="<file>",
|
|
||||||
help="""
|
|
||||||
Exclude <file> (base name only, not a full path) from formatting""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-r',
|
|
||||||
'--regex',
|
|
||||||
dest='regex',
|
|
||||||
default=r'\.(cpp|h|hpp|inc|ino)$',
|
|
||||||
metavar="<regex>",
|
|
||||||
help="""
|
|
||||||
Regular expression for matching source file names""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-z',
|
|
||||||
'-0',
|
|
||||||
action='store_const',
|
|
||||||
dest='input_splitter',
|
|
||||||
const=split_on_nulls,
|
|
||||||
default=split_on_newlines,
|
|
||||||
help="""
|
|
||||||
When reading target filenames from standard input, break on NULL characters instead
|
|
||||||
of newlines.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-f',
|
|
||||||
'--force',
|
|
||||||
action='store_true',
|
|
||||||
help="""
|
|
||||||
Format code even if there are unstaged changes""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'--check',
|
|
||||||
action='store_true',
|
|
||||||
help="""
|
|
||||||
Check for changes after formatting by running `git diff --exit-code`. If there are any
|
|
||||||
changes after formatting, a non-zero exit code is returned.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'targets',
|
|
||||||
metavar="<search_dir>",
|
|
||||||
nargs='*',
|
|
||||||
help="""
|
|
||||||
A list of files and/or directories to search for source files to format.""",
|
|
||||||
)
|
|
||||||
return parser.parse_args(args)
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def main():
|
|
||||||
"""Parse command-line arguments and format source files.
|
|
||||||
"""
|
|
||||||
# Parse command-line argumets:
|
|
||||||
opts = parse_args(sys.argv[1:])
|
|
||||||
# Set up logging system:
|
|
||||||
setup_logging(opts.loglevel)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Unless we've been given the `--force` option, check for unstaged changes to avoid
|
|
||||||
# clobbering any work in progress:
|
|
||||||
exit_code = 0
|
|
||||||
if not opts.force:
|
|
||||||
changed_files = check_git_diff()
|
|
||||||
if len(changed_files) > 0:
|
|
||||||
logging.error("Working tree has unstaged changes; aborting")
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# Locate `clang-format` executable:
|
|
||||||
clang_format_exe = os.getenv('KALEIDOSCOPE_CODE_FORMATTER')
|
|
||||||
if clang_format_exe is None:
|
|
||||||
clang_format_exe = shutil.which('clang-format')
|
|
||||||
logging.debug("Found `clang-format` executable: %s", clang_format_exe)
|
|
||||||
clang_format_cmd = [clang_format_exe, '-i']
|
|
||||||
if opts.loglevel <= logging.INFO:
|
|
||||||
clang_format_cmd.append('--verbose')
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Read targets from command line:
|
|
||||||
targets = opts.targets
|
|
||||||
logging.debug("CLI target parameters: %s", targets)
|
|
||||||
|
|
||||||
# If stdin is a pipe, read target filenames from it:
|
|
||||||
if not sys.stdin.isatty():
|
|
||||||
targets += opts.input_splitter(sys.stdin.read())
|
|
||||||
logging.debug("All targets: %s", targets)
|
|
||||||
|
|
||||||
# Prepare exclusion lists. The file excludes are basenames only, and the dirs get
|
|
||||||
# converted to absolute path names.
|
|
||||||
exclude_files = set(opts.exclude_files)
|
|
||||||
exclude_dirs = set(os.path.abspath(_) for _ in opts.exclude_dirs)
|
|
||||||
|
|
||||||
# Convert target paths to absolute, and remove any that are excluded:
|
|
||||||
target_paths = set(os.path.abspath(_) for _ in targets if _ not in exclude_dirs)
|
|
||||||
logging.debug("Target paths: %s", target_paths)
|
|
||||||
|
|
||||||
# Build separate sets of target files and dirs. Later, we'll search target dirs and add
|
|
||||||
# matching target files to the files set.
|
|
||||||
target_files = set()
|
|
||||||
target_dirs = set()
|
|
||||||
for t in target_paths:
|
|
||||||
if os.path.isfile(t):
|
|
||||||
target_files.add(os.path.abspath(t))
|
|
||||||
elif os.path.isdir(t):
|
|
||||||
target_dirs.add(os.path.abspath(t))
|
|
||||||
logging.debug("Target files after separating: %s", target_files)
|
|
||||||
logging.debug("Target dirs after separating: %s", target_dirs)
|
|
||||||
|
|
||||||
# Remove excluded filenames:
|
|
||||||
target_files -= set(_ for _ in target_files if os.path.basename(_) in exclude_files)
|
|
||||||
|
|
||||||
# Remove files and dirs in excluded dirs:
|
|
||||||
target_files -= set(_ for _ in target_files for x in exclude_dirs if _.startswith(x))
|
|
||||||
target_dirs -= set(_ for _ in target_dirs for x in exclude_dirs if _.startswith(x))
|
|
||||||
|
|
||||||
# Compile regex for matching files to be formatted:
|
|
||||||
target_matcher = re.compile(opts.regex)
|
|
||||||
|
|
||||||
# Remove target files that don't match the regex:
|
|
||||||
logging.debug("Target files before matching regex: %s", target_files)
|
|
||||||
target_files = set(_ for _ in target_files if target_matcher.search(_))
|
|
||||||
logging.debug("Target files after matching regex: %s", target_files)
|
|
||||||
|
|
||||||
# Search target dirs for non-excluded files, and add them to `target_files`:
|
|
||||||
logging.debug("Searching target dirs: %s", target_dirs)
|
|
||||||
for path in target_dirs:
|
|
||||||
for root, dirs, files in os.walk(path):
|
|
||||||
# Prune excluded dirs
|
|
||||||
for x in exclude_dirs:
|
|
||||||
if x in (os.path.join(root, _) for _ in dirs):
|
|
||||||
dirs.remove(os.path.basename(x))
|
|
||||||
# Add non-excluded files
|
|
||||||
for f in files:
|
|
||||||
if target_matcher.search(f) and f not in exclude_files:
|
|
||||||
target_files.add(os.path.join(root, f))
|
|
||||||
|
|
||||||
if len(target_files) == 0:
|
|
||||||
logging.error("No target files found; exiting.")
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# Run clang-format on target files:
|
|
||||||
proc = subprocess.run(clang_format_cmd + sorted(target_files))
|
|
||||||
if proc.returncode != 0:
|
|
||||||
logging.error("Error: clang-format returned non-zero status: %s", proc.returncode)
|
|
||||||
return proc.returncode
|
|
||||||
else:
|
|
||||||
logging.info("Finished formatting target files.")
|
|
||||||
|
|
||||||
# If we've been asked to check for changes made by the formatter:
|
|
||||||
if opts.check:
|
|
||||||
logging.warning('Checking for changes made by the formatter...')
|
|
||||||
changed_files = check_git_diff()
|
|
||||||
if len(changed_files) == 0:
|
|
||||||
logging.warning("No files changed. Congratulations!")
|
|
||||||
else:
|
|
||||||
logging.warning("Found files with changes after formatting:")
|
|
||||||
exit_code = 1
|
|
||||||
for f in changed_files:
|
|
||||||
logging.warning(" %s", f)
|
|
||||||
|
|
||||||
return exit_code
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
sys.exit(main())
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
logging.info("Aborting")
|
|
||||||
sys.exit(1)
|
|
@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
: "${KALEIDOSCOPE_DIR:=$(pwd)}"
|
|
||||||
cd "${KALEIDOSCOPE_DIR}" || exit 1
|
|
||||||
|
|
||||||
: "${VERBOSE:=}"
|
|
||||||
|
|
||||||
"${KALEIDOSCOPE_DIR}/bin/format-code.py" \
|
|
||||||
--exclude-dir 'testing/googletest' \
|
|
||||||
--exclude-file 'generated-testcase.cpp' \
|
|
||||||
--verbose \
|
|
||||||
src plugins testing
|
|
@ -1,508 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Copyright (c) 2022 Michael Richters <gedankenexperimenter@gmail.com>
|
|
||||||
|
|
||||||
# This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
# distribute this software, either in source code form or as a compiled
|
|
||||||
# binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
# means.
|
|
||||||
|
|
||||||
# In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
# of this software dedicate any and all copyright interest in the
|
|
||||||
# software to the public domain. We make this dedication for the benefit
|
|
||||||
# of the public at large and to the detriment of our heirs and
|
|
||||||
# successors. We intend this dedication to be an overt act of
|
|
||||||
# relinquishment in perpetuity of all present and future rights to this
|
|
||||||
# software under copyright law.
|
|
||||||
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
# For more information, please refer to <http://unlicense.org/>
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
"""Run `include-what-you-use` on Kaleidoscope sources
|
|
||||||
|
|
||||||
This is a script for maintenance of the headers included in Kaleidoscope source
|
|
||||||
files. It is not currently possible to run this automatically on all
|
|
||||||
Kaleidoscope source files, because of the peculiarities therein. It uses
|
|
||||||
llvm/clang to determine which headers should be included in a given file, but
|
|
||||||
there's no avr-clang, so we're limited to using the virtual hardware device.
|
|
||||||
|
|
||||||
It takes any number of source files as its input, examines them and updates the
|
|
||||||
list of header `#include` directives.
|
|
||||||
|
|
||||||
It is safe to run on most Kaleidoscope source files, and a good idea to run it
|
|
||||||
on new ones (after staging them, so you can easily see what changes have been
|
|
||||||
made).
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Example invocation:
|
|
||||||
# $ git ls-files -m | grep '\.\(h\|cpp\)' | bin/iwyu.py
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shlex
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.dont_write_bytecode = True
|
|
||||||
|
|
||||||
from common import cwd, setup_logging, split_on_newlines, split_on_nulls
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def parse_args(args):
|
|
||||||
"""Parse command line parameters
|
|
||||||
|
|
||||||
Args:
|
|
||||||
args (list[str]): command line parameters as list of strings
|
|
||||||
(for example ``["--help"]``).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`argparse.Namespace`: command line parameters namespace
|
|
||||||
"""
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="""
|
|
||||||
Run `include-what-you-use` on source files given as command-line arguments and/or read
|
|
||||||
from standard input. When reading target filenames from standard input, they should be
|
|
||||||
either absolute or relative to the current directory, and each line of input (minus the
|
|
||||||
line-ending character(s) is treated as a filename.""")
|
|
||||||
parser.add_argument(
|
|
||||||
'-q',
|
|
||||||
'--quiet',
|
|
||||||
dest='loglevel',
|
|
||||||
action='store_const',
|
|
||||||
const=logging.ERROR,
|
|
||||||
default=logging.WARNING,
|
|
||||||
help="""
|
|
||||||
Suppress output except warnings and errors.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-v',
|
|
||||||
'--verbose',
|
|
||||||
action='store_const',
|
|
||||||
dest='loglevel',
|
|
||||||
const=logging.INFO,
|
|
||||||
help="""
|
|
||||||
Output verbose debugging information.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-d',
|
|
||||||
'--debug',
|
|
||||||
action='store_const',
|
|
||||||
dest='loglevel',
|
|
||||||
const=logging.DEBUG,
|
|
||||||
help="""
|
|
||||||
Save output from `include-what-you-use` for processed files beside the originals, with
|
|
||||||
a '.iwyu' suffix, for debugging purposes.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-r',
|
|
||||||
'--regex',
|
|
||||||
action='store',
|
|
||||||
dest='regex',
|
|
||||||
default=r'\.(h|cpp)$',
|
|
||||||
help="""
|
|
||||||
A regular expression for matching filenames Only the basename of the file is
|
|
||||||
matched, and the regex is only used when searching a directory for files to process,
|
|
||||||
not on target filenames specified in arguments or read from standard input.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-i',
|
|
||||||
'--ignores_file',
|
|
||||||
action='store',
|
|
||||||
dest='ignores_file',
|
|
||||||
default='.iwyu_ignore',
|
|
||||||
metavar='<ignores_file>',
|
|
||||||
help="""
|
|
||||||
The name of a file (relative to KALEIDOSCOPE_DIR) that contains a list of glob patterns
|
|
||||||
that will be ignored when a target directory is searched for filenames that match
|
|
||||||
<regex>.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-I',
|
|
||||||
'--include',
|
|
||||||
action='append',
|
|
||||||
dest='include_dirs',
|
|
||||||
metavar='<dir>',
|
|
||||||
help="""
|
|
||||||
Add <dir> to the list of directories that will be searched for header files.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-z',
|
|
||||||
'-0',
|
|
||||||
action='store_const',
|
|
||||||
dest='input_splitter',
|
|
||||||
const=split_on_nulls,
|
|
||||||
default=split_on_newlines,
|
|
||||||
help="""
|
|
||||||
When reading target filenames from standard input, break on NULL characters instead
|
|
||||||
of newlines.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'--update_comments',
|
|
||||||
action='store_true',
|
|
||||||
help="""
|
|
||||||
Call `include-what-you-use` with `--update_comments` to always rewrite its 'for'
|
|
||||||
comments regarding which symbols are used.""",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'targets',
|
|
||||||
nargs='*',
|
|
||||||
metavar="<target>",
|
|
||||||
help="""
|
|
||||||
A list of target files and/or directories to search for source files to format. Any
|
|
||||||
target file will be processed, regardless of the filename. Any target directory will
|
|
||||||
be recursively searched for files matching the regular expression given by --regex.
|
|
||||||
Filenames and directories beginning with a '.' will always be excluded from the search,
|
|
||||||
but can still be processed if specified as a command-line target.""",
|
|
||||||
)
|
|
||||||
return parser.parse_args(args)
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def main():
|
|
||||||
"""Main entry point function."""
|
|
||||||
# Parse command-line arguments:
|
|
||||||
opts = parse_args(sys.argv[1:])
|
|
||||||
# Set up logging system:
|
|
||||||
setup_logging(opts.loglevel)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Find include-what-you-use:
|
|
||||||
iwyu = shutil.which('include-what-you-use')
|
|
||||||
logging.debug("Found `include-what-you-use` executable: %s", iwyu)
|
|
||||||
iwyu_opts = [
|
|
||||||
'--no_fwd_decls', # No forward declarations
|
|
||||||
'--max_line_length=100',
|
|
||||||
]
|
|
||||||
if opts.update_comments:
|
|
||||||
iwyu_opts.append('--update_comments')
|
|
||||||
# Prepend '-Xiwyu' to each `include-what-you-use` option:
|
|
||||||
iwyu_opts = [_ for opt in iwyu_opts for _ in ('-Xiwyu', opt)]
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Find fix_includes:
|
|
||||||
fix_includes = shutil.which('fix_includes.py')
|
|
||||||
logging.debug("Found `fix_includes` executable: %s", fix_includes)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Find clang (first checking environment variable):
|
|
||||||
clang = os.getenv('CLANG_COMPILER')
|
|
||||||
if clang is None:
|
|
||||||
clang = shutil.which('clang')
|
|
||||||
logging.debug("Found `clang` executable: %s", clang)
|
|
||||||
|
|
||||||
# Get system include dir from `clang`:
|
|
||||||
clang_cmd = [clang, '-print-resource-dir']
|
|
||||||
logging.debug("Running command: `%s`", shlex.join(clang_cmd))
|
|
||||||
result = subprocess.run(clang_cmd, capture_output=True, check=True)
|
|
||||||
clang_resource_dir = result.stdout.decode('utf-8').rstrip()
|
|
||||||
system_include_dir = os.path.join(clang_resource_dir, 'include')
|
|
||||||
logging.debug("Using system include dir: %s", system_include_dir)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Get $KALEIDOSCOPE_DIR from enironment, falling back on `pwd`:
|
|
||||||
kaleidoscope_dir = os.getenv('KALEIDOSCOPE_DIR')
|
|
||||||
if kaleidoscope_dir is None:
|
|
||||||
kaleidoscope_dir = os.getcwd()
|
|
||||||
logging.debug("Using Kaleidoscope dir: %s", kaleidoscope_dir)
|
|
||||||
kaleidoscope_src_dir = os.path.join(kaleidoscope_dir, 'src')
|
|
||||||
|
|
||||||
# Define locations of other dirs to find Arduino libraries:
|
|
||||||
virtual_hardware_dir = os.path.join(
|
|
||||||
kaleidoscope_dir, '.arduino', 'user', 'hardware', 'keyboardio', 'virtual')
|
|
||||||
logging.debug("Using virtual hardware dir: %s", virtual_hardware_dir)
|
|
||||||
|
|
||||||
virtual_arduino_core_dir = os.path.join(virtual_hardware_dir, 'cores', 'arduino')
|
|
||||||
logging.debug("Using virtual arduino core: %s", virtual_arduino_core_dir)
|
|
||||||
|
|
||||||
virtual_model01_dir = os.path.join(virtual_hardware_dir, 'variants', 'model01')
|
|
||||||
logging.debug("Using virtual Model01 dir: %s", virtual_model01_dir)
|
|
||||||
|
|
||||||
virtual_keyboardiohid_dir = os.path.join(
|
|
||||||
virtual_hardware_dir, 'libraries', 'KeyboardioHID', 'src')
|
|
||||||
logging.debug("Using virtual KeyboardioHID dir: %s", virtual_keyboardiohid_dir)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Create the long list of options passed to `clang` via `include-what-you-use`.
|
|
||||||
# First, we tell it we're using C++:
|
|
||||||
clang_opts = ['-x', 'c++']
|
|
||||||
# General compiler options:
|
|
||||||
clang_opts += [
|
|
||||||
'-c',
|
|
||||||
'-g',
|
|
||||||
'-Wall',
|
|
||||||
'-Wextra',
|
|
||||||
'-std=gnu++14', # Not `c++14`, because we're using clang, not gcc
|
|
||||||
'-ffunction-sections',
|
|
||||||
'-fdata-sections',
|
|
||||||
'-fno-threadsafe-statics',
|
|
||||||
'-MMD',
|
|
||||||
'-Woverloaded-virtual',
|
|
||||||
'-Wno-unused-parameter',
|
|
||||||
'-Wno-unused-variable',
|
|
||||||
'-Wno-ignored-qualifiers',
|
|
||||||
'-Wno-type-limits',
|
|
||||||
'-Wno-pragma-once-outside-header',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Variables we define to do a Kaleidoscope build:
|
|
||||||
defines = [
|
|
||||||
'KALEIDOSCOPE_VIRTUAL_BUILD=1',
|
|
||||||
'KEYBOARDIOHID_BUILD_WITHOUT_HID=1',
|
|
||||||
'USBCON=dummy',
|
|
||||||
'ARDUINO_ARCH_AVR=1',
|
|
||||||
'ARDUINO=10607',
|
|
||||||
'ARDUINO_AVR_MODEL01',
|
|
||||||
'ARDUINO_ARCH_VIRTUAL',
|
|
||||||
'USB_VID=0x1209',
|
|
||||||
'USB_PID=0x2301',
|
|
||||||
'USB_MANUFACTURER="Keyboardio"',
|
|
||||||
'USB_PRODUCT="Model 01"',
|
|
||||||
'KALEIDOSCOPE_HARDWARE_H="Kaleidoscope-Hardware-Keyboardio-Model01.h"',
|
|
||||||
'TWI_BUFFER_LENGTH=32',
|
|
||||||
]
|
|
||||||
clang_opts += ['-D' + _ for _ in defines]
|
|
||||||
|
|
||||||
# Directories to search for libraries to include:
|
|
||||||
includes = [
|
|
||||||
system_include_dir,
|
|
||||||
kaleidoscope_src_dir,
|
|
||||||
virtual_arduino_core_dir,
|
|
||||||
virtual_model01_dir,
|
|
||||||
virtual_keyboardiohid_dir,
|
|
||||||
]
|
|
||||||
# Include plugin source dirs for plugins that depend on other plugins:
|
|
||||||
includes += glob.glob(os.path.join(kaleidoscope_dir, 'plugins', '*', 'src'))
|
|
||||||
# Include dirs specified on the command line, if any:
|
|
||||||
if opts.include_dirs:
|
|
||||||
includes += [os.path.abspath(_) for _ in opts.include_dirs]
|
|
||||||
clang_opts += ['-I' + _ for _ in includes]
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Define the `include-what-you-use` command (sans target files)
|
|
||||||
iwyu_cmd = [iwyu] + iwyu_opts + clang_opts
|
|
||||||
logging.debug("Using IWYU command: %s", ' \\\n\t'.join(iwyu_cmd))
|
|
||||||
|
|
||||||
fix_includes_cmd = [
|
|
||||||
fix_includes,
|
|
||||||
'--nosafe_headers',
|
|
||||||
'--reorder',
|
|
||||||
'--separate_project_includes=' + kaleidoscope_src_dir, # Does this help?
|
|
||||||
]
|
|
||||||
if opts.update_comments:
|
|
||||||
fix_includes_cmd.append('--update_comments')
|
|
||||||
logging.debug("Using `fix_includes` command: %s", ' \\\n\t'.join(fix_includes_cmd))
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
targets = opts.targets
|
|
||||||
# If stdin is a pipe, read pathname targets, one per line. This allows us to connect the
|
|
||||||
# output of `find` to our input conveniently:
|
|
||||||
if not sys.stdin.isatty():
|
|
||||||
logging.debug("Reading targets from STDIN...")
|
|
||||||
targets += opts.input_splitter(sys.stdin.read())
|
|
||||||
for t in targets:
|
|
||||||
logging.debug(" Target path: %s", t)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
iwyu_ignores_file = os.path.join(kaleidoscope_dir, opts.ignores_file)
|
|
||||||
ignores = build_ignores_list(iwyu_ignores_file)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
regex = re.compile(opts.regex)
|
|
||||||
# Process source files first, then header files, because a source file might have been
|
|
||||||
# relying on a header included by its associated header, but which that header does not
|
|
||||||
# need on its own. In this case, if we process the header first, IWYU won't be able to
|
|
||||||
# parse the source file, and we'll get an error, but if we do them in the other order,
|
|
||||||
# the source file will get all the includes it needs before the header removes any of them.
|
|
||||||
source_files = []
|
|
||||||
header_files = []
|
|
||||||
for target_file in (_ for t in targets for _ in build_target_list(t, regex, ignores)):
|
|
||||||
if target_file.endswith('.cpp') or target_file.endswith('.ino'):
|
|
||||||
source_files.append(target_file)
|
|
||||||
else:
|
|
||||||
header_files.append(target_file)
|
|
||||||
|
|
||||||
# If there's an error processing any file, return an error code.
|
|
||||||
exit_code = 0
|
|
||||||
for target_file in source_files + header_files:
|
|
||||||
# Run IWYU and fix_headers:
|
|
||||||
if not run_iwyu(os.path.relpath(target_file), iwyu_cmd, fix_includes_cmd):
|
|
||||||
exit_code = 1
|
|
||||||
|
|
||||||
return exit_code
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def build_target_list(target, regex, ignores):
|
|
||||||
"""Build the list of target files, starting from a file or directory.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
target (str): The name of the file or directory to search
|
|
||||||
regex (Pattern): A compiled regular expression to match target file names
|
|
||||||
ignores (list): A list of (absolute) file names to be excluded from the target list
|
|
||||||
Returns:
|
|
||||||
targets (list): A list of (absolute) file names to be processed
|
|
||||||
|
|
||||||
Given a filename or directory (`path`), returns a list of target filenames to run IWYU
|
|
||||||
on. Target filenames will all be absolute, but `path` can be relative to the current
|
|
||||||
directory. All target filenames will match `regex`, and any items in `ignores` will be
|
|
||||||
excluded. If an element of the `ignores` list is a directory, all files and directories
|
|
||||||
beneath it will be excluded from the search.
|
|
||||||
"""
|
|
||||||
logging.debug("Searching target: %s", target)
|
|
||||||
|
|
||||||
# Convert all paths to absolute.
|
|
||||||
root = os.path.abspath(target)
|
|
||||||
|
|
||||||
# If `path` is a file, and it matches `regex`, add it to the target list.
|
|
||||||
if os.path.isfile(target) and regex.search(target) and root not in ignores:
|
|
||||||
return [root]
|
|
||||||
|
|
||||||
# If the specified path is not valid, just return an empty list.
|
|
||||||
if not os.path.isdir(target):
|
|
||||||
logging.error("Error: File not found: %s", target)
|
|
||||||
return []
|
|
||||||
|
|
||||||
# Start with an empty list.
|
|
||||||
targets = []
|
|
||||||
|
|
||||||
# The specified path is a directory, so we search recursively for files
|
|
||||||
# contained therein that match the specified regular expression.
|
|
||||||
for path, dirs, files in os.walk(root):
|
|
||||||
logging.debug("Searching dir: %s", os.path.relpath(path))
|
|
||||||
# First, ignore all dotfiles (and directories).
|
|
||||||
for x in (os.path.basename(_)
|
|
||||||
for _ in ignores + glob.glob(os.path.join(path, '.*'))
|
|
||||||
if os.path.dirname(_) == path):
|
|
||||||
if x in dirs:
|
|
||||||
logging.info("Skipping ignored dir: %s", os.path.join(path, x))
|
|
||||||
dirs.remove(x)
|
|
||||||
if x in files:
|
|
||||||
logging.info("Skipping ignored file: %s", os.path.join(path, x))
|
|
||||||
files.remove(x)
|
|
||||||
|
|
||||||
logging.debug("Files found: %s", ', '.join(files))
|
|
||||||
# Add all matching files to the list of source files to be formatted.
|
|
||||||
for f in (_ for _ in files if regex.search(_)):
|
|
||||||
t = os.path.join(path, f)
|
|
||||||
logging.debug("Source file found: %s", t)
|
|
||||||
targets.append(t)
|
|
||||||
|
|
||||||
return targets
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def build_ignores_list(ignores_file_path):
|
|
||||||
"""Build a list of files and dirs to exclude from processing by IWYU
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
ignores_file_path (str): The name of the file to read ignores globs from
|
|
||||||
Returns:
|
|
||||||
ignores_list (list): A list of (absolute) file names to exclude from processing
|
|
||||||
|
|
||||||
Reads `ignores_file` and expands each line as a glob, returning a list of all the target
|
|
||||||
file names to be excluded from processing. Each path in the file is treated as a relative
|
|
||||||
pathname (unless it is already absolute), relative to the directory in which `ignores_file`
|
|
||||||
is located.
|
|
||||||
"""
|
|
||||||
logging.debug("Searching for ignores file: %s", ignores_file_path)
|
|
||||||
# If the ignores file doesn't exist, return an empty list:
|
|
||||||
if not os.path.isfile(ignores_file_path):
|
|
||||||
logging.debug("Ignores file not found")
|
|
||||||
return []
|
|
||||||
|
|
||||||
ignores_list = []
|
|
||||||
with open(ignores_file_path) as f:
|
|
||||||
for line in f.read().splitlines():
|
|
||||||
# Lines starting with `#` are treated as comments.
|
|
||||||
if line.startswith('#'):
|
|
||||||
continue
|
|
||||||
logging.debug("Ignoring files like: %s", line)
|
|
||||||
ignores_list += glob.glob(line, recursive=True)
|
|
||||||
|
|
||||||
# Get the dir of the ignores file so we can construct absolute pathnames.
|
|
||||||
ignores_file_dir = os.path.dirname(ignores_file_path)
|
|
||||||
with cwd(ignores_file_dir):
|
|
||||||
ignores_list[:] = [os.path.abspath(_) for _ in ignores_list]
|
|
||||||
|
|
||||||
logging.debug("Ignores list:\n\t%s", "\n\t".join(ignores_list))
|
|
||||||
return ignores_list
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
def run_iwyu(source_file, iwyu_cmd, fix_includes_cmd):
|
|
||||||
"""Run IWYU and fix_includes on a single source file
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
source_file (str): The name of a file to run IWYU on
|
|
||||||
iwyu_cmd (list): The command name and options list for `include-what-you-use`
|
|
||||||
fix_includes_cmd (list): The command name and options list for `fix_headers.py`
|
|
||||||
Returns:
|
|
||||||
True on success, False if either IWYU or fix_headers returns an error code
|
|
||||||
|
|
||||||
Run `include-what-you-use` on <source_file>, an update that file's header includes by
|
|
||||||
sending the output to `fix_includes.py`. If either command returns an error code, return
|
|
||||||
`False`, otherwise return `True`.
|
|
||||||
"""
|
|
||||||
logging.info("Fixing headers in file: %s", source_file)
|
|
||||||
|
|
||||||
# Run IWYU on <source_file>
|
|
||||||
iwyu_proc = subprocess.run(iwyu_cmd + [source_file], capture_output=True, check=False)
|
|
||||||
|
|
||||||
# If IWYU returns an error, report on it:
|
|
||||||
if iwyu_proc.returncode != 0:
|
|
||||||
logging.error("Error: failed to parse file: %s", source_file)
|
|
||||||
logging.debug("IWYU returned: %s", iwyu_proc.returncode)
|
|
||||||
logging.debug("STDOUT:\n%s", iwyu_proc.stdout.decode('utf-8'))
|
|
||||||
logging.debug("STDERR:\n%s", iwyu_proc.stderr.decode('utf-8'))
|
|
||||||
# In addition to reporting the error, save the output for analysis:
|
|
||||||
with open(source_file + '.iwyu', 'wb') as f:
|
|
||||||
f.write(iwyu_proc.stderr)
|
|
||||||
# Don't run fix_includes if there was an error (or if we've got an old version of IWYU
|
|
||||||
# that returns bogus exit codes):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# IWYU reports on the associated header of *.cpp files, but if we want to skip processing
|
|
||||||
# that header, we need to use only the part of the output for the *.cpp file. Fortunately,
|
|
||||||
# the header is listed first, so we only need to search for the start of the target file's
|
|
||||||
# section of the output.
|
|
||||||
n = iwyu_proc.stderr.find(f"\n{source_file} should".encode('utf-8'))
|
|
||||||
iwyu_stderr = iwyu_proc.stderr[n:]
|
|
||||||
|
|
||||||
# Run fix_includes.py, using the output (stderr) of IWYU:
|
|
||||||
fix_includes_proc = subprocess.run(
|
|
||||||
fix_includes_cmd, input=iwyu_stderr, capture_output=True, check=False)
|
|
||||||
|
|
||||||
# Report any errors returned by fix_includes.py:
|
|
||||||
if fix_includes_proc.returncode != 0:
|
|
||||||
logging.error("Error: failed to fix includes for file: %s", source_file)
|
|
||||||
logging.debug("fix_includes.py returned: %s", fix_includes_proc.returncode)
|
|
||||||
logging.debug("STDOUT:\n%s", fix_includes_proc.stdout.decode('utf-8'))
|
|
||||||
logging.debug("STDERR:\n%s", fix_includes_proc.stderr.decode('utf-8'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Return true on success, false otherwise:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
sys.exit(main())
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
logging.info("Aborting")
|
|
||||||
sys.exit(1)
|
|
@ -0,0 +1,738 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# kaleidoscope-builder - Kaleidoscope helper tool
|
||||||
|
# Copyright (C) 2017-2018 Keyboard.io, Inc.
|
||||||
|
#
|
||||||
|
# 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, version 3.
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
######
|
||||||
|
###### Build and output configuration
|
||||||
|
######
|
||||||
|
|
||||||
|
absolute_filename() {
|
||||||
|
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_version () {
|
||||||
|
: "${LIB_PROPERTIES_PATH:="../.."}"
|
||||||
|
GIT_VERSION="$(cd "${SKETCH_DIR}"; if [ -d .git ]; then echo -n '-g' && git describe --abbrev=4 --dirty --always; fi)"
|
||||||
|
LIB_VERSION="$(cd "${SKETCH_DIR}"; (grep version= "${LIB_PROPERTIES_PATH}/library.properties" 2>/dev/null || echo version=0.0.0) | cut -d= -f2)${GIT_VERSION}"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_paths() {
|
||||||
|
# We need that echo because we\re piping to cksum
|
||||||
|
# shellcheck disable=SC2005
|
||||||
|
SKETCH_IDENTIFIER="$(echo "${SKETCH_FILE_PATH}" | cksum | cut -d ' ' -f 1)-${SKETCH_FILE_NAME}"
|
||||||
|
: "${KALEIDOSCOPE_TEMP_PATH:=${TMPDIR:-/tmp}/kaleidoscope-${USER}}"
|
||||||
|
|
||||||
|
: "${KALEIDOSCOPE_BUILD_PATH:=${KALEIDOSCOPE_TEMP_PATH}/sketch}"
|
||||||
|
: "${KALEIDOSCOPE_OUTPUT_PATH:=${KALEIDOSCOPE_TEMP_PATH}/sketch}"
|
||||||
|
|
||||||
|
: "${SKETCH_OUTPUT_DIR:=${SKETCH_IDENTIFIER}/output}"
|
||||||
|
: "${SKETCH_BUILD_DIR:=${SKETCH_IDENTIFIER}/build}"
|
||||||
|
|
||||||
|
: "${BUILD_PATH:=${KALEIDOSCOPE_BUILD_PATH}/${SKETCH_BUILD_DIR}}"
|
||||||
|
: "${OUTPUT_PATH:=${KALEIDOSCOPE_OUTPUT_PATH}/${SKETCH_OUTPUT_DIR}}"
|
||||||
|
|
||||||
|
: "${CCACHE_WRAPPER_PATH:=${KALEIDOSCOPE_TEMP_PATH}/ccache/bin}"
|
||||||
|
: "${CORE_CACHE_PATH:=${KALEIDOSCOPE_TEMP_PATH}/arduino-cores}"
|
||||||
|
|
||||||
|
mkdir -p "$CORE_CACHE_PATH"
|
||||||
|
mkdir -p "$BUILD_PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_filenames () {
|
||||||
|
: "${OUTPUT_FILE_PREFIX:=${SKETCH_BASE_NAME}-${LIB_VERSION}}"
|
||||||
|
: "${HEX_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.hex}"
|
||||||
|
: "${HEX_FILE_WITH_BOOTLOADER_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}-with-bootloader.hex}"
|
||||||
|
: "${ELF_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.elf}"
|
||||||
|
: "${LIB_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.a}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enable_ccache () {
|
||||||
|
if [ -z "${CCACHE_NOT_SUPPORTED}" ] && [ "$(command -v ccache)" ]; then
|
||||||
|
if ! [ -d "$CCACHE_WRAPPER_PATH" ]; then
|
||||||
|
mkdir -p "$CCACHE_WRAPPER_PATH"
|
||||||
|
|
||||||
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}" ]; then
|
||||||
|
ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}" ]; then
|
||||||
|
ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm" ]; then
|
||||||
|
ln -s "${AVR_NM}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy" ]; then
|
||||||
|
ln -s "${AVR_OBJCOPY}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar" ]; then
|
||||||
|
ln -s "${AVR_AR}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size" ]; then
|
||||||
|
ln -s "${AVR_SIZE}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export CCACHE_PATH=${COMPILER_PATH}/
|
||||||
|
CCACHE_ENABLE="-prefs compiler.path=${CCACHE_WRAPPER_PATH}/"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
firmware_size () {
|
||||||
|
if [ "${ARCH}" = "virtual" ]; then
|
||||||
|
echo "[Size not computed for virtual build]"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
: "${MAX_PROG_SIZE:=$(get_arduino_pref 'upload.maximum_size')}"
|
||||||
|
|
||||||
|
## This is a terrible hack, please don't hurt me. - algernon
|
||||||
|
|
||||||
|
set +e
|
||||||
|
raw_output=$("$@" 2> /dev/null)
|
||||||
|
rc=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $rc -eq 0 ]; then
|
||||||
|
output="$(echo "${raw_output}"| grep "\\(Program\\|Data\\):" | sed -e 's,^, - ,' && echo)"
|
||||||
|
|
||||||
|
PROGSIZE="$(echo "${output}" | grep "Program:" | cut -d: -f2 | awk '{print $1}')"
|
||||||
|
|
||||||
|
PERCENT="$(echo "${PROGSIZE}" "${MAX_PROG_SIZE}" | awk "{ printf \"%02.01f\", \$1 / \$2 * 100 }")"
|
||||||
|
|
||||||
|
# we want the sed there, doing with shell builtins would be worse.
|
||||||
|
# shellcheck disable=SC2001 disable=SC1117
|
||||||
|
echo "${output}" | sed -e "s/\(Program:.*\)(\([0-9\.]*%\) Full)/\1(${PERCENT}% Full)/"
|
||||||
|
else
|
||||||
|
echo "Unable to determine image size."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
find_sketch () {
|
||||||
|
if [ -z "${SKETCH}" ]; then
|
||||||
|
echo "SKETCH needs to be set before including this file!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SKETCH_DIR="${SKETCH}"
|
||||||
|
SKETCH_BASE_NAME=$(basename "$SKETCH")
|
||||||
|
SKETCH_FILE_NAME="${SKETCH_BASE_NAME}.ino"
|
||||||
|
|
||||||
|
for path in "${SKETCH_DIR}" \
|
||||||
|
"src" \
|
||||||
|
"."; do
|
||||||
|
if [ -f "${path}/${SKETCH_FILE_NAME}" ]; then
|
||||||
|
SKETCH_DIR="${path}"
|
||||||
|
SKETCH_FILE_PATH=$(absolute_filename "${SKETCH_DIR}/${SKETCH_FILE_NAME}")
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "I couldn't find your sketch (.ino file)" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
prompt_before_flashing () {
|
||||||
|
flashing_instructions=$(get_arduino_pref 'build.flashing_instructions')
|
||||||
|
|
||||||
|
if [ "x${flashing_instructions}x" = "xx" ]; then
|
||||||
|
flashing_instructions="If your keyboard needs you to do something to put it in flashing mode, do that now."
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%b\n\n' "${flashing_instructions}"
|
||||||
|
echo ""
|
||||||
|
echo "When you're ready to proceed, press 'Enter'."
|
||||||
|
|
||||||
|
# We do not want to permit line continuations here. We just want a newline.
|
||||||
|
# shellcheck disable=SC2162
|
||||||
|
read
|
||||||
|
}
|
||||||
|
|
||||||
|
flash () {
|
||||||
|
compile "$@"
|
||||||
|
|
||||||
|
# Check to see if we can see a keyboard bootloader port.
|
||||||
|
# If we -can-, then we should skip over the "reset to bootloader" thing
|
||||||
|
find_bootloader_ports
|
||||||
|
if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then
|
||||||
|
prompt_before_flashing
|
||||||
|
|
||||||
|
# This is defined in the (optional) user config.
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
${preFlash_HOOKS}
|
||||||
|
|
||||||
|
# If we're -not- doing a manual reset, then try to do it automatically
|
||||||
|
if [ -z "${MANUAL_RESET}" ]; then
|
||||||
|
reset_device
|
||||||
|
sleep 2
|
||||||
|
find_bootloader_ports
|
||||||
|
# Otherwise, poll for a bootloader port.
|
||||||
|
else
|
||||||
|
wait_for_bootloader_port
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_bootloader_port_and_flash
|
||||||
|
|
||||||
|
# This is defined in the (optional) user config.
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
${postFlash_HOOKS}
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_bootloader_port() {
|
||||||
|
declare -i tries
|
||||||
|
tries=15
|
||||||
|
|
||||||
|
while [ "$tries" -gt 0 ] && [ -z "${DEVICE_PORT_BOOTLOADER}" ]; do
|
||||||
|
sleep 1
|
||||||
|
printf "."
|
||||||
|
find_bootloader_ports
|
||||||
|
# the variable annotations do appear to be necessary
|
||||||
|
# shellcheck disable=SC2004
|
||||||
|
tries=$(($tries-1))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$tries" -gt 0 ]; then
|
||||||
|
echo "Found."
|
||||||
|
else
|
||||||
|
echo "Timed out."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_bootloader_port () {
|
||||||
|
if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then
|
||||||
|
echo "Unable to detect a keyboard in bootloader mode."
|
||||||
|
echo "You may need to hold a key or hit a reset button."
|
||||||
|
echo "Please check your keyboard's documentation"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
check_bootloader_port_and_flash () {
|
||||||
|
|
||||||
|
if ! check_bootloader_port; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Flashing your keyboard:"
|
||||||
|
|
||||||
|
# If the flash fails, try a second time
|
||||||
|
if ! flash_over_usb; then
|
||||||
|
sleep 2
|
||||||
|
if ! flash_over_usb; then
|
||||||
|
if [ "${ARDUINO_VERBOSE}" != "-verbose" ]; then
|
||||||
|
echo "Something went wrong."
|
||||||
|
echo "You might want to try flashing again with the VERBOSE environment variable set"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "Keyboard flashed successfully!"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_over_usb () {
|
||||||
|
|
||||||
|
FLASH_CMD=$(${AVRDUDE} \
|
||||||
|
-C "${AVRDUDE_CONF}" \
|
||||||
|
-p"${MCU}" \
|
||||||
|
-cavr109 \
|
||||||
|
-D \
|
||||||
|
-P "${DEVICE_PORT_BOOTLOADER}" \
|
||||||
|
-b57600 \
|
||||||
|
"-Uflash:w:${HEX_FILE_PATH}:i")
|
||||||
|
|
||||||
|
if [ "${ARDUINO_VERBOSE}" != "-verbose" ]; then
|
||||||
|
${FLASH_CMD} 2>&1 |grep -v ^avrdude | grep -v '^$' |grep -v '^ ' | grep -vi programmer
|
||||||
|
return "${PIPESTATUS[0]}"
|
||||||
|
else
|
||||||
|
${FLASH_CMD}
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_from_bootloader() {
|
||||||
|
compile "$@"
|
||||||
|
prompt_before_flashing
|
||||||
|
find_bootloader_ports
|
||||||
|
check_bootloader_port_and_flash
|
||||||
|
}
|
||||||
|
|
||||||
|
program() {
|
||||||
|
compile "$@"
|
||||||
|
prompt_before_flashing
|
||||||
|
flash_with_programmer
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_with_programmer() {
|
||||||
|
${AVRDUDE} -v \
|
||||||
|
-C "${AVRDUDE_CONF}" \
|
||||||
|
-p"${MCU}" \
|
||||||
|
-cusbtiny \
|
||||||
|
-D \
|
||||||
|
-B 1 \
|
||||||
|
"-Uflash:w:${HEX_FILE_PATH}:i"
|
||||||
|
}
|
||||||
|
|
||||||
|
find_bootloader_path() {
|
||||||
|
BOOTLOADER_FILE=$( get_arduino_pref 'bootloader.file' )
|
||||||
|
: "${BOOTLOADER_FILE:=caterina/Caterina.hex}"
|
||||||
|
: "${BOOTLOADER_PATH:=${BOARD_HARDWARE_PATH}/keyboardio/avr/bootloaders/${BOOTLOADER_FILE}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hex_with_bootloader () {
|
||||||
|
compile
|
||||||
|
|
||||||
|
find_bootloader_path
|
||||||
|
|
||||||
|
awk '/^:00000001FF/ == 0' "${HEX_FILE_PATH}" > "${HEX_FILE_WITH_BOOTLOADER_PATH}"
|
||||||
|
echo "Using ${BOOTLOADER_PATH}"
|
||||||
|
${MD5} "${BOOTLOADER_PATH}"
|
||||||
|
cat "${BOOTLOADER_PATH}" >> "${HEX_FILE_WITH_BOOTLOADER_PATH}"
|
||||||
|
ln -sf -- "${OUTPUT_FILE_PREFIX}-with-bootloader.hex" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest-with-bootloader.hex"
|
||||||
|
cat <<- EOF
|
||||||
|
|
||||||
|
Combined firmware and bootloader are now at ${HEX_FILE_WITH_BOOTLOADER_PATH}
|
||||||
|
Make sure you have the bootloader version you expect.
|
||||||
|
|
||||||
|
And TEST THIS ON REAL HARDWARE BEFORE YOU GIVE IT TO ANYONE
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
build () {
|
||||||
|
compile "$@"
|
||||||
|
size "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prepare_ccache () {
|
||||||
|
build_paths
|
||||||
|
enable_ccache
|
||||||
|
}
|
||||||
|
compile () {
|
||||||
|
find_sketch
|
||||||
|
build_version
|
||||||
|
build_paths
|
||||||
|
build_filenames
|
||||||
|
# If the hex file is older than the sketch file, or the hex file does not exist
|
||||||
|
# then rebuild. This is not as correct as letting make check our dependencies
|
||||||
|
# But it's less broken for most user use cases
|
||||||
|
# TODO(anyone): Make this suck less
|
||||||
|
if [ "${HEX_FILE_PATH}" -ot "${SKETCH_FILE_PATH}" ]; then
|
||||||
|
do_compile "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_compile () {
|
||||||
|
prepare_ccache
|
||||||
|
|
||||||
|
install -d "${OUTPUT_PATH}"
|
||||||
|
|
||||||
|
echo "Building ${SKETCH_FILE_PATH}"
|
||||||
|
|
||||||
|
# This is defined in the (optional) user config.
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
${compile_HOOKS}
|
||||||
|
|
||||||
|
if [ -d "${ARDUINO_LOCAL_LIB_PATH}/libraries" ]; then
|
||||||
|
# shellcheck disable=SC2089
|
||||||
|
# We want literal backslashes here, not arrays.
|
||||||
|
local_LIBS="-libraries \"${ARDUINO_LOCAL_LIB_PATH}/libraries\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARDUINO_PACKAGES=""
|
||||||
|
if [ -d "${ARDUINO_PACKAGE_PATH}" ]; then
|
||||||
|
# shellcheck disable=SC2089
|
||||||
|
# We want literal backslashes here, not arrays.
|
||||||
|
ARDUINO_PACKAGES="-hardware \"${ARDUINO_PACKAGE_PATH}\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
SAVED_BOARD="${BOARD}"
|
||||||
|
SAVED_FQBN="${FQBN}"
|
||||||
|
if [ -e "${SKETCH_DIR}/.kaleidoscope-builder.conf" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
BOARD="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${BOARD}")"
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
FQBN="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${FQBN}")"
|
||||||
|
if [ -n "${BOARD}" ]; then
|
||||||
|
if [ -z "${ARCH}" ]; then
|
||||||
|
FQBN="keyboardio:avr:${BOARD}"
|
||||||
|
else
|
||||||
|
FQBN="keyboardio:${ARCH}:${BOARD}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_CMD_CXX="${CXX:-${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}${COMPILER_SUFFIX}}"
|
||||||
|
_CMD_CC="${CC:-${COMPILER_PREFIX}${C_COMPILER_BASENAME}${COMPILER_SUFFIX}}"
|
||||||
|
_CMD_AR="${AR:-${COMPILER_PREFIX}${AR_BASENAME}${COMPILER_SUFFIX}}"
|
||||||
|
|
||||||
|
# SC2091: We do not care if quotes or backslashes are not respected.
|
||||||
|
# SC2086: We want word splitting.
|
||||||
|
# shellcheck disable=SC2086,SC2090
|
||||||
|
"${ARDUINO_BUILDER}" \
|
||||||
|
-compile \
|
||||||
|
${ARDUINO_PACKAGES} \
|
||||||
|
-hardware "${ARDUINO_PATH}/hardware" \
|
||||||
|
-hardware "${BOARD_HARDWARE_PATH}" \
|
||||||
|
${ARDUINO_TOOLS_FLAG:+"${ARDUINO_TOOLS_FLAG}"} ${ARDUINO_TOOLS_PARAM:+"${ARDUINO_TOOLS_PARAM}"} \
|
||||||
|
-tools "${ARDUINO_BUILDER_TOOLS_PATH}" \
|
||||||
|
-fqbn "${FQBN}" \
|
||||||
|
-libraries "." \
|
||||||
|
-libraries "${KALEIDOSCOPE_DIR}" \
|
||||||
|
-libraries "${BOARD_HARDWARE_PATH}/.." \
|
||||||
|
${local_LIBS} \
|
||||||
|
${EXTRA_BUILDER_ARGS} \
|
||||||
|
-build-cache "${CORE_CACHE_PATH}" \
|
||||||
|
-build-path "${BUILD_PATH}" \
|
||||||
|
-ide-version "${ARDUINO_IDE_VERSION}" \
|
||||||
|
-built-in-libraries "${ARDUINO_PATH}/libraries" \
|
||||||
|
-prefs "compiler.cpp.extra_flags=${ARDUINO_CFLAGS} ${LOCAL_CFLAGS}" \
|
||||||
|
-prefs "compiler.path=${COMPILER_PATH}" \
|
||||||
|
-prefs "compiler.c.cmd=${_CMD_CC}" \
|
||||||
|
-prefs "compiler.cpp.cmd=${_CMD_CXX}" \
|
||||||
|
-prefs "compiler.ar.cmd=${_CMD_AR}" \
|
||||||
|
-prefs "compiler.c.elf.cmd=${_CMD_CXX}" \
|
||||||
|
$CCACHE_ENABLE \
|
||||||
|
-warnings all \
|
||||||
|
${ARDUINO_VERBOSE} \
|
||||||
|
${ARDUINO_AVR_GCC_PREFIX_PARAM} \
|
||||||
|
"${SKETCH_FILE_PATH}"
|
||||||
|
|
||||||
|
if [ -z "${LIBONLY}" ]; then
|
||||||
|
cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.hex" "${HEX_FILE_PATH}"
|
||||||
|
cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.elf" "${ELF_FILE_PATH}"
|
||||||
|
ln -sf "${OUTPUT_FILE_PREFIX}.hex" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.hex"
|
||||||
|
ln -sf "${OUTPUT_FILE_PREFIX}.elf" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.elf"
|
||||||
|
else
|
||||||
|
cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.a" "${LIB_FILE_PATH}"
|
||||||
|
ln -sf "${OUTPUT_FILE_PREFIX}.a" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.a"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${ARDUINO_VERBOSE}" = "-verbose" ]; then
|
||||||
|
echo "Build artifacts can be found in ${BUILD_PATH}";
|
||||||
|
fi
|
||||||
|
|
||||||
|
BOARD="${SAVED_BOARD}"
|
||||||
|
FQBN="${SAVED_FQBN}"
|
||||||
|
}
|
||||||
|
|
||||||
|
find_all_sketches () {
|
||||||
|
for plugin in ./*.ino \
|
||||||
|
$([ -d examples ] && find examples -name '*.ino') \
|
||||||
|
src/*.ino; do
|
||||||
|
if [ -d "$(dirname "${plugin}")" ] || [ -f "${plugin}" ]; then
|
||||||
|
p="$(basename "${plugin}" .ino)"
|
||||||
|
if [ "${p}" != '*' ]; then
|
||||||
|
case "${plugin}" in
|
||||||
|
examples/*/${p}/${p}.ino)
|
||||||
|
echo "${plugin}" | sed -e "s,examples/,," | sed -e "s,/${p}\\.ino,,"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "${p}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done | sort
|
||||||
|
}
|
||||||
|
|
||||||
|
build_all () {
|
||||||
|
plugins="$(find_all_sketches)"
|
||||||
|
|
||||||
|
for plugin in ${plugins}; do
|
||||||
|
export SKETCH="${plugin}"
|
||||||
|
$0 "${plugin}" build
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
compile_all () {
|
||||||
|
plugins="$(find_all_sketches)"
|
||||||
|
|
||||||
|
for plugin in ${plugins}; do
|
||||||
|
export SKETCH="${plugin}"
|
||||||
|
$0 "${plugin}" compile
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size () {
|
||||||
|
compile
|
||||||
|
|
||||||
|
echo "- Size: ${ELF_FILE_PATH}"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
firmware_size "${AVR_SIZE}" ${AVR_SIZE_FLAGS} "${ELF_FILE_PATH}"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
size_map () {
|
||||||
|
compile
|
||||||
|
|
||||||
|
"${AVR_NM}" --size-sort -C -r -l -t decimal "${ELF_FILE_PATH}"
|
||||||
|
}
|
||||||
|
|
||||||
|
disassemble () {
|
||||||
|
compile
|
||||||
|
|
||||||
|
"${AVR_OBJDUMP}" -C -d "${ELF_FILE_PATH}"
|
||||||
|
}
|
||||||
|
|
||||||
|
decompile () {
|
||||||
|
disassemble
|
||||||
|
}
|
||||||
|
|
||||||
|
clean () {
|
||||||
|
find_sketch
|
||||||
|
build_paths
|
||||||
|
rm -rf -- "${OUTPUT_PATH}"
|
||||||
|
rm -rf -- "${BUILD_PATH}"
|
||||||
|
kaleidoscope_dir="$(dirname "$0")/.."
|
||||||
|
if [ -d "${kaleidoscope_dir}/testing/googletest/build" ]; then
|
||||||
|
( cd "${kaleidoscope_dir}/testing/googletest/build" &&
|
||||||
|
cmake .. &&
|
||||||
|
make clean)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_device() {
|
||||||
|
find_device_port
|
||||||
|
check_device_port
|
||||||
|
reset_device_cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
check_device_port () {
|
||||||
|
if [ -z "$DEVICE_PORT" ]; then
|
||||||
|
cat <<EOF >&2
|
||||||
|
|
||||||
|
I couldn't autodetect the keyboard's serial port.
|
||||||
|
|
||||||
|
If you see this message and your keyboard is connected to your computer,
|
||||||
|
it may mean that our serial port detection logic is buggy or incomplete.
|
||||||
|
In that case, please report this issue at:
|
||||||
|
https://github.com/keyboardio/Kaleidoscope
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
elif echo "$DEVICE_PORT" | grep -q '[[:space:]]'; then
|
||||||
|
cat <<EOF >&2
|
||||||
|
Unexpected whitespace found in detected serial port:
|
||||||
|
|
||||||
|
$DEVICE_PORT
|
||||||
|
|
||||||
|
If you see this message, it means that our serial port
|
||||||
|
detection logic is buggy or incomplete.
|
||||||
|
|
||||||
|
Please report this issue at:
|
||||||
|
https://github.com/keyboardio/Kaleidoscope
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -w "$DEVICE_PORT" ]; then
|
||||||
|
cat <<EOF >&2
|
||||||
|
|
||||||
|
In order to update your keyboard's firmware you need to have permission
|
||||||
|
to write to its serial port $DEVICE_PORT.
|
||||||
|
|
||||||
|
It appears that you do not have this permission:
|
||||||
|
|
||||||
|
$(ls -l "$DEVICE_PORT")
|
||||||
|
|
||||||
|
This may be because you're not in the correct unix group:
|
||||||
|
|
||||||
|
$(stat -c %G "$DEVICE_PORT").
|
||||||
|
|
||||||
|
You are currently in the following groups:
|
||||||
|
|
||||||
|
$(id -Gn)
|
||||||
|
|
||||||
|
Please ensure you have followed the instructions on setting up your
|
||||||
|
account to be in the right group:
|
||||||
|
|
||||||
|
https://github.com/keyboardio/Kaleidoscope/wiki/Install-Arduino-support-on-Linux
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deprecation_message() {
|
||||||
|
echo "kaleidoscope-builder is deprecated and will be removed"
|
||||||
|
echo "by February 15, 2021"
|
||||||
|
echo ""
|
||||||
|
echo "To switch to the new build system, replace your sketch's"
|
||||||
|
echo "Makefile with a copy of:"
|
||||||
|
echo ""
|
||||||
|
echo "${KALEIDOSCOPE_DIR}/etc/Makefile.sketch"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
usage () {
|
||||||
|
cat <<- EOF
|
||||||
|
Usage: $0 SKETCH commands...
|
||||||
|
|
||||||
|
Runs all of the commands in the context of the Sketch.
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
|
||||||
|
help
|
||||||
|
This help screen.
|
||||||
|
|
||||||
|
compile
|
||||||
|
Compiles the sketch.
|
||||||
|
|
||||||
|
size
|
||||||
|
Reports the size of the compiled sketch.
|
||||||
|
|
||||||
|
build
|
||||||
|
Runs compile and report-size.
|
||||||
|
|
||||||
|
clean
|
||||||
|
Cleans up the output directory.
|
||||||
|
|
||||||
|
size-map
|
||||||
|
Displays the size map for the sketch.
|
||||||
|
|
||||||
|
disassemble
|
||||||
|
Decompile the sketch.
|
||||||
|
|
||||||
|
reset-device
|
||||||
|
Reset the device.
|
||||||
|
|
||||||
|
flash
|
||||||
|
Flashes the firmware using avrdude.
|
||||||
|
|
||||||
|
build-all
|
||||||
|
Build all Sketches we can find.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KALEIDOSCOPE_DIR="$(cd "$(dirname "$0")"/..; pwd)"
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
KALEIDOSCOPE_BIN_DIR="${KALEIDOSCOPE_DIR}/bin/"
|
||||||
|
|
||||||
|
|
||||||
|
help () {
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
## Parse the command-line
|
||||||
|
## - anything that has a =, is an env var
|
||||||
|
## - from the remaining stuff, the first one is the Library/Sketch
|
||||||
|
## - everything else are commands
|
||||||
|
##
|
||||||
|
## - if there is only one argument, that's a command
|
||||||
|
|
||||||
|
|
||||||
|
deprecation_message
|
||||||
|
|
||||||
|
|
||||||
|
# shellcheck disable=SC2155
|
||||||
|
export SOURCEDIR="$(pwd)"
|
||||||
|
|
||||||
|
|
||||||
|
for conf_file in \
|
||||||
|
"${HOME}/.kaleidoscope-builder.conf" \
|
||||||
|
"${SOURCEDIR}/.kaleidoscope-builder.conf" \
|
||||||
|
"${SOURCEDIR}/kaleidoscope-builder.conf" \
|
||||||
|
"${KALEIDOSCOPE_DIR}/etc/kaleidoscope-builder.conf"; do
|
||||||
|
if [ -e "${conf_file}" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "${conf_file}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
|
||||||
|
if [ -n "${VERBOSE}" ] && [[ "${VERBOSE}" -gt 0 ]]; then
|
||||||
|
ARDUINO_VERBOSE="-verbose"
|
||||||
|
else
|
||||||
|
ARDUINO_VERBOSE="-quiet"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmds=""
|
||||||
|
|
||||||
|
## Export vars
|
||||||
|
for i in $(seq 1 $#); do
|
||||||
|
v="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
case "${v}" in
|
||||||
|
*=*)
|
||||||
|
# Exporting an expansion is *precisely* what we want here.
|
||||||
|
# shellcheck disable=SC2086,SC2163
|
||||||
|
export ${v}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
cmds="${cmds} ${v}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Word splitting is desired here.
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
set -- ${cmds}
|
||||||
|
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
cmd="$(echo "$1" | tr '-' '_')"
|
||||||
|
${cmd}
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
SKETCH="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ "${SKETCH}" = "default" ]; then
|
||||||
|
SKETCH="${DEFAULT_SKETCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmds=""
|
||||||
|
|
||||||
|
# shellcheck disable=2034
|
||||||
|
for i in $(seq 1 $#); do
|
||||||
|
cmds="${cmds} $(echo "$1" | tr '-' '_')"
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
for cmd in ${cmds}; do
|
||||||
|
${cmd}
|
||||||
|
done
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
# This script sets all of the files inside src and example to have mtimes
|
||||||
|
# that match the times of the last git commit that touched each file
|
||||||
|
|
||||||
|
# This can be useful when build tools depend on file timestamps to
|
||||||
|
# make caching decisions
|
||||||
|
|
||||||
|
find src examples -type f -exec sh -c '
|
||||||
|
timestamp=$(git log --pretty=format:%ad --date=format:%Y%m%d%H%M.%S -n 1 HEAD "$1" 2> /dev/null)
|
||||||
|
if [ "x$timestamp" != "x" ]; then
|
||||||
|
touch -t "$timestamp" "$1"
|
||||||
|
fi
|
||||||
|
' sh {} \;
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
# Docker
|
|
||||||
|
|
||||||
It's possible to use Docker to run Kaleidoscope's test suite.
|
|
||||||
|
|
||||||
## Running tests in Docker
|
|
||||||
|
|
||||||
```
|
|
||||||
# make docker-simulator-tests
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cleaning out stale data in the Docker image:
|
|
||||||
|
|
||||||
```
|
|
||||||
# make docker-clean
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Removing the Kaleidoscope Docker image entirely:
|
|
||||||
|
|
||||||
```
|
|
||||||
# docker volume rm kaleidoscope-persist
|
|
||||||
# docker volume rm kaleidoscope-googletest-build
|
|
||||||
# docker volume rm kaleidoscope-build
|
|
||||||
# docker image rm kaleidoscope/docker
|
|
||||||
```
|
|
@ -0,0 +1,274 @@
|
|||||||
|
# -*- shell-script -*-
|
||||||
|
|
||||||
|
## NEEDS: SKETCH
|
||||||
|
## Should be included when the current directory is the dir of the Sketch.
|
||||||
|
|
||||||
|
SKETCH="${SKETCH:-${DEFAULT_SKETCH}}"
|
||||||
|
|
||||||
|
########
|
||||||
|
######## Keyboard hardware definitions
|
||||||
|
########
|
||||||
|
|
||||||
|
: "${BOARD:=model01}"
|
||||||
|
: "${MCU:=atmega32u4}"
|
||||||
|
|
||||||
|
if [ -z "${ARCH}" ]; then
|
||||||
|
ARCH=$(echo "${FQBN}" | sed -n -e 's/^[^:]\+:\([^:]\+\).*/\1/p')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${ARCH}" = "virtual" ]; then
|
||||||
|
: "${FQBN:=keyboardio:virtual:${BOARD}}"
|
||||||
|
|
||||||
|
# Set the compiler path for virtual builds
|
||||||
|
#
|
||||||
|
if [ -z "${COMPILER_PATH}" ]; then
|
||||||
|
COMPILER_PATH="/usr/bin/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMPILER_PREFIX=""
|
||||||
|
else
|
||||||
|
ARCH="avr"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${FQBN}" ]; then
|
||||||
|
: "${FQBN:=keyboardio:avr:${BOARD}}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
########
|
||||||
|
######## Host OS specific commands
|
||||||
|
########
|
||||||
|
|
||||||
|
## Platform-specific overrides
|
||||||
|
# Shamelessly stolen from git's Makefile
|
||||||
|
uname_S=$(uname -s 2>/dev/null || echo not)
|
||||||
|
uname_O=$(uname -o 2>/dev/null || echo not)
|
||||||
|
|
||||||
|
|
||||||
|
find_device_vid_pid() {
|
||||||
|
: ${VID:=$(get_arduino_pref 'build.vid')}
|
||||||
|
: ${SKETCH_PID:=$(get_arduino_pref 'build.pid')}
|
||||||
|
: ${BOOTLOADER_PID:=$(get_arduino_pref 'bootloader.pid')}
|
||||||
|
: ${BOOTLOADER_VID:=$(get_arduino_pref 'bootloader.vid')}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get_arduino_pref() {
|
||||||
|
pref=$1
|
||||||
|
# Strip the preference name. And then strip leading and trailing quotations
|
||||||
|
MESSAGE=$(dump_arduino_prefs | grep --max-count=1 ${pref}= | sed -e s/^.*${pref}=// -e 's/^"//' -e 's/"$//')
|
||||||
|
echo $MESSAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dump_arduino_prefs() {
|
||||||
|
# SKETCH and -build-path in this command are here because of a bug introduced in Arduino 1.8.10
|
||||||
|
# https://github.com/arduino/arduino-builder/issues/341
|
||||||
|
|
||||||
|
if [ "x${_ARDUINO_PREFS}x" == "xx" ]; then
|
||||||
|
|
||||||
|
_ARDUINO_PREFS=$("${ARDUINO_BUILDER}" \
|
||||||
|
-hardware "${ARDUINO_PATH}/hardware" \
|
||||||
|
-hardware "${BOARD_HARDWARE_PATH}" \
|
||||||
|
${ARDUINO_TOOLS_FLAG:+"${ARDUINO_TOOLS_FLAG}"} ${ARDUINO_TOOLS_PARAM:+"${ARDUINO_TOOLS_PARAM}"} \
|
||||||
|
-tools "${ARDUINO_BUILDER_TOOLS_PATH}" \
|
||||||
|
-fqbn "${FQBN}" \
|
||||||
|
-build-path "${ARDUINO_PATH}" \
|
||||||
|
-dump-prefs "${SKETCH_DIR}/${SKETCH}.ino" )
|
||||||
|
fi
|
||||||
|
echo "$_ARDUINO_PREFS"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
find_device_port() {
|
||||||
|
find_device_vid_pid
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-linux-udev"
|
||||||
|
if [[ "${DEVICE_PORT}" = "" ]]; then
|
||||||
|
DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID})"
|
||||||
|
else
|
||||||
|
echo "DEVICE_PORT=\"${DEVICE_PORT}\" predefined."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_device_cmd() {
|
||||||
|
if [ -z ${NO_RESET} ]; then
|
||||||
|
stty -F ${DEVICE_PORT} 1200 hupcl
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
find_bootloader_ports() {
|
||||||
|
find_device_vid_pid
|
||||||
|
: "${BOOTLOADER_VID:=${VID}}"
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-linux-udev"
|
||||||
|
if [[ "${DEVICE_PORT_BOOTLOADER}" = "" ]]; then
|
||||||
|
DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID})"
|
||||||
|
else
|
||||||
|
echo "DEVICE_PORT_BOOTLOADER=\"${DEVICE_PORT_BOOTLOADER}\" predefined."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MD5="md5sum"
|
||||||
|
|
||||||
|
if [ "${uname_S}" = "Darwin" ]; then
|
||||||
|
|
||||||
|
find_device_port() {
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-macos"
|
||||||
|
DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID})"
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_device_cmd() {
|
||||||
|
/bin/stty -f ${DEVICE_PORT} 1200
|
||||||
|
}
|
||||||
|
|
||||||
|
: "${ARDUINO_PATH:=/Applications/Arduino.app/Contents/Java/}"
|
||||||
|
: "${ARDUINO_PACKAGE_PATH:=${HOME}/Library/Arduino15/packages}"
|
||||||
|
: "${ARDUINO_LOCAL_LIB_PATH:=${HOME}/Documents/Arduino}"
|
||||||
|
|
||||||
|
MD5="md5"
|
||||||
|
|
||||||
|
find_bootloader_ports() {
|
||||||
|
find_device_vid_pid
|
||||||
|
: "${BOOTLOADER_VID:=${VID}}"
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-macos"
|
||||||
|
if [[ "${DEVICE_PORT_BOOTLOADER}" = "" ]]; then
|
||||||
|
DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID})"
|
||||||
|
else
|
||||||
|
echo "DEVICE_PORT_BOOTLOADER=\"${DEVICE_PORT_BOOTLOADER}\" predefined."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
elif [ "${uname_S}" = "FreeBSD" ]; then
|
||||||
|
|
||||||
|
find_device_port() {
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-freebsd"
|
||||||
|
DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER})"
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_device_cmd() {
|
||||||
|
/bin/stty -f ${DEVICE_PORT} 1200
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5="md5"
|
||||||
|
: "${AVR_SIZE:=/usr/local/bin/avr-size}"
|
||||||
|
: "${AVR_NM:=/usr/local/bin/avr-nm}"
|
||||||
|
: "${AVR_OBJDUMP:=/usr/local/bin/avr-objdump}"
|
||||||
|
: "${AVRDUDE:=/usr/local/bin/avrdude}"
|
||||||
|
: "${AVRDUDE_CONF:=/usr/local/etc/avrdude.conf}"
|
||||||
|
: "${ARDUINO_BUILDER:=/usr/local/bin/arduino-builder}"
|
||||||
|
|
||||||
|
find_bootloader_ports() {
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCPE_BIN_DIR}/find-device-port-freebsd"
|
||||||
|
DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER})"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${ARCH}" = "virtual" ]; then
|
||||||
|
: "${COMPILER_PATH:=/usr/local/bin/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [ "${uname_O}" = "Cygwin" ]; then
|
||||||
|
# The Windows arduino-builder.exe doesn't understand being told to exec against Cygwin symlinks
|
||||||
|
CCACHE_NOT_SUPPORTED=1
|
||||||
|
|
||||||
|
# Note: the default ARDUINO_PATH here is the default Arduino installation path on Windows, but it won't actually
|
||||||
|
# work in practice right now since we haven't fixed all bugs related to interpretation of spaces in these paths.
|
||||||
|
#
|
||||||
|
# It's important that all of these be underneath /cygdrive/c so they can be converted to Windows paths that the
|
||||||
|
# Windows Arduino binaries can understand.
|
||||||
|
: "${ARDUINO_PATH:=/cygdrive/c/Program\ Files\ (x86)/Arduino}"
|
||||||
|
: "${ARDUINO_PACKAGE_PATH:=/cygdrive/c/Users/${USER}/AppData/Local/Arduino15/packages}"
|
||||||
|
: "${ARDUINO_LOCAL_LIB_PATH:=/cygdrive/c/Users/${USER}/Arduino}"
|
||||||
|
TMPDIR="${ARDUINO_LOCAL_LIB_PATH:-/cygdrive/c/Users/${USER}/AppData/Local/Temp}"
|
||||||
|
|
||||||
|
# We need to prevent Windows executables from being passed parameters that are absolute paths, since they won't
|
||||||
|
# be interpretable when of the form /cygdrive/c/foo. To work around this, we set the common path root variables
|
||||||
|
# to use relative paths instead of absolute paths, since those have mostly platform-agnostic behavior.
|
||||||
|
#
|
||||||
|
# Note that this trick requires that all of these paths exist on the same drive letter as the current directory,
|
||||||
|
# since otherwise even the relative paths would include Cygwin-specific components. So...
|
||||||
|
if [[ $(realpath --relative-base=/cygdrive/c .) == /* ]]; then
|
||||||
|
echo "kaleidoscope-builder's Cygwin support is currently limited to running from within /cygdrive/c"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARDUINO_PATH="$(realpath --relative-to=./ ${ARDUINO_PATH})"
|
||||||
|
ARDUINO_PACKAGE_PATH="$(realpath --relative-to=./ ${ARDUINO_PACKAGE_PATH})"
|
||||||
|
ARDUINO_LOCAL_LIB_PATH="$(realpath --relative-to=./ ${ARDUINO_LOCAL_LIB_PATH})"
|
||||||
|
TMPDIR="$(realpath --relative-to=./ ${ARDUINO_PATH})"
|
||||||
|
|
||||||
|
find_device_port() {
|
||||||
|
find_device_vid_pid
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-windows.ps1"
|
||||||
|
DEVICE_PORT="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID} -Format Cygwin)"
|
||||||
|
DEVICE_COM_PORT="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID} -Format COM)"
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_device_cmd() {
|
||||||
|
cmd /c mode ${DEVICE_COM_PORT} baud=1200
|
||||||
|
}
|
||||||
|
|
||||||
|
find_bootloader_ports() {
|
||||||
|
find_device_vid_pid
|
||||||
|
: "${BOOTLOADER_VID:=${VID}}"
|
||||||
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-windows.ps1"
|
||||||
|
DEVICE_PORT_BOOTLOADER="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID} -Format COM)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
######
|
||||||
|
###### Arduino tools configuration
|
||||||
|
######
|
||||||
|
|
||||||
|
: "${ARDUINO_PATH:=/usr/local/arduino}"
|
||||||
|
: "${ARDUINO_LOCAL_LIB_PATH:=${HOME}/Arduino}"
|
||||||
|
: "${ARDUINO_TOOLS_PATH:=${ARDUINO_PATH}/hardware/tools}"
|
||||||
|
: "${ARDUINO_PACKAGE_PATH:=${HOME}/.arduino15/packages}"
|
||||||
|
: "${ARDUINO_BUILDER:=${ARDUINO_PATH}/arduino-builder}"
|
||||||
|
: "${ARDUINO_BUILDER_TOOLS_PATH:=${ARDUINO_PATH}/tools-builder}"
|
||||||
|
|
||||||
|
ARDUINO_IDE_VERSION="10607"
|
||||||
|
|
||||||
|
######
|
||||||
|
###### Executable paths
|
||||||
|
######
|
||||||
|
|
||||||
|
# Allow the compiler path to be empty for virtual builds
|
||||||
|
: "${COMPILER_PATH=${ARDUINO_TOOLS_PATH}/avr/bin/}"
|
||||||
|
|
||||||
|
COMPILER_SUFFIX=""
|
||||||
|
|
||||||
|
C_COMPILER_BASENAME=$(basename ${CC:-gcc})
|
||||||
|
CXX_COMPILER_BASENAME=$(basename ${CXX:-g++})
|
||||||
|
AR_BASENAME=$(basename ${AR:-ar})
|
||||||
|
OBJCOPY_BASENAME=$(basename ${OBJCOPY:-objcopy})
|
||||||
|
|
||||||
|
# Allow the compiler prefix to be empty for virtual builds
|
||||||
|
COMPILER_PREFIX="${COMPILER_PREFIX-avr-}"
|
||||||
|
: "${AVR_SIZE:=${COMPILER_PATH}/${COMPILER_PREFIX}size}"
|
||||||
|
: "${AVR_SIZE_FLAGS:=-C --mcu=${MCU}}"
|
||||||
|
: "${AVR_OBJDUMP:=${COMPILER_PATH}/${COMPILER_PREFIX}objdump}"
|
||||||
|
: "${AVR_OBJCOPY:=${COMPILER_PATH}/${COMPILER_PREFIX}objcopy}"
|
||||||
|
: "${AVR_NM:=${COMPILER_PATH}/${COMPILER_PREFIX}nm}"
|
||||||
|
: "${AVR_AR:=${COMPILER_PATH}/${COMPILER_PREFIX}ar}"
|
||||||
|
: "${AVR_GCC:=${COMPILER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}}"
|
||||||
|
AVR_GPLUSPLUS="${AVR_GCC:-${COMPILER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
: "${AVRDUDE:=${ARDUINO_TOOLS_PATH}/avr/bin/avrdude}"
|
||||||
|
: "${AVRDUDE_CONF:=${ARDUINO_TOOLS_PATH}/avr/etc/avrdude.conf}"
|
||||||
|
|
||||||
|
######
|
||||||
|
###### Source files and dependencies
|
||||||
|
######
|
||||||
|
|
||||||
|
: "${BOARD_HARDWARE_PATH:=${ARDUINO_LOCAL_LIB_PATH}/hardware}"
|
||||||
|
|
||||||
|
if [ ! -z "${ARDUINO_TOOLS_PATH}" ]; then
|
||||||
|
ARDUINO_TOOLS_PARAM="${ARDUINO_TOOLS_PATH}"
|
||||||
|
ARDUINO_TOOLS_FLAG="-tools"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "${AVR_GCC_PREFIX}" ]; then
|
||||||
|
ARDUINO_AVR_GCC_PREFIX_PARAM="-prefs \"runtime.tools.avr-gcc.path=${AVR_GCC_PREFIX}\""
|
||||||
|
fi
|
@ -0,0 +1,2 @@
|
|||||||
|
DEFAULT_SKETCH="Atreus"
|
||||||
|
BOARD="keyboardio_atreus"
|
@ -1,618 +0,0 @@
|
|||||||
// -*- mode: c++ -*-
|
|
||||||
// Copyright 2016-2022 Keyboardio, inc. <jesse@keyboard.io>
|
|
||||||
// See "LICENSE" for license details
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These #include directives pull in the Kaleidoscope firmware core,
|
|
||||||
* as well as the Kaleidoscope plugins we use in the Model 100's firmware
|
|
||||||
*/
|
|
||||||
|
|
||||||
// The Kaleidoscope core
|
|
||||||
#include "Kaleidoscope.h"
|
|
||||||
|
|
||||||
// Support for storing the keymap in EEPROM
|
|
||||||
#include "Kaleidoscope-EEPROM-Settings.h"
|
|
||||||
#include "Kaleidoscope-EEPROM-Keymap.h"
|
|
||||||
|
|
||||||
// Support for communicating with the host via a simple Serial protocol
|
|
||||||
#include "Kaleidoscope-FocusSerial.h"
|
|
||||||
|
|
||||||
// Support for querying the firmware version via Focus
|
|
||||||
#include "Kaleidoscope-FirmwareVersion.h"
|
|
||||||
|
|
||||||
// Support for keys that move the mouse
|
|
||||||
// #include "Kaleidoscope-MouseKeys.h"
|
|
||||||
|
|
||||||
// Support for macros
|
|
||||||
#include "Kaleidoscope-Macros.h"
|
|
||||||
|
|
||||||
// Support for controlling the keyboard's LEDs
|
|
||||||
#include "Kaleidoscope-LEDControl.h"
|
|
||||||
|
|
||||||
// Support for "Numpad" mode, which is mostly just the Numpad specific LED mode
|
|
||||||
// #include "Kaleidoscope-NumPad.h"
|
|
||||||
|
|
||||||
// Support for the "Boot greeting" effect, which pulses the 'LED' button for 10s
|
|
||||||
// when the keyboard is connected to a computer (or that computer is powered on)
|
|
||||||
#include "Kaleidoscope-LEDEffect-BootGreeting.h"
|
|
||||||
|
|
||||||
// Support for LED modes that set all LEDs to a single color
|
|
||||||
#include "Kaleidoscope-LEDEffect-SolidColor.h"
|
|
||||||
|
|
||||||
// Support for an LED mode that makes all the LEDs 'breathe'
|
|
||||||
#include "Kaleidoscope-LEDEffect-Breathe.h"
|
|
||||||
|
|
||||||
// Support for an LED mode that makes a red pixel chase a blue pixel across the keyboard
|
|
||||||
#include "Kaleidoscope-LEDEffect-Chase.h"
|
|
||||||
|
|
||||||
// Support for LED modes that pulse the keyboard's LED in a rainbow pattern
|
|
||||||
#include "Kaleidoscope-LEDEffect-Rainbow.h"
|
|
||||||
|
|
||||||
// Support for an LED mode that lights up the keys as you press them
|
|
||||||
#include "Kaleidoscope-LED-Stalker.h"
|
|
||||||
|
|
||||||
// Support for an LED mode that prints the keys you press in letters 4px high
|
|
||||||
#include "Kaleidoscope-LED-AlphaSquare.h"
|
|
||||||
|
|
||||||
// Support for shared palettes for other plugins, like Colormap below
|
|
||||||
#include "Kaleidoscope-LED-Palette-Theme.h"
|
|
||||||
|
|
||||||
// Support for an LED mode that lets one configure per-layer color maps
|
|
||||||
#include "Kaleidoscope-Colormap.h"
|
|
||||||
|
|
||||||
// Support for turning the LEDs off after a certain amount of time
|
|
||||||
#include "Kaleidoscope-IdleLEDs.h"
|
|
||||||
|
|
||||||
// Support for setting and saving the default LED mode
|
|
||||||
#include "Kaleidoscope-DefaultLEDModeConfig.h"
|
|
||||||
|
|
||||||
// Support for Keyboardio's internal keyboard testing mode
|
|
||||||
#include "Kaleidoscope-HardwareTestMode.h"
|
|
||||||
|
|
||||||
// Support for host power management (suspend & wakeup)
|
|
||||||
#include "Kaleidoscope-HostPowerManagement.h"
|
|
||||||
|
|
||||||
// Support for magic combos (key chords that trigger an action)
|
|
||||||
#include "Kaleidoscope-MagicCombo.h"
|
|
||||||
|
|
||||||
// Support for USB quirks, like changing the key state report protocol
|
|
||||||
#include "Kaleidoscope-USB-Quirks.h"
|
|
||||||
|
|
||||||
// Support for secondary actions on keys
|
|
||||||
#include "Kaleidoscope-Qukeys.h"
|
|
||||||
|
|
||||||
// Support for one-shot modifiers and layer keys
|
|
||||||
#include "Kaleidoscope-OneShot.h"
|
|
||||||
#include "Kaleidoscope-Escape-OneShot.h"
|
|
||||||
|
|
||||||
// Support for dynamic, Chrysalis-editable macros
|
|
||||||
#include "Kaleidoscope-DynamicMacros.h"
|
|
||||||
|
|
||||||
// Support for SpaceCadet keys
|
|
||||||
#include "Kaleidoscope-SpaceCadet.h"
|
|
||||||
|
|
||||||
// Support for editable layer names
|
|
||||||
#include "Kaleidoscope-LayerNames.h"
|
|
||||||
|
|
||||||
// Support for the GeminiPR Stenography protocol
|
|
||||||
// #include "Kaleidoscope-Steno.h"
|
|
||||||
|
|
||||||
/** This 'enum' is a list of all the macros used by the Model 100's firmware
|
|
||||||
* The names aren't particularly important. What is important is that each
|
|
||||||
* is unique.
|
|
||||||
*
|
|
||||||
* These are the names of your macros. They'll be used in two places.
|
|
||||||
* The first is in your keymap definitions. There, you'll use the syntax
|
|
||||||
* `M(MACRO_NAME)` to mark a specific keymap position as triggering `MACRO_NAME`
|
|
||||||
*
|
|
||||||
* The second usage is in the 'switch' statement in the `macroAction` function.
|
|
||||||
* That switch statement actually runs the code associated with a macro when
|
|
||||||
* a macro key is pressed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum {
|
|
||||||
MACRO_VERSION_INFO,
|
|
||||||
MACRO_ANY,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** The Model 100's key layouts are defined as 'keymaps'. By default, there are three
|
|
||||||
* keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad"
|
|
||||||
* keymap.
|
|
||||||
*
|
|
||||||
* Each keymap is defined as a list using the 'KEYMAP_STACKED' macro, built
|
|
||||||
* of first the left hand's layout, followed by the right hand's layout.
|
|
||||||
*
|
|
||||||
* Keymaps typically consist mostly of `Key_` definitions. There are many, many keys
|
|
||||||
* defined as part of the USB HID Keyboard specification. You can find the names
|
|
||||||
* (if not yet the explanations) for all the standard `Key_` defintions offered by
|
|
||||||
* Kaleidoscope in these files:
|
|
||||||
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/keyboard.h
|
|
||||||
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/consumerctl.h
|
|
||||||
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/sysctl.h
|
|
||||||
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/keymaps.h
|
|
||||||
*
|
|
||||||
* Additional things that should be documented here include
|
|
||||||
* using ___ to let keypresses fall through to the previously active layer
|
|
||||||
* using XXX to mark a keyswitch as 'blocked' on this layer
|
|
||||||
* using ShiftToLayer() and LockLayer() keys to change the active keymap.
|
|
||||||
* keeping NUM and FN consistent and accessible on all layers
|
|
||||||
*
|
|
||||||
* The PROG key is special, since it is how you indicate to the board that you
|
|
||||||
* want to flash the firmware. However, it can be remapped to a regular key.
|
|
||||||
* When the keyboard boots, it first looks to see whether the PROG key is held
|
|
||||||
* down; if it is, it simply awaits further flashing instructions. If it is
|
|
||||||
* not, it continues loading the rest of the firmware and the keyboard
|
|
||||||
* functions normally, with whatever binding you have set to PROG. More detail
|
|
||||||
* here: https://community.keyboard.io/t/how-the-prog-key-gets-you-into-the-bootloader/506/8
|
|
||||||
*
|
|
||||||
* The "keymaps" data structure is a list of the keymaps compiled into the firmware.
|
|
||||||
* The order of keymaps in the list is important, as the ShiftToLayer(#) and LockLayer(#)
|
|
||||||
* macros switch to key layers based on this list.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
|
|
||||||
* A key defined as 'ShiftToLayer(FUNCTION)' will switch to FUNCTION while held.
|
|
||||||
* Similarly, a key defined as 'LockLayer(NUMPAD)' will switch to NUMPAD when tapped.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Layers are "0-indexed" -- That is the first one is layer 0. The second one is layer 1.
|
|
||||||
* The third one is layer 2.
|
|
||||||
* This 'enum' lets us use names like QWERTY, FUNCTION, and NUMPAD in place of
|
|
||||||
* the numbers 0, 1 and 2.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PRIMARY,
|
|
||||||
// NUMPAD,
|
|
||||||
FUNCTION,
|
|
||||||
ETC,
|
|
||||||
}; // layers
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To change your keyboard's layout from QWERTY to DVORAK or COLEMAK, comment out the line
|
|
||||||
*
|
|
||||||
* #define PRIMARY_KEYMAP_QWERTY
|
|
||||||
*
|
|
||||||
* by changing it to
|
|
||||||
*
|
|
||||||
* // #define PRIMARY_KEYMAP_QWERTY
|
|
||||||
*
|
|
||||||
* Then uncomment the line corresponding to the layout you want to use.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// #define PRIMARY_KEYMAP_QWERTY
|
|
||||||
// #define PRIMARY_KEYMAP_DVORAK
|
|
||||||
// #define PRIMARY_KEYMAP_COLEMAK
|
|
||||||
#define PRIMARY_KEYMAP_CUSTOM
|
|
||||||
|
|
||||||
|
|
||||||
/* This comment temporarily turns off astyle's indent enforcement
|
|
||||||
* so we can make the keymaps actually resemble the physical key layout better
|
|
||||||
*/
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
KEYMAPS(
|
|
||||||
|
|
||||||
[PRIMARY] = KEYMAP_STACKED
|
|
||||||
(___, ___, ___, ___, ___, ___, Key_LEDEffectNext,
|
|
||||||
___, Key_Q, Key_W, Key_D, Key_F, Key_K, Key_Tab,
|
|
||||||
___, Key_A, Key_S, Key_E, Key_T, Key_G,
|
|
||||||
Key_Backtick, Key_Z, Key_X, Key_C, Key_V, Key_B, LCTRL(LALT(Key_LeftGui)),
|
|
||||||
GUI_T(Tab), ALT_T(Backspace), CTL_T(Escape), Key_LeftShift,
|
|
||||||
ShiftToLayer(FUNCTION),
|
|
||||||
|
|
||||||
M(MACRO_ANY), ___, Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___,
|
|
||||||
Consumer_VolumeIncrement, Key_J, Key_U, Key_R, Key_L, Key_Semicolon, Key_Backslash,
|
|
||||||
Key_Y, Key_N, Key_I, Key_O, Key_H, Key_Quote,
|
|
||||||
Consumer_VolumeDecrement, Key_P, Key_M, Key_Comma, Key_Period, Key_Slash, ___,
|
|
||||||
Key_RightShift, ALT_T(Enter), Key_Spacebar, GUI_T(Tab),
|
|
||||||
ShiftToLayer(FUNCTION)),
|
|
||||||
|
|
||||||
[FUNCTION] = KEYMAP_STACKED
|
|
||||||
(___, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, ___,
|
|
||||||
___, LSHIFT(Key_1), LSHIFT(Key_2), LSHIFT(Key_LeftBracket), LSHIFT(Key_RightBracket), LSHIFT(Key_Backslash), ___,
|
|
||||||
LSHIFT(Key_7), LSHIFT(Key_3), LSHIFT(Key_4), LSHIFT(Key_9), LSHIFT(Key_0), Key_Backslash,
|
|
||||||
LSHIFT(Key_Backtick), LSHIFT(Key_5), LSHIFT(Key_6), Key_LeftBracket, Key_RightBracket, LSHIFT(Key_8), ___,
|
|
||||||
___, Key_Delete, ___, ___,
|
|
||||||
___,
|
|
||||||
|
|
||||||
___, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11,
|
|
||||||
___, Key_Equals, Key_7, Key_8, Key_9, LSHIFT(Key_Equals), Key_F12,
|
|
||||||
Key_Minus, Key_4, Key_5, Key_6, Key_Quote, ___,
|
|
||||||
___, LSHIFT(Key_Minus), Key_1, Key_2, Key_3, LSHIFT(Key_Quote), ___,
|
|
||||||
___, ___, Key_Enter, Key_0,
|
|
||||||
___),
|
|
||||||
|
|
||||||
[ETC] = KEYMAP_STACKED
|
|
||||||
(___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___,
|
|
||||||
___,
|
|
||||||
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, Key_F7, Key_F8, Key_F9, Key_Home, ___,
|
|
||||||
___, Key_F4, Key_F5, Key_F6, Key_End, ___,
|
|
||||||
___, ___, Key_F1, Key_F2, Key_F3, Key_Insert, ___,
|
|
||||||
___, ___, ___, ___,
|
|
||||||
___)
|
|
||||||
|
|
||||||
) // KEYMAPS(
|
|
||||||
|
|
||||||
/* Re-enable astyle's indent enforcement */
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
/** versionInfoMacro handles the 'firmware version info' macro
|
|
||||||
* When a key bound to the macro is pressed, this macro
|
|
||||||
* prints out the firmware build information as virtual keystrokes
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void versionInfoMacro(uint8_t key_state) {
|
|
||||||
if (keyToggledOn(key_state)) {
|
|
||||||
Macros.type(PSTR("Keyboardio Model 100 - Firmware version "));
|
|
||||||
Macros.type(PSTR(KALEIDOSCOPE_FIRMWARE_VERSION));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** anyKeyMacro is used to provide the functionality of the 'Any' key.
|
|
||||||
*
|
|
||||||
* When the 'any key' macro is toggled on, a random alphanumeric key is
|
|
||||||
* selected. While the key is held, the function generates a synthetic
|
|
||||||
* keypress event repeating that randomly selected key.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void anyKeyMacro(KeyEvent &event) {
|
|
||||||
if (keyToggledOn(event.state)) {
|
|
||||||
event.key.setKeyCode(Key_A.getKeyCode() + (uint8_t)(millis() % 36));
|
|
||||||
event.key.setFlags(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** macroAction dispatches keymap events that are tied to a macro
|
|
||||||
to that macro. It takes two uint8_t parameters.
|
|
||||||
|
|
||||||
The first is the macro being called (the entry in the 'enum' earlier in this file).
|
|
||||||
The second is the state of the keyswitch. You can use the keyswitch state to figure out
|
|
||||||
if the key has just been toggled on, is currently pressed or if it's just been released.
|
|
||||||
|
|
||||||
The 'switch' statement should have a 'case' for each entry of the macro enum.
|
|
||||||
Each 'case' statement should call out to a function to handle the macro in question.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
|
|
||||||
switch (macro_id) {
|
|
||||||
|
|
||||||
case MACRO_VERSION_INFO:
|
|
||||||
versionInfoMacro(event.state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MACRO_ANY:
|
|
||||||
anyKeyMacro(event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return MACRO_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// These 'solid' color effect definitions define a rainbow of
|
|
||||||
// LED color modes calibrated to draw 500mA or less on the
|
|
||||||
// Keyboardio Model 100.
|
|
||||||
|
|
||||||
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0);
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidOrange(140, 70, 0);
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidYellow(130, 100, 0);
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidGreen(0, 160, 0);
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidBlue(0, 70, 130);
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidIndigo(0, 0, 170);
|
|
||||||
static kaleidoscope::plugin::LEDSolidColor solidViolet(130, 0, 120);
|
|
||||||
|
|
||||||
/** toggleLedsOnSuspendResume toggles the LEDs off when the host goes to sleep,
|
|
||||||
* and turns them back on when it wakes up.
|
|
||||||
*/
|
|
||||||
void toggleLedsOnSuspendResume(kaleidoscope::plugin::HostPowerManagement::Event event) {
|
|
||||||
switch (event) {
|
|
||||||
case kaleidoscope::plugin::HostPowerManagement::Suspend:
|
|
||||||
LEDControl.disable();
|
|
||||||
break;
|
|
||||||
case kaleidoscope::plugin::HostPowerManagement::Resume:
|
|
||||||
LEDControl.enable();
|
|
||||||
break;
|
|
||||||
case kaleidoscope::plugin::HostPowerManagement::Sleep:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** hostPowerManagementEventHandler dispatches power management events (suspend,
|
|
||||||
* resume, and sleep) to other functions that perform action based on these
|
|
||||||
* events.
|
|
||||||
*/
|
|
||||||
void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::Event event) {
|
|
||||||
toggleLedsOnSuspendResume(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This 'enum' is a list of all the magic combos used by the Model 100's
|
|
||||||
* firmware The names aren't particularly important. What is important is that
|
|
||||||
* each is unique.
|
|
||||||
*
|
|
||||||
* These are the names of your magic combos. They will be used by the
|
|
||||||
* `USE_MAGIC_COMBOS` call below.
|
|
||||||
*/
|
|
||||||
enum {
|
|
||||||
// Toggle between Boot (6-key rollover; for BIOSes and early boot) and NKRO
|
|
||||||
// mode.
|
|
||||||
COMBO_TOGGLE_NKRO_MODE,
|
|
||||||
// Enter test mode
|
|
||||||
COMBO_ENTER_TEST_MODE
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Wrappers, to be used by MagicCombo. **/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This simply toggles the keyboard protocol via USBQuirks, and wraps it within
|
|
||||||
* a function with an unused argument, to match what MagicCombo expects.
|
|
||||||
*/
|
|
||||||
static void toggleKeyboardProtocol(uint8_t combo_index) {
|
|
||||||
USBQuirks.toggleKeyboardProtocol();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles between using the built-in keymap, and the EEPROM-stored one.
|
|
||||||
*/
|
|
||||||
static void toggleKeymapSource(uint8_t combo_index) {
|
|
||||||
if (Layer.getKey == Layer.getKeyFromPROGMEM) {
|
|
||||||
Layer.getKey = EEPROMKeymap.getKey;
|
|
||||||
} else {
|
|
||||||
Layer.getKey = Layer.getKeyFromPROGMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This enters the hardware test mode
|
|
||||||
*/
|
|
||||||
static void enterHardwareTestMode(uint8_t combo_index) {
|
|
||||||
HardwareTestMode.runTests();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Magic combo list, a list of key combo and action pairs the firmware should
|
|
||||||
* recognise.
|
|
||||||
*/
|
|
||||||
USE_MAGIC_COMBOS({.action = toggleKeyboardProtocol,
|
|
||||||
// Left Fn + Esc + Shift
|
|
||||||
.keys = {R3C6, R2C6, R3C7}},
|
|
||||||
{.action = enterHardwareTestMode,
|
|
||||||
// Left Fn + Prog + LED
|
|
||||||
.keys = {R3C6, R0C0, R0C6}},
|
|
||||||
{.action = toggleKeymapSource,
|
|
||||||
// Left Fn + Prog + Shift
|
|
||||||
.keys = {R3C6, R0C0, R3C7}});
|
|
||||||
|
|
||||||
// First, tell Kaleidoscope which plugins you want to use.
|
|
||||||
// The order can be important. For example, LED effects are
|
|
||||||
// added in the order they're listed here.
|
|
||||||
KALEIDOSCOPE_INIT_PLUGINS(
|
|
||||||
// The EEPROMSettings & EEPROMKeymap plugins make it possible to have an
|
|
||||||
// editable keymap in EEPROM.
|
|
||||||
EEPROMSettings,
|
|
||||||
EEPROMKeymap,
|
|
||||||
|
|
||||||
// SpaceCadet can turn your shifts into parens on tap, while keeping them as
|
|
||||||
// Shifts when held. SpaceCadetConfig lets Chrysalis configure some aspects of
|
|
||||||
// the plugin.
|
|
||||||
// SpaceCadet,
|
|
||||||
// SpaceCadetConfig,
|
|
||||||
|
|
||||||
// Focus allows bi-directional communication with the host, and is the
|
|
||||||
// interface through which the keymap in EEPROM can be edited.
|
|
||||||
Focus,
|
|
||||||
|
|
||||||
// FocusSettingsCommand adds a few Focus commands, intended to aid in
|
|
||||||
// changing some settings of the keyboard, such as the default layer (via the
|
|
||||||
// `settings.defaultLayer` command)
|
|
||||||
FocusSettingsCommand,
|
|
||||||
|
|
||||||
// FocusEEPROMCommand adds a set of Focus commands, which are very helpful in
|
|
||||||
// both debugging, and in backing up one's EEPROM contents.
|
|
||||||
FocusEEPROMCommand,
|
|
||||||
|
|
||||||
// The boot greeting effect pulses the LED button for 10 seconds after the
|
|
||||||
// keyboard is first connected
|
|
||||||
BootGreetingEffect,
|
|
||||||
|
|
||||||
// The hardware test mode, which can be invoked by tapping Prog, LED and the
|
|
||||||
// left Fn button at the same time.
|
|
||||||
HardwareTestMode,
|
|
||||||
|
|
||||||
// LEDControl provides support for other LED modes
|
|
||||||
LEDControl,
|
|
||||||
|
|
||||||
// We start with the LED effect that turns off all the LEDs.
|
|
||||||
LEDOff,
|
|
||||||
|
|
||||||
// The rainbow effect changes the color of all of the keyboard's keys at the same time
|
|
||||||
// running through all the colors of the rainbow.
|
|
||||||
LEDRainbowEffect,
|
|
||||||
|
|
||||||
// The rainbow wave effect lights up your keyboard with all the colors of a rainbow
|
|
||||||
// and slowly moves the rainbow across your keyboard
|
|
||||||
LEDRainbowWaveEffect,
|
|
||||||
|
|
||||||
// The chase effect follows the adventure of a blue pixel which chases a red pixel across
|
|
||||||
// your keyboard. Spoiler: the blue pixel never catches the red pixel
|
|
||||||
LEDChaseEffect,
|
|
||||||
|
|
||||||
// These static effects turn your keyboard's LEDs a variety of colors
|
|
||||||
solidRed,
|
|
||||||
solidOrange,
|
|
||||||
solidYellow,
|
|
||||||
solidGreen,
|
|
||||||
solidBlue,
|
|
||||||
solidIndigo,
|
|
||||||
solidViolet,
|
|
||||||
|
|
||||||
// The breathe effect slowly pulses all of the LEDs on your keyboard
|
|
||||||
LEDBreatheEffect,
|
|
||||||
|
|
||||||
// The AlphaSquare effect prints each character you type, using your
|
|
||||||
// keyboard's LEDs as a display
|
|
||||||
AlphaSquareEffect,
|
|
||||||
|
|
||||||
// The stalker effect lights up the keys you've pressed recently
|
|
||||||
StalkerEffect,
|
|
||||||
|
|
||||||
// The LED Palette Theme plugin provides a shared palette for other plugins,
|
|
||||||
// like Colormap below
|
|
||||||
LEDPaletteTheme,
|
|
||||||
|
|
||||||
// The Colormap effect makes it possible to set up per-layer colormaps
|
|
||||||
ColormapEffect,
|
|
||||||
|
|
||||||
// The numpad plugin is responsible for lighting up the 'numpad' mode
|
|
||||||
// with a custom LED effect
|
|
||||||
// NumPad,
|
|
||||||
|
|
||||||
// The macros plugin adds support for macros
|
|
||||||
Macros,
|
|
||||||
|
|
||||||
// The MouseKeys plugin lets you add keys to your keymap which move the mouse.
|
|
||||||
// MouseKeys,
|
|
||||||
|
|
||||||
// The HostPowerManagement plugin allows us to turn LEDs off when then host
|
|
||||||
// goes to sleep, and resume them when it wakes up.
|
|
||||||
HostPowerManagement,
|
|
||||||
|
|
||||||
// The MagicCombo plugin lets you use key combinations to trigger custom
|
|
||||||
// actions - a bit like Macros, but triggered by pressing multiple keys at the
|
|
||||||
// same time.
|
|
||||||
MagicCombo,
|
|
||||||
|
|
||||||
// The USBQuirks plugin lets you do some things with USB that we aren't
|
|
||||||
// comfortable - or able - to do automatically, but can be useful
|
|
||||||
// nevertheless. Such as toggling the key report protocol between Boot (used
|
|
||||||
// by BIOSes) and Report (NKRO).
|
|
||||||
USBQuirks,
|
|
||||||
|
|
||||||
// The Qukeys plugin enables the "Secondary action" functionality in
|
|
||||||
// Chrysalis. Keys with secondary actions will have their primary action
|
|
||||||
// performed when tapped, but the secondary action when held.
|
|
||||||
Qukeys,
|
|
||||||
|
|
||||||
// Enables the "Sticky" behavior for modifiers, and the "Layer shift when
|
|
||||||
// held" functionality for layer keys.
|
|
||||||
OneShot,
|
|
||||||
EscapeOneShot,
|
|
||||||
EscapeOneShotConfig,
|
|
||||||
|
|
||||||
// Turns LEDs off after a configurable amount of idle time.
|
|
||||||
IdleLEDs,
|
|
||||||
PersistentIdleLEDs,
|
|
||||||
|
|
||||||
// Enables dynamic, Chrysalis-editable macros.
|
|
||||||
DynamicMacros,
|
|
||||||
|
|
||||||
// The FirmwareVersion plugin lets Chrysalis query the version of the firmware
|
|
||||||
// programmatically.
|
|
||||||
FirmwareVersion,
|
|
||||||
|
|
||||||
// The LayerNames plugin allows Chrysalis to display - and edit - custom layer
|
|
||||||
// names, to be shown instead of the default indexes.
|
|
||||||
LayerNames,
|
|
||||||
|
|
||||||
// Enables setting, saving (via Chrysalis), and restoring (on boot) the
|
|
||||||
// default LED mode.
|
|
||||||
DefaultLEDModeConfig
|
|
||||||
|
|
||||||
// Enables the GeminiPR Stenography protocol. Unused by default, but with the
|
|
||||||
// plugin enabled, it becomes configurable - and then usable - via Chrysalis.
|
|
||||||
//GeminiPR
|
|
||||||
);
|
|
||||||
|
|
||||||
/** The 'setup' function is one of the two standard Arduino sketch functions.
|
|
||||||
* It's called when your keyboard first powers up. This is where you set up
|
|
||||||
* Kaleidoscope and any plugins.
|
|
||||||
*/
|
|
||||||
void setup() {
|
|
||||||
// First, call Kaleidoscope's internal setup function
|
|
||||||
Kaleidoscope.setup();
|
|
||||||
|
|
||||||
// Set the hue of the boot greeting effect to something that will result in a
|
|
||||||
// nice green color.
|
|
||||||
BootGreetingEffect.hue = 85;
|
|
||||||
|
|
||||||
// While we hope to improve this in the future, the NumPad plugin
|
|
||||||
// needs to be explicitly told which keymap layer is your numpad layer
|
|
||||||
// NumPad.numPadLayer = NUMPAD;
|
|
||||||
|
|
||||||
// We configure the AlphaSquare effect to use RED letters
|
|
||||||
AlphaSquare.color = CRGB(255, 0, 0);
|
|
||||||
|
|
||||||
// We set the brightness of the rainbow effects to 150 (on a scale of 0-255)
|
|
||||||
// This draws more than 500mA, but looks much nicer than a dimmer effect
|
|
||||||
LEDRainbowEffect.brightness(255);
|
|
||||||
LEDRainbowWaveEffect.brightness(255);
|
|
||||||
|
|
||||||
// Set the action key the test mode should listen for to Left Fn
|
|
||||||
HardwareTestMode.setActionKey(R3C6);
|
|
||||||
|
|
||||||
// The LED Stalker mode has a few effects. The one we like is called
|
|
||||||
// 'BlazingTrail'. For details on other options, see
|
|
||||||
// https://github.com/keyboardio/Kaleidoscope/blob/master/docs/plugins/LED-Stalker.md
|
|
||||||
StalkerEffect.variant = STALKER(BlazingTrail);
|
|
||||||
|
|
||||||
// To make the keymap editable without flashing new firmware, we store
|
|
||||||
// additional layers in EEPROM. For now, we reserve space for eight layers. If
|
|
||||||
// one wants to use these layers, just set the default layer to one in EEPROM,
|
|
||||||
// by using the `settings.defaultLayer` Focus command, or by using the
|
|
||||||
// `keymap.onlyCustom` command to use EEPROM layers only.
|
|
||||||
EEPROMKeymap.setup(8);
|
|
||||||
|
|
||||||
// We need to tell the Colormap plugin how many layers we want to have custom
|
|
||||||
// maps for. To make things simple, we set it to eight layers, which is how
|
|
||||||
// many editable layers we have (see above).
|
|
||||||
ColormapEffect.max_layers(8);
|
|
||||||
|
|
||||||
// For Dynamic Macros, we need to reserve storage space for the editable
|
|
||||||
// macros. A kilobyte is a reasonable default.
|
|
||||||
DynamicMacros.reserve_storage(1024);
|
|
||||||
|
|
||||||
// If there's a default layer set in EEPROM, we should set that as the default
|
|
||||||
// here.
|
|
||||||
Layer.move(EEPROMSettings.default_layer());
|
|
||||||
|
|
||||||
// To avoid any surprises, SpaceCadet is turned off by default. However, it
|
|
||||||
// can be permanently enabled via Chrysalis, so we should only disable it if
|
|
||||||
// no configuration exists.
|
|
||||||
// SpaceCadetConfig.disableSpaceCadetIfUnconfigured();
|
|
||||||
// SpaceCadet.disable();
|
|
||||||
|
|
||||||
// Editable layer names are stored in EEPROM too, and we reserve 16 bytes per
|
|
||||||
// layer for them. We need one extra byte per layer for bookkeeping, so we
|
|
||||||
// reserve 17 / layer in total.
|
|
||||||
LayerNames.reserve_storage(17 * 8);
|
|
||||||
|
|
||||||
// Unless configured otherwise with Chrysalis, we want to make sure that the
|
|
||||||
// firmware starts with LED effects off. This avoids over-taxing devices that
|
|
||||||
// don't have a lot of power to share with USB devices
|
|
||||||
DefaultLEDModeConfig.activateLEDModeIfUnconfigured(&LEDOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** loop is the second of the standard Arduino sketch functions.
|
|
||||||
* As you might expect, it runs in a loop, never exiting.
|
|
||||||
*
|
|
||||||
* For Kaleidoscope-based keyboard firmware, you usually just want to
|
|
||||||
* call Kaleidoscope.loop(); and not do anything custom here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
Kaleidoscope.loop();
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"cpu": {
|
|
||||||
"fqbn": "keyboardio:gd32:keyboardio_model_100",
|
|
||||||
"port": ""
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
/* -*- mode: c++ -*-
|
|
||||||
* Kaleidoscope - A Kaleidoscope example
|
|
||||||
* Copyright (C) 2016-2022 Keyboard.io, Inc.
|
|
||||||
*
|
|
||||||
* 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, version 3.
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DEBUG_SERIAL false
|
|
||||||
|
|
||||||
#include <Kaleidoscope.h>
|
|
||||||
#include <Kaleidoscope-MouseKeys.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PRIMARY,
|
|
||||||
MOUSEKEYS,
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
KEYMAPS(
|
|
||||||
[PRIMARY] = KEYMAP_STACKED
|
|
||||||
(Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
|
|
||||||
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
|
|
||||||
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
|
|
||||||
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
|
|
||||||
|
|
||||||
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
|
|
||||||
ShiftToLayer(MOUSEKEYS),
|
|
||||||
|
|
||||||
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
|
|
||||||
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
|
|
||||||
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
|
|
||||||
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
|
|
||||||
|
|
||||||
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
|
|
||||||
LockLayer(MOUSEKEYS)
|
|
||||||
),
|
|
||||||
|
|
||||||
[MOUSEKEYS] = KEYMAP_STACKED
|
|
||||||
(___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, Key_mouseWarpNW, Key_mouseWarpNE, ___,
|
|
||||||
___, ___, ___, ___, Key_mouseWarpSW, Key_mouseWarpSE,
|
|
||||||
___, ___, Key_mouseBtnL, Key_mouseBtnM, Key_mouseBtnR, ___, ___,
|
|
||||||
___, ___, ___, ___,
|
|
||||||
___,
|
|
||||||
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, Key_mouseUp, ___, ___, ___,
|
|
||||||
___, Key_mouseUp, Key_mouseDn, Key_mouseR, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___,
|
|
||||||
___)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
KALEIDOSCOPE_INIT_PLUGINS(MouseKeys);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Kaleidoscope.setup();
|
|
||||||
MouseKeys.setSpeedLimit(100);
|
|
||||||
MouseKeys.setWarpGridSize(MOUSE_WARP_GRID_2X2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
Kaleidoscope.loop();
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"cpu": {
|
|
||||||
"fqbn": "keyboardio:avr:model01",
|
|
||||||
"port": ""
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
/* -*- mode: c++ -*-
|
|
||||||
* ShiftBlocker -- A Kaleidoscope Example
|
|
||||||
* Copyright (C) 2016-2022 Keyboard.io, Inc.
|
|
||||||
*
|
|
||||||
* 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, version 3.
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Kaleidoscope.h"
|
|
||||||
#include "Kaleidoscope-Macros.h"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
KEYMAPS(
|
|
||||||
[0] = KEYMAP_STACKED
|
|
||||||
(
|
|
||||||
Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
|
|
||||||
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
|
|
||||||
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
|
|
||||||
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
|
|
||||||
|
|
||||||
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
|
|
||||||
M(0),
|
|
||||||
|
|
||||||
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
|
|
||||||
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
|
|
||||||
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
|
|
||||||
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
|
|
||||||
|
|
||||||
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
|
|
||||||
M(0)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
namespace kaleidoscope {
|
|
||||||
namespace plugin {
|
|
||||||
|
|
||||||
// When activated, this plugin will suppress any `Shift` key (including modifier
|
|
||||||
// combos with `Shift`) before it's added to the HID report.
|
|
||||||
class ShiftBlocker : public Plugin {
|
|
||||||
|
|
||||||
public:
|
|
||||||
EventHandlerResult onAddToReport(Key key) {
|
|
||||||
if (active_ && key.isKeyboardShift())
|
|
||||||
return EventHandlerResult::ABORT;
|
|
||||||
return EventHandlerResult::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
active_ = true;
|
|
||||||
}
|
|
||||||
void disable() {
|
|
||||||
active_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool active_{false};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace plugin
|
|
||||||
} // namespace kaleidoscope
|
|
||||||
|
|
||||||
kaleidoscope::plugin::ShiftBlocker ShiftBlocker;
|
|
||||||
|
|
||||||
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
|
|
||||||
if (keyToggledOn(event.state)) {
|
|
||||||
switch (macro_id) {
|
|
||||||
case 0:
|
|
||||||
// First, enable ShiftBlocker to suppress any held `Shift` key(s).
|
|
||||||
ShiftBlocker.enable();
|
|
||||||
// Tap `AltGr` + `7` to activate the grave accent dead key.
|
|
||||||
Macros.tap(RALT(Key_7));
|
|
||||||
// Disable ShiftBlocker so it won't affect the `E` event.
|
|
||||||
ShiftBlocker.disable();
|
|
||||||
// Change the Macros key into a plain `E` key before its press event is
|
|
||||||
// processed.
|
|
||||||
event.key = Key_E;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MACRO_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
KALEIDOSCOPE_INIT_PLUGINS(Macros,
|
|
||||||
ShiftBlocker);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Kaleidoscope.setup();
|
|
||||||
// Uncomment to manually set the OS, as Kaleidoscope will not autodetect it.
|
|
||||||
// (Possible values are in HostOS.h.)
|
|
||||||
// HostOS.os(kaleidoscope::hostos::LINUX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
Kaleidoscope.loop();
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"cpu": {
|
|
||||||
"fqbn": "keyboardio:avr:model01",
|
|
||||||
"port": ""
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
// -*- mode: c++ -*-
|
|
||||||
|
|
||||||
/* This example demonstrates the Model 01 / Model 100 butterfly logo key as a
|
|
||||||
* tmux prefix key. When the key is held, Ctrl-B is pressed prior to the key
|
|
||||||
* you pressed.
|
|
||||||
*
|
|
||||||
* This example also demonstrates the purpose of using an entire layer for this
|
|
||||||
* plugin: the h/j/k/l keys in the TMUX layer are swapped for arrow keys to
|
|
||||||
* make switching between panes easier.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Kaleidoscope.h>
|
|
||||||
#include <Kaleidoscope-PrefixLayer.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PRIMARY,
|
|
||||||
TMUX,
|
|
||||||
}; // layers
|
|
||||||
|
|
||||||
/* Used in setup() below. */
|
|
||||||
static const kaleidoscope::plugin::PrefixLayer::Entry prefix_layers[] PROGMEM = {
|
|
||||||
kaleidoscope::plugin::PrefixLayer::Entry(TMUX, LCTRL(Key_B)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
KEYMAPS(
|
|
||||||
[PRIMARY] = KEYMAP_STACKED
|
|
||||||
(XXX, Key_1, Key_2, Key_3, Key_4, Key_5, XXX,
|
|
||||||
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
|
|
||||||
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
|
|
||||||
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
|
|
||||||
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
|
|
||||||
XXX,
|
|
||||||
|
|
||||||
XXX, Key_6, Key_7, Key_8, Key_9, Key_0, XXX,
|
|
||||||
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
|
|
||||||
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
|
|
||||||
ShiftToLayer(TMUX), Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
|
|
||||||
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
|
|
||||||
XXX),
|
|
||||||
|
|
||||||
[TMUX] = KEYMAP_STACKED
|
|
||||||
(___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___,
|
|
||||||
___,
|
|
||||||
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___,
|
|
||||||
___, ___, ___, ___, ___, ___, ___,
|
|
||||||
___, ___, ___, ___,
|
|
||||||
___),
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Kaleidoscope.setup();
|
|
||||||
/* Configure the previously-defined prefix layers. */
|
|
||||||
PrefixLayer.setPrefixLayers(prefix_layers);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
Kaleidoscope.loop();
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"cpu": {
|
|
||||||
"fqbn": "keyboardio:avr:model01",
|
|
||||||
"port": ""
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue