Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69de9f19e6 | |||
| dfc3ae5765 | |||
| 628615b3a9 | |||
| 5990fdddce | |||
| 9559d406f5 | |||
| fb1993ab04 | |||
| d7c20a56a2 |
@@ -13,33 +13,67 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.3.4
|
- uses: actions/checkout@v2.3.4
|
||||||
|
|
||||||
|
# Environment Setup
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2.2.2
|
uses: actions/setup-python@v2.2.2
|
||||||
with:
|
with:
|
||||||
python-version: '3.7'
|
python-version: '3.7'
|
||||||
|
|
||||||
- name: Run ci_tests
|
- name: Run ci_tests
|
||||||
run: ./ci_tests
|
run: ./ci_tests
|
||||||
- name: Install dependencies
|
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install devscripts equivs sphinx-common sphinx-rtd-theme-common # dh-virtualenv deps
|
||||||
|
apt-get install debhelper dh-python python3-all # stdeb deps
|
||||||
|
apt-get install dpkg-sig # signing deps
|
||||||
|
|
||||||
|
- name: Install dh-virtualenv
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/spotify/dh-virtualenv.git
|
||||||
|
cd dh-virtualenv
|
||||||
|
mk-build-deps -ri
|
||||||
|
dpkg-buildpackage -us -uc -b
|
||||||
|
cd ..
|
||||||
|
dpkg -i dh-virtualenv_*.deb
|
||||||
|
|
||||||
|
- name: Install GPG secret key
|
||||||
|
run: |
|
||||||
|
echo -e "${{ secrets.QMK_GPG_SECRET_KEY }}" | gpg --batch --import
|
||||||
|
gpg --list-secret-keys --keyid-format LONG
|
||||||
|
|
||||||
|
- name: Install python dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install setuptools wheel
|
pip install setuptools wheel
|
||||||
pip install -r requirements-dev.txt
|
pip install -r requirements-dev.txt
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v1.10.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
# Build and upload new Python package
|
||||||
- name: Bump version
|
- name: Bump version
|
||||||
run: |
|
run: |
|
||||||
git config --local user.email "hello@qmk.fm"
|
git config --local user.email "hello@qmk.fm"
|
||||||
git config --local user.name "QMK Bot"
|
git config --local user.name "QMK Bot"
|
||||||
bumpversion ${{ github.event.inputs.version_part }}
|
bumpversion ${{ github.event.inputs.version_part }}
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
uses: ad-m/github-push-action@master
|
uses: ad-m/github-push-action@master
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
branch: master
|
branch: master
|
||||||
tags: true
|
tags: true
|
||||||
|
|
||||||
- name: Build and publish
|
- name: Build and publish
|
||||||
env:
|
env:
|
||||||
TWINE_USERNAME: qmk
|
TWINE_USERNAME: qmk
|
||||||
@@ -47,14 +81,44 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python setup.py sdist bdist_wheel
|
python setup.py sdist bdist_wheel
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
- name: Log in to Docker Hub
|
|
||||||
uses: docker/login-action@v1.10.0
|
# Build and upload new Docker container
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
|
||||||
- name: Build and Push to Docker Hub
|
- name: Build and Push to Docker Hub
|
||||||
uses: docker/build-push-action@v2.6.1
|
uses: docker/build-push-action@v2.6.1
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: qmkfm/qmk_cli:latest
|
tags: qmkfm/qmk_cli:latest
|
||||||
|
|
||||||
|
# Build Debian package
|
||||||
|
- name: Build debian package
|
||||||
|
run: |
|
||||||
|
python3 setup.py bdist_deb
|
||||||
|
dpkg-sig -s builder -k F464DFD46C4DA3FD4D06234691B06358D2CAE8AE deb_dist/*.deb
|
||||||
|
|
||||||
|
# Create Debian repo
|
||||||
|
- name: Build debian package repository
|
||||||
|
run: |
|
||||||
|
mkdir -p deb_repo/deb deb_repo/dsc
|
||||||
|
cp gpg_pubkey.txt deb_repo
|
||||||
|
cp deb_dist/*.deb deb_repo/deb
|
||||||
|
cp deb_dist/*.dsc deb_dist/*.orig.tar.gz deb_dist/*.debian.tar.xz deb_repo/dsc
|
||||||
|
cd deb_repo
|
||||||
|
apt-ftparchive packages deb > Packages
|
||||||
|
apt-ftparchive sources dsc > Sources
|
||||||
|
gzip -k {Packages,Sources}
|
||||||
|
apt-ftparchive release . > Release
|
||||||
|
gpg --default-key F464DFD46C4DA3FD4D06234691B06358D2CAE8AE -abs -o Release.gpg Release
|
||||||
|
gpg --default-key F464DFD46C4DA3FD4D06234691B06358D2CAE8AE --clearsign -o InRelease Release
|
||||||
|
|
||||||
|
# Upload the Debian repo to S3
|
||||||
|
- name: Upload Debian Repo
|
||||||
|
uses: jakejarvis/s3-sync-action@0.5.1
|
||||||
|
with:
|
||||||
|
args: --acl public-read --follow-symlinks --delete
|
||||||
|
env:
|
||||||
|
AWS_S3_BUCKET: qmk-debian
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_KEY }}
|
||||||
|
AWS_S3_ENDPOINT: https://nyc3.digitaloceanspaces.com
|
||||||
|
SOURCE_DIR: 'deb_repo'
|
||||||
|
|||||||
@@ -106,3 +106,8 @@ venv.bak/
|
|||||||
|
|
||||||
# QMK
|
# QMK
|
||||||
qmk_firmware
|
qmk_firmware
|
||||||
|
|
||||||
|
# Debian packages
|
||||||
|
deb_dist
|
||||||
|
deb_repo
|
||||||
|
qmk-*.tar.gz
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ A program to help users work with [QMK Firmware](https://qmk.fm/).
|
|||||||
* Interact with your qmk_firmware tree from any location
|
* Interact with your qmk_firmware tree from any location
|
||||||
* Use `qmk clone` to pull down anyone's `qmk_firmware` fork
|
* Use `qmk clone` to pull down anyone's `qmk_firmware` fork
|
||||||
* Setup your build environment with `qmk setup`
|
* Setup your build environment with `qmk setup`
|
||||||
* Use `qmk console` to get debugging information from your keyboard(s)
|
|
||||||
* Check that your environment is correctly setup with `qmk doctor`
|
* Check that your environment is correctly setup with `qmk doctor`
|
||||||
* Integrates with qmk_firmware for additional functionality:
|
* Integrates with qmk_firmware for additional functionality:
|
||||||
* `qmk compile`
|
* `qmk compile`
|
||||||
* `qmk info`
|
* `qmk console`
|
||||||
* `qmk flash`
|
* `qmk flash`
|
||||||
* `qmk lint`
|
* `qmk lint`
|
||||||
* ...and many more!
|
* ...and many more!
|
||||||
|
|||||||
Vendored
+65
@@ -0,0 +1,65 @@
|
|||||||
|
# Atmel DFU
|
||||||
|
### ATmega16U2
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2fef", TAG+="uaccess"
|
||||||
|
### ATmega32U2
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff0", TAG+="uaccess"
|
||||||
|
### ATmega16U4
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff3", TAG+="uaccess"
|
||||||
|
### ATmega32U4
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff4", TAG+="uaccess"
|
||||||
|
### AT90USB64
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff9", TAG+="uaccess"
|
||||||
|
### AT90USB162
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffa", TAG+="uaccess"
|
||||||
|
### AT90USB128
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffb", TAG+="uaccess"
|
||||||
|
|
||||||
|
# Input Club
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1c11", ATTRS{idProduct}=="b007", TAG+="uaccess"
|
||||||
|
|
||||||
|
# STM32duino
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="0003", TAG+="uaccess"
|
||||||
|
# STM32 DFU
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess"
|
||||||
|
|
||||||
|
# BootloadHID
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", TAG+="uaccess"
|
||||||
|
|
||||||
|
# USBAspLoader
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", TAG+="uaccess"
|
||||||
|
|
||||||
|
# ModemManager should ignore the following devices
|
||||||
|
# Atmel SAM-BA (Massdrop)
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
|
||||||
|
# Caterina (Pro Micro)
|
||||||
|
## Spark Fun Electronics
|
||||||
|
### Pro Micro 3V3/8MHz
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9203", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
### Pro Micro 5V/16MHz
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9205", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
### LilyPad 3V3/8MHz (and some Pro Micro clones)
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9207", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
## Pololu Electronics
|
||||||
|
### A-Star 32U4
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="0101", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
## Arduino SA
|
||||||
|
### Leonardo
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
### Micro
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
## Adafruit Industries LLC
|
||||||
|
### Feather 32U4
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000c", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
### ItsyBitsy 32U4 3V3/8MHz
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000d", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
### ItsyBitsy 32U4 5V/16MHz
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000e", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
## dog hunter AG
|
||||||
|
### Leonardo
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
### Micro
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
|
||||||
|
# hid_listen
|
||||||
|
KERNEL=="hidraw*", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
Files: *
|
||||||
|
Copyright: 2019-2021 Zach White, et al
|
||||||
|
License: expat
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=t1lg
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
"""A program to help you work with qmk_firmware."""
|
"""A program to help you work with qmk_firmware."""
|
||||||
|
|
||||||
__version__ = '0.3.0'
|
__version__ = '0.2.2'
|
||||||
|
|||||||
@@ -3,6 +3,5 @@
|
|||||||
We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup.
|
We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup.
|
||||||
"""
|
"""
|
||||||
from . import clone # noqa
|
from . import clone # noqa
|
||||||
from . import console # noqa
|
|
||||||
from . import env # noqa
|
from . import env # noqa
|
||||||
from . import setup # noqa
|
from . import setup # noqa
|
||||||
|
|||||||
@@ -1,358 +0,0 @@
|
|||||||
"""Acquire debugging information from usb hid devices
|
|
||||||
|
|
||||||
cli implementation of https://www.pjrc.com/teensy/hid_listen.html
|
|
||||||
"""
|
|
||||||
from functools import lru_cache
|
|
||||||
from pathlib import Path
|
|
||||||
from platform import platform
|
|
||||||
from threading import Thread
|
|
||||||
from time import sleep, strftime
|
|
||||||
|
|
||||||
from milc import cli
|
|
||||||
from milc.questions import yesno
|
|
||||||
|
|
||||||
LOG_COLOR = {
|
|
||||||
'next': 0,
|
|
||||||
'colors': [
|
|
||||||
'{fg_blue}',
|
|
||||||
'{fg_cyan}',
|
|
||||||
'{fg_green}',
|
|
||||||
'{fg_magenta}',
|
|
||||||
'{fg_red}',
|
|
||||||
'{fg_yellow}',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
KNOWN_BOOTLOADERS = {
|
|
||||||
# VID , PID
|
|
||||||
('03EB', '2FEF'): 'atmel-dfu: ATmega16U2',
|
|
||||||
('03EB', '2FF0'): 'atmel-dfu: ATmega32U2',
|
|
||||||
('03EB', '2FF3'): 'atmel-dfu: ATmega16U4',
|
|
||||||
('03EB', '2FF4'): 'atmel-dfu: ATmega32U4',
|
|
||||||
('03EB', '2FF9'): 'atmel-dfu: AT90USB64',
|
|
||||||
('03EB', '2FFA'): 'atmel-dfu: AT90USB162',
|
|
||||||
('03EB', '2FFB'): 'atmel-dfu: AT90USB128',
|
|
||||||
('03EB', '6124'): 'Microchip SAM-BA',
|
|
||||||
('0483', 'DF11'): 'stm32-dfu: STM32 BOOTLOADER',
|
|
||||||
('16C0', '05DC'): 'USBasp: USBaspLoader',
|
|
||||||
('16C0', '05DF'): 'bootloadHID: HIDBoot',
|
|
||||||
('16C0', '0478'): 'halfkay: Teensy Halfkay',
|
|
||||||
('1B4F', '9203'): 'caterina: Pro Micro 3.3V',
|
|
||||||
('1B4F', '9205'): 'caterina: Pro Micro 5V',
|
|
||||||
('1B4F', '9207'): 'caterina: LilyPadUSB',
|
|
||||||
('1C11', 'B007'): 'kiibohd: Kiibohd DFU Bootloader',
|
|
||||||
('1EAF', '0003'): 'stm32duino: Maple 003',
|
|
||||||
('1FFB', '0101'): 'caterina: Polou A-Star 32U4 Bootloader',
|
|
||||||
('2341', '0036'): 'caterina: Arduino Leonardo',
|
|
||||||
('2341', '0037'): 'caterina: Arduino Micro',
|
|
||||||
('239A', '000C'): 'caterina: Adafruit Feather 32U4',
|
|
||||||
('239A', '000D'): 'caterina: Adafruit ItsyBitsy 32U4 3v',
|
|
||||||
('239A', '000E'): 'caterina: Adafruit ItsyBitsy 32U4 5v',
|
|
||||||
('239A', '000E'): 'caterina: Adafruit ItsyBitsy 32U4 5v',
|
|
||||||
('2A03', '0036'): 'caterina: Arduino Leonardo',
|
|
||||||
('2A03', '0037'): 'caterina: Arduino Micro',
|
|
||||||
('314B', '0106'): 'apm32-dfu: APM32 DFU ISP Mode'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def install_deps():
|
|
||||||
"""Install the necessary dependencies for qmk console.
|
|
||||||
"""
|
|
||||||
this_platform = platform().lower()
|
|
||||||
|
|
||||||
if 'darwin' in this_platform or 'macos' in this_platform:
|
|
||||||
command = ['brew', 'install', 'hidapi']
|
|
||||||
elif 'linux' in this_platform:
|
|
||||||
command = ['sudo', 'apt', 'install', '-y', 'libhidapi-hidraw0', 'libusb-dev']
|
|
||||||
elif 'windows' in this_platform:
|
|
||||||
command = ['pacboy', 'sync', '--needed', '--noconfirm', '--disable-download-timeout', 'hidapi:x']
|
|
||||||
else:
|
|
||||||
cli.log.error('Unsupported platform: %s', this_platform)
|
|
||||||
|
|
||||||
if yesno("Would you like to run `%s` to install the necessary package?", ' '.join(command)):
|
|
||||||
cli.run(command, capture_output=False)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=0)
|
|
||||||
def import_usb_core():
|
|
||||||
"""Attempts to import the usb.core module.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
import usb.core
|
|
||||||
return usb.core
|
|
||||||
|
|
||||||
except ImportError as e:
|
|
||||||
cli.log.error('Could not import usb.core: %s', e)
|
|
||||||
|
|
||||||
if install_deps():
|
|
||||||
return import_usb_core()
|
|
||||||
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def import_hid():
|
|
||||||
"""Attempts to import the hid module.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
import hid
|
|
||||||
return hid
|
|
||||||
|
|
||||||
except ImportError as e:
|
|
||||||
cli.log.error('Could not import hid: %s', e)
|
|
||||||
|
|
||||||
if install_deps():
|
|
||||||
return import_hid()
|
|
||||||
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
class MonitorDevice(object):
|
|
||||||
def __init__(self, hid_device, numeric):
|
|
||||||
self.hid = import_hid()
|
|
||||||
self.hid_device = hid_device
|
|
||||||
self.numeric = numeric
|
|
||||||
self.device = self.hid.Device(path=hid_device['path'])
|
|
||||||
self.current_line = ''
|
|
||||||
|
|
||||||
cli.log.info('Console Connected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', hid_device)
|
|
||||||
|
|
||||||
def read(self, size, encoding='ascii', timeout=1):
|
|
||||||
"""Read size bytes from the device.
|
|
||||||
"""
|
|
||||||
return self.device.read(size, timeout).decode(encoding)
|
|
||||||
|
|
||||||
def read_line(self):
|
|
||||||
"""Read from the device's console until we get a \n.
|
|
||||||
"""
|
|
||||||
while '\n' not in self.current_line:
|
|
||||||
self.current_line += self.read(32).replace('\x00', '')
|
|
||||||
|
|
||||||
lines = self.current_line.split('\n', 1)
|
|
||||||
self.current_line = lines[1]
|
|
||||||
|
|
||||||
return lines[0]
|
|
||||||
|
|
||||||
def run_forever(self):
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
message = {**self.hid_device, 'text': self.read_line()}
|
|
||||||
identifier = (int2hex(message['vendor_id']), int2hex(message['product_id'])) if self.numeric else (message['manufacturer_string'], message['product_string'])
|
|
||||||
message['identifier'] = ':'.join(identifier)
|
|
||||||
message['ts'] = '{style_dim}{fg_green}%s{style_reset_all} ' % (strftime(cli.config.general.datetime_fmt),) if cli.args.timestamp else ''
|
|
||||||
|
|
||||||
cli.echo('%(ts)s%(color)s%(identifier)s:%(index)d{style_reset_all}: %(text)s' % message)
|
|
||||||
|
|
||||||
except self.hid.HIDException:
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
class FindDevices(object):
|
|
||||||
def __init__(self, vid, pid, index, numeric):
|
|
||||||
self.hid = import_hid()
|
|
||||||
self.vid = vid
|
|
||||||
self.pid = pid
|
|
||||||
self.index = index
|
|
||||||
self.numeric = numeric
|
|
||||||
|
|
||||||
def run_forever(self):
|
|
||||||
"""Process messages from our queue in a loop.
|
|
||||||
"""
|
|
||||||
live_devices = {}
|
|
||||||
live_bootloaders = {}
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
for device in list(live_devices):
|
|
||||||
if not live_devices[device]['thread'].is_alive():
|
|
||||||
cli.log.info('Console Disconnected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', live_devices[device])
|
|
||||||
del live_devices[device]
|
|
||||||
|
|
||||||
for device in self.find_devices():
|
|
||||||
if device['path'] not in live_devices:
|
|
||||||
device['color'] = LOG_COLOR['colors'][LOG_COLOR['next']]
|
|
||||||
LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors'])
|
|
||||||
live_devices[device['path']] = device
|
|
||||||
|
|
||||||
try:
|
|
||||||
monitor = MonitorDevice(device, self.numeric)
|
|
||||||
device['thread'] = Thread(target=monitor.run_forever, daemon=True)
|
|
||||||
|
|
||||||
device['thread'].start()
|
|
||||||
except Exception as e:
|
|
||||||
device['e'] = e
|
|
||||||
device['e_name'] = e.__class__.__name__
|
|
||||||
cli.log.error("Could not connect to %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s:%(vendor_id)04X:%(product_id)04X:%(index)d): %(e_name)s: %(e)s", device)
|
|
||||||
if cli.config.general.verbose:
|
|
||||||
cli.log.exception(e)
|
|
||||||
del live_devices[device['path']]
|
|
||||||
|
|
||||||
if cli.args.bootloaders:
|
|
||||||
for device in self.find_bootloaders():
|
|
||||||
if device.address in live_bootloaders:
|
|
||||||
live_bootloaders[device.address]._qmk_found = True
|
|
||||||
else:
|
|
||||||
name = KNOWN_BOOTLOADERS[(int2hex(device.idVendor), int2hex(device.idProduct))]
|
|
||||||
cli.log.info('Bootloader Connected: {style_bright}{fg_magenta}%s', name)
|
|
||||||
device._qmk_found = True
|
|
||||||
live_bootloaders[device.address] = device
|
|
||||||
|
|
||||||
for device in list(live_bootloaders):
|
|
||||||
if live_bootloaders[device]._qmk_found:
|
|
||||||
live_bootloaders[device]._qmk_found = False
|
|
||||||
else:
|
|
||||||
name = KNOWN_BOOTLOADERS[(int2hex(live_bootloaders[device].idVendor), int2hex(live_bootloaders[device].idProduct))]
|
|
||||||
cli.log.info('Bootloader Disconnected: {style_bright}{fg_magenta}%s', name)
|
|
||||||
del live_bootloaders[device]
|
|
||||||
|
|
||||||
sleep(.1)
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
break
|
|
||||||
|
|
||||||
def is_bootloader(self, hid_device):
|
|
||||||
"""Returns true if the device in question matches a known bootloader vid/pid.
|
|
||||||
"""
|
|
||||||
return (int2hex(hid_device.idVendor), int2hex(hid_device.idProduct)) in KNOWN_BOOTLOADERS
|
|
||||||
|
|
||||||
def is_console_hid(self, hid_device):
|
|
||||||
"""Returns true when the usage page indicates it's a teensy-style console.
|
|
||||||
"""
|
|
||||||
return hid_device['usage_page'] == 0xFF31 and hid_device['usage'] == 0x0074
|
|
||||||
|
|
||||||
def is_filtered_device(self, hid_device):
|
|
||||||
"""Returns True if the device should be included in the list of available consoles.
|
|
||||||
"""
|
|
||||||
return int2hex(hid_device['vendor_id']) == self.vid and int2hex(hid_device['product_id']) == self.pid
|
|
||||||
|
|
||||||
def find_devices_by_report(self, hid_devices):
|
|
||||||
"""Returns a list of available teensy-style consoles by doing a brute-force search.
|
|
||||||
|
|
||||||
Some versions of linux don't report usage and usage_page. In that case we fallback to reading the report (possibly inaccurately) ourselves.
|
|
||||||
"""
|
|
||||||
devices = []
|
|
||||||
|
|
||||||
for device in hid_devices:
|
|
||||||
path = device['path'].decode('utf-8')
|
|
||||||
|
|
||||||
if path.startswith('/dev/hidraw'):
|
|
||||||
number = path[11:]
|
|
||||||
report = Path(f'/sys/class/hidraw/hidraw{number}/device/report_descriptor')
|
|
||||||
|
|
||||||
if report.exists():
|
|
||||||
rp = report.read_bytes()
|
|
||||||
|
|
||||||
if rp[1] == 0x31 and rp[3] == 0x09:
|
|
||||||
devices.append(device)
|
|
||||||
|
|
||||||
return devices
|
|
||||||
|
|
||||||
def find_bootloaders(self):
|
|
||||||
"""Returns a list of available bootloader devices.
|
|
||||||
"""
|
|
||||||
import usb.core
|
|
||||||
|
|
||||||
return list(filter(self.is_bootloader, usb.core.find(find_all=True)))
|
|
||||||
|
|
||||||
def find_devices(self):
|
|
||||||
"""Returns a list of available teensy-style consoles.
|
|
||||||
"""
|
|
||||||
hid_devices = self.hid.enumerate()
|
|
||||||
devices = list(filter(self.is_console_hid, hid_devices))
|
|
||||||
|
|
||||||
if not devices:
|
|
||||||
devices = self.find_devices_by_report(hid_devices)
|
|
||||||
|
|
||||||
if self.vid and self.pid:
|
|
||||||
devices = list(filter(self.is_filtered_device, devices))
|
|
||||||
|
|
||||||
# Add index numbers
|
|
||||||
device_index = {}
|
|
||||||
for device in devices:
|
|
||||||
id = ':'.join((int2hex(device['vendor_id']), int2hex(device['product_id'])))
|
|
||||||
|
|
||||||
if id not in device_index:
|
|
||||||
device_index[id] = 0
|
|
||||||
|
|
||||||
device_index[id] += 1
|
|
||||||
device['index'] = device_index[id]
|
|
||||||
|
|
||||||
return devices
|
|
||||||
|
|
||||||
|
|
||||||
def int2hex(number):
|
|
||||||
"""Returns a string representation of the number as hex.
|
|
||||||
"""
|
|
||||||
return "%04X" % number
|
|
||||||
|
|
||||||
|
|
||||||
def list_devices(device_finder):
|
|
||||||
"""Show the user a nicely formatted list of devices.
|
|
||||||
"""
|
|
||||||
devices = device_finder.find_devices()
|
|
||||||
|
|
||||||
if devices:
|
|
||||||
cli.log.info('Available devices:')
|
|
||||||
for dev in devices:
|
|
||||||
color = LOG_COLOR['colors'][LOG_COLOR['next']]
|
|
||||||
LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors'])
|
|
||||||
cli.log.info("\t%s%s:%s:%d{style_reset_all}\t%s %s", color, int2hex(dev['vendor_id']), int2hex(dev['product_id']), dev['index'], dev['manufacturer_string'], dev['product_string'])
|
|
||||||
|
|
||||||
if cli.args.bootloaders:
|
|
||||||
bootloaders = device_finder.find_bootloaders()
|
|
||||||
|
|
||||||
if bootloaders:
|
|
||||||
cli.log.info('Available Bootloaders:')
|
|
||||||
|
|
||||||
for dev in bootloaders:
|
|
||||||
cli.log.info("\t%s:%s\t%s", int2hex(dev.idVendor), int2hex(dev.idProduct), KNOWN_BOOTLOADERS[(int2hex(dev.idVendor), int2hex(dev.idProduct))])
|
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('--bootloaders', arg_only=True, default=True, action='store_boolean', help='displaying bootloaders.')
|
|
||||||
@cli.argument('-d', '--device', help='Device to select - uses format <pid>:<vid>[:<index>].')
|
|
||||||
@cli.argument('-l', '--list', arg_only=True, action='store_true', help='List available hid_listen devices.')
|
|
||||||
@cli.argument('-n', '--numeric', arg_only=True, action='store_true', help='Show VID/PID instead of names.')
|
|
||||||
@cli.argument('-t', '--timestamp', arg_only=True, action='store_true', help='Print the timestamp for received messages as well.')
|
|
||||||
@cli.argument('-w', '--wait', type=int, default=1, help="How many seconds to wait between checks (Default: 1)")
|
|
||||||
@cli.subcommand('Acquire debugging information from usb hid devices.')
|
|
||||||
def console(cli):
|
|
||||||
"""Acquire debugging information from usb hid devices
|
|
||||||
"""
|
|
||||||
vid = None
|
|
||||||
pid = None
|
|
||||||
index = 1
|
|
||||||
|
|
||||||
if cli.config.console.device:
|
|
||||||
device = cli.config.console.device.split(':')
|
|
||||||
|
|
||||||
if len(device) == 2:
|
|
||||||
vid, pid = device
|
|
||||||
|
|
||||||
elif len(device) == 3:
|
|
||||||
vid, pid, index = device
|
|
||||||
|
|
||||||
if not index.isdigit():
|
|
||||||
cli.log.error('Device index must be a number! Got "%s" instead.', index)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
index = int(index)
|
|
||||||
|
|
||||||
if index < 1:
|
|
||||||
cli.log.error('Device index must be greater than 0! Got %s', index)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
else:
|
|
||||||
cli.log.error('Invalid format for device, expected "<pid>:<vid>[:<index>]" but got "%s".', cli.config.console.device)
|
|
||||||
cli.print_help()
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
vid = vid.upper()
|
|
||||||
pid = pid.upper()
|
|
||||||
|
|
||||||
device_finder = FindDevices(vid, pid, index, cli.args.numeric)
|
|
||||||
|
|
||||||
if cli.args.list:
|
|
||||||
return list_devices(device_finder)
|
|
||||||
|
|
||||||
print('Looking for devices...', flush=True)
|
|
||||||
device_finder.run_forever()
|
|
||||||
@@ -22,6 +22,7 @@ requests-toolbelt==0.9.1
|
|||||||
rfc3986==1.5.0
|
rfc3986==1.5.0
|
||||||
SecretStorage==3.3.1
|
SecretStorage==3.3.1
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
|
stdeb==0.10.0
|
||||||
tqdm==4.62.0
|
tqdm==4.62.0
|
||||||
twine==3.4.2
|
twine==3.4.2
|
||||||
urllib3==1.26.6
|
urllib3==1.26.6
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
[global]
|
||||||
|
command-packages: stdeb.command
|
||||||
|
|
||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.3.0
|
current_version = 0.2.2
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
tag_name = {new_version}
|
tag_name = {new_version}
|
||||||
@@ -12,6 +15,9 @@ message = New release: {current_version} → {new_version}
|
|||||||
[bdist_wheel]
|
[bdist_wheel]
|
||||||
universal = 1
|
universal = 1
|
||||||
|
|
||||||
|
[entry_points]
|
||||||
|
qmk = qmk_cli.script_qmk:main
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = E501,E226
|
ignore = E501,E226
|
||||||
|
|
||||||
@@ -22,11 +28,24 @@ description-file = README.md
|
|||||||
dist-name = qmk
|
dist-name = qmk
|
||||||
license_file = LICENSE
|
license_file = LICENSE
|
||||||
module = qmk_cli
|
module = qmk_cli
|
||||||
home-page = https://github.com/qmk/qmk_cli
|
home-page = https://qmk.fm/
|
||||||
requires-python = >=3.7
|
requires-python = >=3.7
|
||||||
|
|
||||||
[entry_points]
|
[sdist_dsc]
|
||||||
qmk = qmk_cli.script_qmk:main
|
# Configuration for the Debian package
|
||||||
|
with-python2: False
|
||||||
|
with-python3: True
|
||||||
|
with-dh-virtualenv: True
|
||||||
|
sign-results: True
|
||||||
|
compat: 10
|
||||||
|
suite3: stable
|
||||||
|
package3: qmk
|
||||||
|
maintainer: QMK Firmware (Official QMK GPG Signing Key) <hello@qmk.fm>
|
||||||
|
section: devel
|
||||||
|
depends3: build-essential, clang-format, diffutils, gcc, git, unzip, wget, zip, python3-pip, binutils-avr, gcc-avr, avr-libc, binutils-arm-none-eabi, gcc-arm-none-eabi, libnewlib-arm-none-eabi, avrdude, dfu-programmer, dfu-util, teensy-loader-cli, libhidapi-hidraw0, libusb-dev
|
||||||
|
depends: build-essential, clang-format, diffutils, gcc, git, unzip, wget, zip, python3-pip, binutils-avr, gcc-avr, avr-libc, binutils-arm-none-eabi, gcc-arm-none-eabi, libnewlib-arm-none-eabi, avrdude, dfu-programmer, dfu-util, teensy-loader-cli, libhidapi-hidraw0, libusb-dev
|
||||||
|
x-python3-version: >= 3.7
|
||||||
|
udev-rules: debian/50-qmk.rules
|
||||||
|
|
||||||
[yapf]
|
[yapf]
|
||||||
align_closing_bracket_with_visual_indent = True
|
align_closing_bracket_with_visual_indent = True
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ if __name__ == "__main__":
|
|||||||
"jsonschema==3.2.0",
|
"jsonschema==3.2.0",
|
||||||
"log-symbols==0.0.14",
|
"log-symbols==0.0.14",
|
||||||
"mccabe==0.6.1",
|
"mccabe==0.6.1",
|
||||||
"milc==1.5.0",
|
"milc==1.4.2",
|
||||||
"nose2==0.10.0",
|
"nose2==0.10.0",
|
||||||
"pycodestyle==2.7.0",
|
"pycodestyle==2.7.0",
|
||||||
"pyflakes==2.3.1",
|
"pyflakes==2.3.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user