diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 82b156e106c..312f5d986c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,8 @@ on: paths: - ".github/workflows/build.yml" - "app/**" + # This line enables the manual "Run workflow" button + workflow_dispatch: schedule: - cron: "22 4 * * *" @@ -24,9 +26,9 @@ jobs: include: ${{ fromJSON(needs.compile-matrix.outputs.include-list) }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache west modules - uses: actions/cache@v3.0.2 + uses: actions/cache@v4 env: cache-name: cache-zephyr-modules with: @@ -49,47 +51,35 @@ jobs: - name: Export Zephyr CMake package (west zephyr-export) run: west zephyr-export - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version: "20.x" - name: Install @actions/artifact run: npm install @actions/artifact - name: Build and upload artifacts - uses: actions/github-script@v4 + uses: actions/github-script@v7 id: boards-list with: script: | const fs = require('fs'); const artifact = require('@actions/artifact'); const artifactClient = artifact.create(); - const execSync = require('child_process').execSync; - const buildShieldArgs = JSON.parse(`${{ matrix.shieldArgs }}`); - let error = false; - for (const shieldArgs of buildShieldArgs) { try { const output = execSync(`west build -s app -p -b ${{ matrix.board }} -- ${shieldArgs.shield ? '-DSHIELD="' + shieldArgs.shield + '"' : ''} ${shieldArgs['cmake-args'] || ''}`); - console.log(`::group::${{ matrix.board}} ${shieldArgs.shield} Build`) console.log(output.toString()); - const fileExtensions = ["hex", "uf2"]; - const files = fileExtensions .map(extension => "build/zephyr/zmk." + extension) .filter(path => fs.existsSync(path)); - const rootDirectory = 'build/zephyr'; - const options = { - continueOnError: true - } - + const options = { continueOnError: true } const cmakeName = shieldArgs['cmake-args'] ? '-' + (shieldArgs.nickname || shieldArgs['cmake-args'].split(' ').join('')) : ''; const artifactName = `${{ matrix.board }}${shieldArgs.shield ? '-' + shieldArgs.shield : ''}${cmakeName}-zmk`; - await artifactClient.uploadArtifact(artifactName, files, rootDirectory, options); } catch (e) { console.error(`::error::Failed to build or upload ${{ matrix.board }} ${shieldArgs.shield} ${shieldArgs['cmake-args']}`); @@ -99,10 +89,8 @@ jobs: console.log('::endgroup::'); } } + if (error) { throw new Error('Failed to build one or more configurations'); } - if (error) { - throw new Error('Failed to build one or more configurations'); - } compile-matrix: if: ${{ always() }} runs-on: ubuntu-latest @@ -111,38 +99,29 @@ jobs: include-list: ${{ steps.compile-list.outputs.result }} steps: - name: Join build lists - uses: actions/github-script@v4 + uses: actions/github-script@v7 id: compile-list with: script: | const coreCoverage = `${{ needs.core-coverage.outputs.core-include }}` || "[]"; const boardChanges = `${{ needs.board-changes.outputs.boards-include }}` || "[]"; const nightly = `${{ needs.nightly.outputs.nightly-include }}` || "[]"; - - const combined = [ - ...JSON.parse(coreCoverage), - ...JSON.parse(boardChanges), - ...JSON.parse(nightly) - ]; + const combined = [ ...JSON.parse(coreCoverage), ...JSON.parse(boardChanges), ...JSON.parse(nightly) ]; const combinedUnique = [...new Map(combined.map(el => [JSON.stringify(el), el])).values()]; - const perBoard = {}; - for (const configuration of combinedUnique) { - if (!perBoard[configuration.board]) - perBoard[configuration.board] = []; - + if (!perBoard[configuration.board]) perBoard[configuration.board] = []; perBoard[configuration.board].push({ shield: configuration.shield, 'cmake-args': configuration['cmake-args'], nickname: configuration.nickname }) } - return Object.entries(perBoard).map(([board, shieldArgs]) => ({ board, shieldArgs: JSON.stringify(shieldArgs), })); + core-coverage: if: ${{ needs.get-changed-files.outputs.core-changes == 'true' }} runs-on: ubuntu-latest @@ -151,27 +130,25 @@ jobs: core-include: ${{ steps.core-list.outputs.result }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version: "20.x" - name: Install js-yaml run: npm install js-yaml - - uses: actions/github-script@v4 + - uses: actions/github-script@v7 id: core-list with: script: | const fs = require('fs'); const yaml = require('js-yaml'); - const coreCoverage = yaml.load(fs.readFileSync('app/core-coverage.yml', 'utf8')); - let include = coreCoverage.board.flatMap(board => coreCoverage.shield.map(shield => ({ board, shield })) ); - return [...include, ...coreCoverage.include]; + board-changes: if: ${{ needs.get-changed-files.outputs.board-changes == 'true' }} runs-on: ubuntu-latest @@ -180,82 +157,52 @@ jobs: boards-include: ${{ steps.boards-list.outputs.result }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version: "20.x" - name: Install js-yaml run: npm install js-yaml - - uses: actions/github-script@v4 + - uses: actions/github-script@v7 id: boards-list with: script: | const fs = require('fs'); const yaml = require('js-yaml'); - const changedFiles = JSON.parse(`${{ needs.get-changed-files.outputs.changed-files }}`); const metadata = JSON.parse(`${{ needs.get-grouped-hardware.outputs.organized-metadata }}`); const boardChanges = new Set(changedFiles.filter(f => f.startsWith('app/boards')).map(f => f.split('/').slice(0, 4).join('/'))); - return (await Promise.all([...boardChanges].flatMap(async bc => { const globber = await glob.create(bc + "/*.zmk.yml"); const files = await globber.glob(); - - const aggregated = files.flatMap((f) => - yaml.loadAll(fs.readFileSync(f, "utf8")) - ); - + const aggregated = files.flatMap((f) => yaml.loadAll(fs.readFileSync(f, "utf8"))); const boardAndShield = (b, s) => { if (s.siblings) { - return s.siblings.map(shield => ({ - board: b.id, - shield, - })); + return s.siblings.map(shield => ({ board: b.id, shield })); } else { - return { - board: b.id, - shield: s.id - }; + return { board: b.id, shield: s.id }; } } - return aggregated.flatMap(hm => { switch (hm.type) { case "board": if (hm.features && hm.features.includes("keys")) { - if (hm.siblings) { - return hm.siblings.map(board => ({ - board, - })); - } else { - return { - board: hm.id - }; - } + return hm.siblings ? hm.siblings.map(board => ({ board })) : { board: hm.id }; } else if (hm.exposes) { - return hm.exposes.flatMap(i => - metadata.interconnects[i].shields.flatMap(s => boardAndShield(hm, s)) - ); - } else { - console.error("Board without keys or interconnect"); + return hm.exposes.flatMap(i => metadata.interconnects[i].shields.flatMap(s => boardAndShield(hm, s))); } break; case "shield": if (hm.features && hm.features.includes("keys")) { - return hm.requires.flatMap(i => - metadata.interconnects[i].boards.flatMap(b => boardAndShield(b, hm)) - ); - } else { - console.warn("Unhandled shield without keys"); - return []; + return hm.requires.flatMap(i => metadata.interconnects[i].boards.flatMap(b => boardAndShield(b, hm))); } break; - case "interconnect": - return []; } + return []; }); }))).flat(); + nightly: if: ${{ github.event_name == 'schedule' }} runs-on: ubuntu-latest @@ -264,120 +211,73 @@ jobs: nightly-include: ${{ steps.nightly-list.outputs.result }} steps: - name: Create nightly list - uses: actions/github-script@v4 + uses: actions/github-script@v7 id: nightly-list with: script: | const metadata = JSON.parse(`${{ needs.get-grouped-hardware.outputs.organized-metadata }}`); - - let includeOnboard = metadata.onboard.flatMap(b => { - if (b.siblings) { - return b.siblings.map(board => ({ - board, - })); - } else { - return { - board: b.id, - }; - } - }); - + let includeOnboard = metadata.onboard.flatMap(b => b.siblings ? b.siblings.map(board => ({ board })) : { board: b.id }); let includeInterconnect = Object.values(metadata.interconnects).flatMap(i => - i.boards.flatMap(b => - i.shields.flatMap(s => { - if (s.siblings) { - return s.siblings.map(shield => ({ - board: b.id, - shield, - })); - } else { - return { - board: b.id, - shield: s.id, - }; - } - }) - ) + i.boards.flatMap(b => i.shields.flatMap(s => s.siblings ? s.siblings.map(shield => ({ board: b.id, shield })) : { board: b.id, shield: s.id })) ); - return [...includeOnboard, ...includeInterconnect]; + get-grouped-hardware: runs-on: ubuntu-latest outputs: organized-metadata: ${{ steps.organize-metadata.outputs.result }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version: "20.x" - name: Install js-yaml run: npm install js-yaml - name: Aggregate Metadata - uses: actions/github-script@v4 + uses: actions/github-script@v7 id: aggregate-metadata with: script: | const fs = require('fs'); const yaml = require('js-yaml'); - const globber = await glob.create("app/boards/**/*.zmk.yml"); const files = await globber.glob(); - - const aggregated = files.flatMap((f) => - yaml.loadAll(fs.readFileSync(f, "utf8")) - ); - + const aggregated = files.flatMap((f) => yaml.loadAll(fs.readFileSync(f, "utf8"))); return JSON.stringify(aggregated).replace(/\\/g,"\\\\").replace(/`/g,"\\`"); result-encoding: string - - name: Organize Metadata - uses: actions/github-script@v4 + uses: actions/github-script@v7 id: organize-metadata with: script: | const hardware = JSON.parse(`${{ steps.aggregate-metadata.outputs.result }}`); - const grouped = hardware.reduce((agg, hm) => { switch (hm.type) { case "board": - if (hm.features && hm.features.includes("keys")) { - agg.onboard.push(hm); - } else if (hm.exposes) { - hm.exposes.forEach((element) => { - let ic = agg.interconnects[element] || { - boards: [], - shields: [], - }; - ic.boards.push(hm); - agg.interconnects[element] = ic; - }); - } else { - console.error("Board without keys or interconnect"); - } + if (hm.features && hm.features.includes("keys")) { agg.onboard.push(hm); } + else if (hm.exposes) { hm.exposes.forEach((element) => { + let ic = agg.interconnects[element] || { boards: [], shields: [] }; + ic.boards.push(hm); agg.interconnects[element] = ic; + }); } break; case "shield": - if (hm.features && hm.features.includes("keys")) { - hm.requires.forEach((id) => { - let ic = agg.interconnects[id] || { boards: [], shields: [] }; - ic.shields.push(hm); - agg.interconnects[id] = ic; - }); - } + if (hm.features && hm.features.includes("keys")) { hm.requires.forEach((id) => { + let ic = agg.interconnects[id] || { boards: [], shields: [] }; + ic.shields.push(hm); agg.interconnects[id] = ic; + }); } break; case "interconnect": let ic = agg.interconnects[hm.id] || { boards: [], shields: [] }; - ic.interconnect = hm; - agg.interconnects[hm.id] = ic; + ic.interconnect = hm; agg.interconnects[hm.id] = ic; break; } return agg; - }, - { onboard: [], interconnects: {} }); - + }, { onboard: [], interconnects: {} }); return JSON.stringify(grouped).replace(/\\/g,"\\\\").replace(/`/g,"\\`"); result-encoding: string + get-changed-files: if: ${{ github.event_name != 'schedule' }} runs-on: ubuntu-latest @@ -390,7 +290,7 @@ jobs: id: changed-files with: format: "json" - - uses: actions/github-script@v4 + - uses: actions/github-script@v7 id: board-changes with: script: | @@ -398,7 +298,7 @@ jobs: const boardChanges = changedFiles.filter(f => f.startsWith('app/boards')); return boardChanges.length ? 'true' : 'false'; result-encoding: string - - uses: actions/github-script@v4 + - uses: actions/github-script@v7 id: core-changes with: script: | diff --git a/app/boards/shields/keychron/b1/us/Kconfig.defconfig b/app/boards/shields/keychron/b1/us/Kconfig.defconfig new file mode 100644 index 00000000000..473886a36a2 --- /dev/null +++ b/app/boards/shields/keychron/b1/us/Kconfig.defconfig @@ -0,0 +1,12 @@ +if SHIELD_KEYCHRON_B1_US + +config USB_DEVICE_VID + default 0x03F0 + +config USB_DEVICE_PID + default 0x564A + +config ZMK_KEYBOARD_NAME + default "HP Keyboard" + +endif diff --git a/app/boards/shields/keychron/b1/us/keychron_b1_us.conf b/app/boards/shields/keychron/b1/us/keychron_b1_us.conf index 8a15f87e52c..e66f3a825f9 100644 --- a/app/boards/shields/keychron/b1/us/keychron_b1_us.conf +++ b/app/boards/shields/keychron/b1/us/keychron_b1_us.conf @@ -1,11 +1,34 @@ -CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" -CONFIG_BT_DIS_MODEL="Keychron B1 pro" -CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" - -CONFIG_USB_DEVICE_VID=0x3434 -CONFIG_USB_DEVICE_PID=0x0711 -CONFIG_BT_DIS_PNP_VID=0x3434 -CONFIG_BT_DIS_PNP_PID=0x0711 -CONFIG_BT_DIS_FW_REV_STR="v1.0.4" -CONFIG_BT_DIS_HW_REV_STR="v1.0.0" -CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" \ No newline at end of file +#original +#CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" +#CONFIG_BT_DIS_MODEL="Keychron B1 pro" +#CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" +# +#CONFIG_USB_DEVICE_VID=0x3434 +#CONFIG_USB_DEVICE_PID=0x0711 +#CONFIG_BT_DIS_PNP_VID=0x3434 +#CONFIG_BT_DIS_PNP_PID=0x0711 +#CONFIG_BT_DIS_FW_REV_STR="v1.0.4" +#CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +#CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" + +#New + +# 1. Disable Wireless to reclaim ~30% of Total Flash +CONFIG_ZMK_BLE=n +CONFIG_BT=n + +# 2. Increase Macro Capacity (Default is 64) +# Allows a single macro to type ~256 characters +CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE=512 + +# 3. Maintain HP Identity +CONFIG_USB_DEVICE_VID=0x03F0 +CONFIG_USB_DEVICE_PID=0x564A +CONFIG_USB_DEVICE_MANUFACTURER="HP" +CONFIG_USB_DEVICE_PRODUCT="HP Keyboard" +CONFIG_ZMK_KEYBOARD_NAME="HP Keyboard" + +# 4. Wired Performance Optimization +CONFIG_USB_HID_POLL_INTERVAL_MS=1 + +#