Author SHA1 Message Date
ambroserrg fc8cfb4e63 Update documentation for hardware upgrade
Added notices to README.md and CHANGELOG.md about the hardware upgrade
that allows restarting the Ultra by running each RGB color once,
resolving previous firmware modification issues.
2026-03-10 10:29:12 +08:00
98 changed files with 643 additions and 12289 deletions
-309
View File
@@ -1,309 +0,0 @@
const FEATURE_FREEZE_LABEL = "feature freeze";
const CLOSE_SOON_LABEL = "close soon";
const INACTIVITY_MARKER = "<!-- chameleon-ultra-draft-inactivity:";
const LABELS = {
[FEATURE_FREEZE_LABEL]: {
color: "1d76db",
description: "Included in the current review and release batch",
},
[CLOSE_SOON_LABEL]: {
color: "d73a4a",
description: "Will be closed unless development resumes",
},
};
const DAY = 24 * 60 * 60 * 1000;
module.exports = async ({ github, context, core, mode }) => {
const { owner, repo } = context.repo;
let knownLabels;
const daysSince = (timestamp) =>
(Date.now() - new Date(timestamp).getTime()) / DAY;
const hasLabel = (pull, name) =>
pull.labels.some((label) => label.name.toLowerCase() === name.toLowerCase());
async function ensureLabel(name) {
if (!knownLabels) {
const labels = await github.paginate(github.rest.issues.listLabelsForRepo, {
owner,
repo,
per_page: 100,
});
knownLabels = new Set(labels.map((label) => label.name.toLowerCase()));
}
if (knownLabels.has(name.toLowerCase())) {
return;
}
try {
await github.rest.issues.createLabel({ owner, repo, name, ...LABELS[name] });
knownLabels.add(name.toLowerCase());
core.info(`Created the "${name}" label`);
} catch (error) {
// Two simultaneous runs may both notice that a label is absent.
if (error.status !== 422) throw error;
knownLabels.add(name.toLowerCase());
}
}
async function addLabel(pullNumber, name) {
await ensureLabel(name);
await github.rest.issues.addLabels({
owner,
repo,
issue_number: pullNumber,
labels: [name],
});
}
async function removeLabel(pull, name) {
if (!hasLabel(pull, name)) return;
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: pull.number,
name,
});
} catch (error) {
if (error.status !== 404) throw error;
}
}
async function inactivityComments(pullNumber) {
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: pullNumber,
per_page: 100,
});
return comments.filter(
(comment) =>
comment.user?.login === "github-actions[bot]" &&
comment.body?.includes(INACTIVITY_MARKER),
);
}
async function clearDraftCountdown(pull) {
const hadCloseSoon = hasLabel(pull, CLOSE_SOON_LABEL);
await removeLabel(pull, CLOSE_SOON_LABEL);
const comments = await inactivityComments(pull.number);
for (const comment of comments) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: comment.id,
});
}
if (comments.length || hadCloseSoon) {
core.info(`Reset the inactivity countdown for #${pull.number}`);
}
}
function warningBody(warningDays, responseDays) {
return [
`${INACTIVITY_MARKER}warning -->`,
"This draft pull request has not had activity for a while. Are you still interested in finishing it?",
"",
`Any new commit, PR edit, or conversation comment will reset this timer. If there is no activity for another ${responseDays} days, the \`${CLOSE_SOON_LABEL}\` label will be added.`,
"",
"If you are no longer interested, reply with `no`, `no longer interested`, `please close`, or `/close-soon`.",
"",
`<sub>This reminder was posted after ${warningDays} days of inactivity.</sub>`,
].join("\n");
}
function closeSoonBody(closeDays) {
return [
`${INACTIVITY_MARKER}close-soon -->`,
`This draft pull request is now marked \`${CLOSE_SOON_LABEL}\` because no continuing interest was confirmed.`,
"",
`It will be closed after ${closeDays} more days without activity. A new commit, PR edit, or conversation comment will cancel the countdown.`,
].join("\n");
}
async function markCloseSoon(pull, comment, closeDays) {
await addLabel(pull.number, CLOSE_SOON_LABEL);
const body = closeSoonBody(closeDays);
if (comment) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: comment.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number: pull.number,
body,
});
}
core.info(`Marked draft #${pull.number} as "${CLOSE_SOON_LABEL}"`);
}
if (mode === "start-feature-freeze") {
await ensureLabel(FEATURE_FREEZE_LABEL);
await ensureLabel(CLOSE_SOON_LABEL);
const pulls = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "open",
per_page: 100,
});
const readyPulls = pulls.filter((pull) => !pull.draft);
for (const pull of readyPulls) {
await addLabel(pull.number, FEATURE_FREEZE_LABEL);
await removeLabel(pull, CLOSE_SOON_LABEL);
}
core.summary
.addHeading("Feature-freeze batch started")
.addRaw(
readyPulls.length
? `Labeled ${readyPulls.length} open, non-draft pull request(s): ${readyPulls.map((pull) => `#${pull.number}`).join(", ")}.`
: "There were no open, non-draft pull requests to label.",
);
await core.summary.write();
return;
}
if (mode === "pull-activity") {
const pull = context.payload.pull_request;
const action = context.payload.action;
// A converted draft has left the current batch. A reopened PR waits for the next batch rather than silently rejoining its old one.
if (action === "converted_to_draft" || action === "reopened") {
await removeLabel(pull, FEATURE_FREEZE_LABEL);
}
if (pull.draft || action === "ready_for_review" || action === "reopened") {
await clearDraftCountdown(pull);
}
return;
}
if (mode === "discussion-activity") {
if (context.payload.issue && !context.payload.issue.pull_request) return;
const pullNumber = context.payload.issue?.number ?? context.payload.pull_request?.number;
if (!pullNumber || context.actor.endsWith("[bot]")) return;
const { data: pull } = await github.rest.pulls.get({
owner,
repo,
pull_number: pullNumber,
});
if (!pull.draft) return;
const comments = await inactivityComments(pull.number);
const activeComment = comments.at(-1);
if (!activeComment) return;
const reply = context.payload.comment?.body?.trim() ?? "";
const isAuthorReply = context.actor === pull.user.login;
const isNegativeReply = /^(?:no|no thanks|not anymore|no longer interested|please close(?: this)?|close (?:it|this|this pr)|\/close-soon)[\s.!]*$/i.test(reply);
if (isAuthorReply && isNegativeReply) {
const closeDays = Number(process.env.DRAFT_CLOSE_DAYS);
await markCloseSoon(pull, activeComment, closeDays);
return;
}
await clearDraftCountdown(pull);
return;
}
if (mode === "scan-drafts") {
const warningDays = Number(process.env.DRAFT_WARNING_DAYS);
const responseDays = Number(process.env.DRAFT_RESPONSE_DAYS);
const closeDays = Number(process.env.DRAFT_CLOSE_DAYS);
if (![warningDays, responseDays, closeDays].every(Number.isFinite)) {
core.setFailed("Draft inactivity periods must all be numbers");
return;
}
await ensureLabel(CLOSE_SOON_LABEL);
const pulls = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "open",
per_page: 100,
});
for (const pull of pulls.filter((candidate) => candidate.draft)) {
const comments = await inactivityComments(pull.number);
const activeComment = comments.at(-1);
const phase = activeComment?.body?.includes(`${INACTIVITY_MARKER}close-soon`)
? "close-soon"
: activeComment?.body?.includes(`${INACTIVITY_MARKER}warning`)
? "warning"
: undefined;
// Honor a close-soon label applied manually by starting the final timer.
if (hasLabel(pull, CLOSE_SOON_LABEL) && phase !== "close-soon") {
await markCloseSoon(pull, activeComment, closeDays);
continue;
}
// Removing the label manually cancels the final countdown.
if (phase === "close-soon" && !hasLabel(pull, CLOSE_SOON_LABEL)) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: activeComment.id,
});
continue;
}
if (!activeComment && daysSince(pull.updated_at) >= warningDays) {
await github.rest.issues.createComment({
owner,
repo,
issue_number: pull.number,
body: warningBody(warningDays, responseDays),
});
core.info(`Warned inactive draft #${pull.number}`);
continue;
}
if (phase === "warning" && daysSince(activeComment.created_at) >= responseDays) {
await markCloseSoon(pull, activeComment, closeDays);
continue;
}
if (phase === "close-soon" && daysSince(activeComment.updated_at) >= closeDays) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: activeComment.id,
body: [
`${INACTIVITY_MARKER}closed -->`,
`Closing this draft pull request after the \`${CLOSE_SOON_LABEL}\` waiting period expired. It can be reopened if development resumes.`,
].join("\n"),
});
await github.rest.pulls.update({
owner,
repo,
pull_number: pull.number,
state: "closed",
});
core.info(`Closed inactive draft #${pull.number}`);
}
}
}
};
+4 -7
View File
@@ -11,8 +11,6 @@ on:
jobs:
build_client:
name: Build client
permissions:
contents: read
strategy:
matrix:
include:
@@ -37,12 +35,11 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Check out the repo
uses: actions/checkout@v7
uses: actions/checkout@v4
with:
ref: ${{ inputs.checkout-sha == null && github.sha || inputs.checkout-sha }}
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install PyInstaller and client dependencies
@@ -64,14 +61,14 @@ jobs:
cd software
pyinstaller pyinstaller.spec
- name: Upload built client
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: client-${{ matrix.name }}
path: software/dist/*
- name: Zip up client for release
run: ${{ matrix.bundle_command }}
- name: Upload release artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: release-artifacts-${{ matrix.name }}
path: client-${{ matrix.name }}.zip
+19 -62
View File
@@ -6,44 +6,38 @@ on:
checkout-sha:
required: false
type: string
publish-builder:
description: Build and publish the firmware builder image
required: false
type: boolean
default: true
jobs:
build_fw_builder:
name: Build fw-builder Docker image
runs-on: ubuntu-latest # Inherits permissions from caller
name: Build and push fw-builder Docker image
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
outputs:
image_ref: ${{ steps.published-image.outputs.image_ref || steps.local-image.outputs.image_ref }}
image_hash: ${{ steps.push.outputs.digest }}
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v2
- name: Check out the repo
uses: actions/checkout@v7
uses: actions/checkout@v4
with:
ref: ${{ inputs.checkout-sha == null && github.sha || inputs.checkout-sha }}
fetch-depth: 0
persist-credentials: false
- name: ghcr.io login
if: ${{ inputs.publish-builder }}
uses: docker/login-action@v4
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
if: ${{ inputs.publish-builder }}
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v4
with:
images: ghcr.io/${{ github.repository }}-fw-builder
- name: Build and push Docker images
if: ${{ inputs.publish-builder }}
id: push
uses: docker/build-push-action@v7
uses: docker/build-push-action@v4
with:
context: firmware
push: true
@@ -51,63 +45,26 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build Docker image for this workflow
if: ${{ !inputs.publish-builder }}
uses: docker/build-push-action@v7
with:
context: firmware
tags: chameleonultra-fw-builder:pr
outputs: type=docker,dest=${{ runner.temp }}/fw-builder.tar
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Upload Docker image
if: ${{ !inputs.publish-builder }}
uses: actions/upload-artifact@v7
with:
name: firmware-builder-image
path: ${{ runner.temp }}/fw-builder.tar
retention-days: 1
- name: Use local builder image
if: ${{ !inputs.publish-builder }}
id: local-image
run: echo "image_ref=chameleonultra-fw-builder:pr" >> "$GITHUB_OUTPUT"
- name: Use published builder image
if: ${{ inputs.publish-builder }}
id: published-image
env:
IMAGE: ghcr.io/${{ github.repository }}-fw-builder
DIGEST: ${{ steps.push.outputs.digest }}
run: echo "image_ref=${IMAGE,,}@${DIGEST}" >> "$GITHUB_OUTPUT"
build_fw:
name: Build firmware
runs-on: ubuntu-latest
needs: build_fw_builder
permissions:
contents: read
strategy:
matrix:
device_type: [ultra, lite]
steps:
- name: Check out the repo
uses: actions/checkout@v7
uses: actions/checkout@v4
with:
ref: ${{ inputs.checkout-sha == null && github.sha || inputs.checkout-sha }}
fetch-depth: 0
persist-credentials: false
- name: Download Docker image
if: ${{ !inputs.publish-builder }}
uses: actions/download-artifact@v8
with:
name: firmware-builder-image
path: ${{ runner.temp }}
- name: Load Docker image
if: ${{ !inputs.publish-builder }}
run: docker load --input "${{ runner.temp }}/fw-builder.tar"
- name: Build firmware
env:
repo: ${{ github.repository }}
run: |
docker run --rm -v ${PWD}:/workdir -e CURRENT_DEVICE_TYPE=${{ matrix.device_type }} "${{ needs.build_fw_builder.outputs.image_ref }}" firmware/build.sh
docker run --rm -v ${PWD}:/workdir -e CURRENT_DEVICE_TYPE=${{ matrix.device_type }} ghcr.io/${repo,,}-fw-builder@${{ needs.build_fw_builder.outputs.image_hash }} firmware/build.sh
- name: Upload built binaries
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.device_type }}-firmware
path: firmware/objects/*.hex
@@ -119,17 +76,17 @@ jobs:
unzip firmware/objects/${{ matrix.device_type }}-dfu-app.zip -d firmware/objects/${{ matrix.device_type }}-dfu-app
unzip firmware/objects/${{ matrix.device_type }}-dfu-full.zip -d firmware/objects/${{ matrix.device_type }}-dfu-full
- name: Upload dfu app image
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.device_type }}-dfu-app
path: firmware/objects/${{ matrix.device_type }}-dfu-app/*
- name: Upload dfu full image
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.device_type }}-dfu-full
path: firmware/objects/${{ matrix.device_type }}-dfu-full/*
- name: Upload release artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: release-artifacts-${{ matrix.device_type }}
path: firmware/objects/*.zip
+9 -42
View File
@@ -1,48 +1,15 @@
on: pull_request_target
name: Changelog Reminder
on:
pull_request_target:
permissions:
pull-requests: write
jobs:
remind:
name: Changelog Reminder
runs-on: ubuntu-latest
steps:
- name: Changelog Reminder
uses: actions/github-script@v9
with:
script: |
const message = 'You are welcome to add an entry to the CHANGELOG.md as well';
const pullNumber = context.payload.pull_request.number;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pullNumber,
per_page: 100,
});
if (files.some((file) => file.filename === 'CHANGELOG.md')) {
return;
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullNumber,
per_page: 100,
});
const alreadyReminded = comments.some((comment) =>
comment.user?.login === 'github-actions[bot]' && comment.body === message
);
if (!alreadyReminded) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullNumber,
body: message,
});
}
- uses: actions/checkout@master
- name: Changelog Reminder
uses: peterjgrainger/action-changelog-reminder@v1.2.0
with:
changelog_regex: 'CHANGELOG.md'
customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+9 -11
View File
@@ -5,7 +5,11 @@ on:
branches: ["main"]
workflow_dispatch:
permissions: {}
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
@@ -17,23 +21,20 @@ jobs:
# Build job
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@v4
with:
repository: ${{ github.repository }}.wiki
persist-credentials: false
- name: Setup Pages
uses: actions/configure-pages@v6
uses: actions/configure-pages@v5
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v5
uses: actions/upload-pages-artifact@v3
# Deployment job
deploy:
@@ -42,10 +43,7 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
permissions:
pages: write
id-token: write
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
uses: actions/deploy-pages@v4
+28 -8
View File
@@ -1,24 +1,44 @@
name: PR handler
on:
pull_request:
concurrency:
group: pr-build-${{ github.event.pull_request.number }}
cancel-in-progress: true
pull_request_target:
jobs:
firmware_pipeline:
name: Build Firmware
permissions:
packages: write
contents: read
uses: ./.github/workflows/build_firmware.yml
with:
checkout-sha: "${{ github.event.pull_request.head.sha }}"
publish-builder: false
client_pipeline:
name: Build Firmware
permissions:
contents: read
uses: ./.github/workflows/build_client.yml
with:
checkout-sha: "${{ github.event.pull_request.head.sha }}"
comment:
runs-on: ubuntu-latest
name: Comment on PR
needs:
- firmware_pipeline
- client_pipeline
permissions:
pull-requests: write
steps:
- uses: marocchino/sticky-pull-request-comment@v2
with:
message: |
# Built artifacts for commit ${{ github.event.pull_request.head.sha }}
## Firmware
- [Ultra APP DFU Package](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/ultra-dfu-app.zip)
- [Ultra binaries](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/ultra-firmware.zip)
- [Lite APP DFU Package](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/lite-dfu-app.zip)
- [Lite binaries](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/lite-firmware.zip)
## Client
- [Linux](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/client-linux.zip)
- [macOS](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/client-macos.zip)
- [Windows](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/client-windows.zip)
-106
View File
@@ -1,106 +0,0 @@
name: PR build artifact comment
on:
workflow_run:
workflows: ["PR handler"]
types: [completed]
permissions:
pull-requests: write
jobs:
comment:
name: Comment on PR build result
if: github.event.workflow_run.event == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Add or update artifact links
uses: actions/github-script@v9
with:
script: |
const run = context.payload.workflow_run;
let pullNumber = run.pull_requests[0]?.number;
if (!pullNumber) {
const head = `${run.head_repository.owner.login}:${run.head_branch}`;
const candidates = await github.paginate(github.rest.pulls.list, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head,
per_page: 100,
});
pullNumber = candidates.find((pull) => pull.head.sha === run.head_sha)?.number;
}
if (!pullNumber) {
core.setFailed(`Could not find the pull request for workflow run ${run.id}`);
return;
}
const { data: pull } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pullNumber,
});
if (pull.head.sha !== run.head_sha) {
core.notice(`Skipping superseded workflow run ${run.id}`);
return;
}
const marker = '<!-- chameleon-ultra-pr-build-artifacts -->';
const lines = [marker, `# Build result for commit ${run.head_sha}`, ''];
if (run.conclusion === 'success') {
const baseUrl = `https://nightly.link/${context.repo.owner}/${context.repo.repo}/actions/runs/${run.id}`;
lines.push(
'## Firmware',
'',
`- [Ultra APP DFU Package](${baseUrl}/ultra-dfu-app.zip)`,
`- [Ultra binaries](${baseUrl}/ultra-firmware.zip)`,
`- [Lite APP DFU Package](${baseUrl}/lite-dfu-app.zip)`,
`- [Lite binaries](${baseUrl}/lite-firmware.zip)`,
'',
'## Client',
'',
`- [Linux](${baseUrl}/client-linux.zip)`,
`- [macOS](${baseUrl}/client-macos.zip)`,
`- [Windows](${baseUrl}/client-windows.zip)`,
);
} else {
lines.push(
`**Status:** ${run.conclusion ?? 'unknown'}`,
'',
`[View workflow run](${run.html_url})`,
);
}
const body = lines.join('\n');
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullNumber,
per_page: 100,
});
const existing = comments.find((comment) =>
comment.user?.login === 'github-actions[bot]' &&
(comment.body?.includes(marker) || comment.body?.includes('# Built artifacts for commit '))
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullNumber,
body,
});
}
+7 -27
View File
@@ -3,10 +3,6 @@ name: Push handler
on:
push:
concurrency:
group: push-${{ github.ref }}
cancel-in-progress: true
jobs:
firmware_pipeline:
name: Build Firmware
@@ -16,8 +12,6 @@ jobs:
uses: ./.github/workflows/build_firmware.yml
client_pipeline:
name: Build Firmware
permissions:
contents: read
uses: ./.github/workflows/build_client.yml
create_dev_release:
permissions:
@@ -30,15 +24,15 @@ jobs:
- client_pipeline
steps:
- name: Check out the repo
uses: actions/checkout@v7
uses: actions/checkout@v4
- name: Download release artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
pattern: release-artifacts-*
merge-multiple: true
path: release-artifacts
- name: Upload to dev release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@v1
with:
body: |
Auto-Generated DFU packages from latest `main` commit.
@@ -55,7 +49,7 @@ jobs:
- name: Fix up release tag
run: |
git tag -f dev
git push origin refs/tags/dev --force
git push --tags -f
create_release:
permissions:
contents: write
@@ -67,17 +61,15 @@ jobs:
- client_pipeline
steps:
- name: Check out the repo
uses: actions/checkout@v7
with:
persist-credentials: false
uses: actions/checkout@v4
- name: Download release artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
pattern: release-artifacts-*
merge-multiple: true
path: release-artifacts
- name: Upload to tagged release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@v1
with:
body: |
Auto-Generated DFU packages for Release ${{ github.ref_name }}
@@ -88,15 +80,3 @@ jobs:
generate_release_notes: true
append_body: true
files: release-artifacts/*
start_feature_freeze:
name: Start the next PR review cycle
if: startsWith(github.ref, 'refs/tags/v')
needs: create_release
permissions:
contents: read
issues: write
pull-requests: write
uses: ./.github/workflows/pr_review_cycle.yml
with:
start_feature_freeze: true
-102
View File
@@ -1,102 +0,0 @@
name: PR review cycle
on:
# The tagged-release workflow calls this explicitly because events created by GITHUB_TOKEN do not normally start another workflow.
workflow_call:
inputs:
start_feature_freeze:
description: Label the next review batch
type: boolean
required: false
default: false
workflow_dispatch:
release:
types: [published]
pull_request_target:
types: [converted_to_draft, edited, ready_for_review, reopened, synchronize]
issue_comment:
types: [created]
schedule:
- cron: "23 4 * * *"
env:
DRAFT_WARNING_DAYS: 30
DRAFT_RESPONSE_DAYS: 14
DRAFT_CLOSE_DAYS: 30
permissions:
contents: read
issues: write
pull-requests: write
concurrency:
group: pr-review-cycle-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
cancel-in-progress: false
jobs:
start-feature-freeze:
name: Start feature-freeze batch
if: >-
inputs.start_feature_freeze == true ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'release' && github.event.release.prerelease == false)
runs-on: ubuntu-latest
steps:
- name: Check out trusted automation
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
- name: Label all currently ready PRs
uses: actions/github-script@v9
with:
script: |
const run = require('./.github/scripts/pr-review-cycle.js');
await run({ github, context, core, mode: 'start-feature-freeze' });
handle-pull-activity:
name: Update labels after PR activity
if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
steps:
- name: Check out trusted automation
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
- name: Update the PR lifecycle
uses: actions/github-script@v9
with:
script: |
const run = require('./.github/scripts/pr-review-cycle.js');
await run({ github, context, core, mode: 'pull-activity' });
handle-discussion-activity:
name: Reset inactive draft after discussion
if: github.event_name == 'issue_comment' && github.event.issue.pull_request
runs-on: ubuntu-latest
steps:
- name: Check out trusted automation
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
- name: Update the draft lifecycle
uses: actions/github-script@v9
with:
script: |
const run = require('./.github/scripts/pr-review-cycle.js');
await run({ github, context, core, mode: 'discussion-activity' });
scan-inactive-drafts:
name: Scan inactive drafts
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Check out trusted automation
uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
- name: Warn, label, or close inactive drafts
uses: actions/github-script@v9
with:
script: |
const run = require('./.github/scripts/pr-review-cycle.js');
await run({ github, context, core, mode: 'scan-drafts' });
+20 -42
View File
@@ -7,11 +7,8 @@ on:
- ".github/workflows/**"
workflow_dispatch:
permissions:
contents: read
jobs:
lint-formatting:
lint:
runs-on: ubuntu-latest
defaults:
run:
@@ -20,12 +17,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: "pip"
@@ -37,42 +32,25 @@ jobs:
- name: Set up uv
uses: astral-sh/setup-uv@v6
- name: Install dependencies with uv
- name: Install dependencies with uv (if lockfile present)
if: ${{ hashFiles('software/uv.lock') != '' }}
run: uv sync --dev
- name: Install tools with pip (fallback)
if: ${{ hashFiles('software/uv.lock') == '' }}
run: |
python -m pip install --upgrade pip
# Try project requirements if present
if [ -f script/requirements.txt ]; then pip install -r script/requirements.txt || true; fi
# Ensure ruff and pyrefly are available
pip install ruff pyrefly
- name: Ruff check
run: uv run ruff check .
lint-types:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: software
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: "3.13"
cache: "pip"
cache-dependency-path: |
software/pyproject.toml
software/uv.lock
software/script/requirements.txt
- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
- name: Install dependencies with uv
run: uv sync --dev
run: |
set -e
(uv run ruff --version && uv run ruff check .) || ruff check .
- name: Pyrefly check
run: uv run pyrefly check
run: |
set -e
(uv run pyrefly --help >/dev/null 2>&1 && uv run pyrefly check) || pyrefly check
-5
View File
@@ -708,8 +708,3 @@ FodyWeavers.xsd
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,c++,c,python,visualstudiocode,macos,windows
software/script/tests/nonces.bin
software/script/nonces.bin
.vscode/settings.json
.vscode/tasks.json
firmware/compile_commands.json
firmware/application/compile_commands.json
software/src/target_arch_detect.c
+1 -10
View File
@@ -3,14 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
## [v2.2.0][2026-07-04]
- Added Jablotron LF protocol support: read, emulate and T55xx clone (@midlan)
- Added IDTECK LF protocol support: tag emulation (PSK1 RF/32) and T55xx clone. No reader path yet; PSK demodulation on the envelope-only receive chain is left for a follow-up.
- Added PAC/Stanley LF protocol support: read, emulate and T55xx clone (@kevihiiin, @danieltwagner)
- Fix firmware application USB serial number (@taichunmin)
- Added ioProx LF protocol support (read, emulate and T55xx clone)
- Added `hf mfu nfcimport` to import Flipper Zero `.nfc` files into MFU/NTAG emulator slots, with `--amiibo` flag for automatic PWD/PACK derivation (@fmuk)
- Hardware upgrade: Restarting the Ultra now only requires running each of the three RGB colors once, resolving previous firmware modification issues
- Added commands to dump and clone Mifare tags
- Fix bad missing tools warning (@suut)
- Fix for FAST_READ command for nfc - mf0 tags
@@ -26,8 +19,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fix Windows build (@suut)
- Added `hf 14a config` to deal with badly configured cards (@azuwis)
- New Symmetrical LED Animation Mode and Improved Minimal Mode (@WillyJL)
- Fix MF1 state reset logic and access control conditions (@unkernet)
- Added support for SEOS credentials (@aaronjamt)
## [v2.1.0][2025-09-02]
- Added UV, formatter and linter. Contribution guidelines. (@GameTec-live)
-23
View File
@@ -19,26 +19,3 @@ Heres a bit of info and a few guidelines to get you started:
- Type safety is important. The CLI should be typesafe. Python 3.9+ offer a wide variety of type declarations. Metas [pyrefly](https://pyrefly.org/) is used to do type validation. It is recommended to install the appropriate vscode extension and check your types before opening a PR.
- Formatting matters. Mostly. While pixelpeeping and exact rules are annoying and unnescesary, format your code in a readable and logical way. [Ruff](https://docs.astral.sh/ruff/) is used to enforce various formatting rules. You may install the Ruff vscode extension or use the CLI to format before opening a PR.
- Avoid extra packages. Almost everyone knows the "meme" of the javascript ["is-even"](https://www.npmjs.com/package/is-even) package. While it is encouraged and makes sense to use packages where appropriate, just installing packages for the hell of it even if its a 2 liner is not sensible.
## Feature freeze and review cycle
Pull requests are reviewed in batches so maintainers and testers can focus on a manageable set of changes. The `feature freeze` label marks the PRs in the current batch. This does not mean that you can not make new Pull requests or contributions.
The cycle works as follows:
1. At the start of a cycle, every open PR that is ready for review is given the `feature freeze` label. Draft PRs are not included.
2. Maintainers and contributors focus their review and testing on the labeled PRs. These PRs are then merged, closed, or converted back to drafts as appropriate.
3. PRs opened or marked ready after the batch starts normally wait for the next cycle. Maintainers may make exceptions when necessary.
4. Once no open, ready PRs remain in the current batch, a release is made and the next cycle begins. All PRs that are ready at that point enter the new batch.
If a PR in the current batch is converted to a draft, it leaves that batch. Marking it ready again does not automatically add it back to the current batch. It may be included in the next one.
### Inactive drafts
Draft PRs are welcome and the ideal solution while work is in progress and you may want to gather early feedback. To prevent stale PRs from cluttering up the list, inactive draft PRs will follow the following process:
- After 30 days without activity, a bot asks whether there is still interest in completing the PR.
- After another 14 days without activity, the PR receives the `close soon` label.
- After 30 more days without activity, the draft is closed. It can be reopened if development resumes.
A new commit, an edit to the PR, or a new comment resets the inactivity countdown. An author can also reply to the bot with `no`, `no longer interested`, `please close`, or `/close-soon` to move the PR directly to the `close soon` stage.
+5 -8
View File
@@ -18,6 +18,10 @@ Guangdong, China: [MTools Tec](https://shop.mtoolstec.com/)
Lazada One, Singapore: [Aliexpress by RRG](https://proxgrind.aliexpress.com/store/1101312023)
# Hardware Upgrade Notice
**Important:** The Chameleon Ultra hardware has been upgraded! Restarting the device now only requires running each of the three RGB colors once (equivalent to a restart). This resolves previous issues where firmware modifications could cause the device to malfunction.
# What is it and how to use ?
Read the [available documentation](https://github.com/RfidResearchGroup/ChameleonUltra/wiki).
@@ -26,8 +30,6 @@ Read the [available documentation](https://github.com/RfidResearchGroup/Chameleo
* [ChameleonUltraGUI](https://github.com/GameTec-live/ChameleonUltraGUI)
* [MTools BLE](https://github.com/RfidResearchGroup/ChameleonUltra/wiki/mtoolsble)
* [Mifare Chameleon Tool (iOS only, Beta)](https://apps.apple.com/it/app/mifare-chameleon-tool/id6761231484)
* [Chameleon Ultra (Sailfish OS only)](https://sailfishos-chum.github.io/apps/harbour-chameleon-ultra)
# Videos
@@ -47,9 +49,4 @@ Where do you find the community?
* Devices/chameleon-ultra for usage discussions
* [GameTec_live discord server](https://discord.gg/DJ2A4wxncK)
Other notable projects:
* [Fantasi](https://fantasi.cloud)
* [Discord](https://fantasi.cloud/discord)
* [chameleon-ultra.js](https://github.com/taichunmin/chameleon-ultra.js/)
###### Searching for the docs repo? Find it [here](https://github.com/RfidResearchGroup/ChameleonUltraDocs)
###### Searching for the docs repo? Find it [here](https://github.com/RfidResearchGroup/ChameleonUltraDocs)
+1 -14
View File
@@ -28,24 +28,16 @@ SRC_FILES += \
$(PROJ_DIR)/rfid/nfctag/tag_persistence.c \
$(PROJ_DIR)/rfid/nfctag/hf/crypto1_helper.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_14a.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_14a_4.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_mf1.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_mf0_ntag.c \
$(PROJ_DIR)/rfid/nfctag/hf/nfc_seos.c \
$(PROJ_DIR)/rfid/nfctag/lf/lf_tag_em.c \
$(PROJ_DIR)/rfid/nfctag/lf/utils/fskdemod.c \
$(PROJ_DIR)/rfid/nfctag/lf/utils/circular_buffer.c \
$(PROJ_DIR)/rfid/nfctag/lf/utils/manchester.c \
$(PROJ_DIR)/rfid/nfctag/lf/utils/psk1.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/em410x.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/hidprox.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/pac.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/ioprox.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/viking.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/jablotron.c \
$(PROJ_DIR)/rfid/nfctag/lf/utils/diphase.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/wiegand.c \
$(PROJ_DIR)/rfid/nfctag/lf/protocols/idteck.c \
$(PROJ_DIR)/utils/dataframe.c \
$(PROJ_DIR)/utils/delayed_reset.c \
$(PROJ_DIR)/utils/fds_util.c \
@@ -348,17 +340,12 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA})
$(PROJ_DIR)/rfid/reader/hf/rc522.c \
$(PROJ_DIR)/rfid/reader/lf/lf_125khz_radio.c \
$(PROJ_DIR)/rfid/reader/lf/lf_em410x_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_em4x05_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_gap.c \
$(PROJ_DIR)/rfid/reader/lf/lf_reader_generic.c \
$(PROJ_DIR)/rfid/reader/lf/lf_reader_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_reader_main.c \
$(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_hidprox_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_pac_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_ioprox_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_viking_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_jablotron_data.c \
$(PROJ_DIR)/rfid/reader/lf/lf_reader_generic.c \
INC_FOLDERS +=\
${PROJ_DIR}/rfid/reader/ \
File diff suppressed because it is too large Load Diff
+18 -34
View File
@@ -12,7 +12,6 @@
#include "nrf_delay.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_rng.h"
#include "nfc_mf1.h" // for nfc_tag_mf1_prng_seed
#include "nrf_power.h"
#include "nrf_pwr_mgmt.h"
#include "nrfx_nfct.h"
@@ -62,7 +61,7 @@ static bool m_is_a_btn_release = false;
static bool m_system_off_processing = false;
// NFC field generator state
volatile bool m_is_field_on = false;
volatile bool m_is_field_on = false;
// cpu reset reason
static uint32_t m_reset_source;
@@ -137,11 +136,6 @@ void rng_drv_and_srand_init(void) {
// Finally initialize the srand seeds in the c standard library
srand(rand_int);
// Seed the MFC LFSR PRNG with the same hardware random value.
// This makes nonce generation follow the real Mifare Classic LFSR pattern
// so readers that fingerprint PRNG type (e.g. Eltis) accept the emulated card.
nfc_tag_mf1_prng_seed(rand_int);
}
/**@brief Initialize GPIO matrix library
@@ -156,27 +150,27 @@ static void gpio_te_init(void) {
static void field_generator_rainbow_loop(void) {
static uint8_t color_index = 0;
static uint32_t last_update = 0;
if (!m_is_field_on) return;
uint32_t now = app_timer_cnt_get();
if (app_timer_cnt_diff_compute(now, last_update) < APP_TIMER_TICKS(100)) {
return;
}
last_update = now;
// Rainbow colors
const uint8_t colors[] = {RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_CYAN, RGB_BLUE, RGB_MAGENTA};
set_slot_light_color(colors[color_index]);
uint32_t *led_pins = hw_get_led_array();
// Light up all LEDs with current color
for (int i = 0; i < RGB_LIST_NUM; i++) {
nrf_gpio_pin_set(led_pins[i]);
}
color_index = (color_index + 1) % 6;
}
#endif
@@ -204,9 +198,9 @@ static void timer_button_event_handle(void *arg) {
NRF_LOG_INFO("BUTTON press during shutdown");
return;
}
nrf_drv_gpiote_pin_t pin = *(nrf_drv_gpiote_pin_t *)arg;
// Check here if the current GPIO is at the pressed level
if (nrf_gpio_pin_read(pin) == 1) {
if (pin == BUTTON_1) {
@@ -673,11 +667,6 @@ static void btn_fn_copy_lf(uint8_t slot, tag_specific_type_t type) {
size = LF_HIDPROX_TAG_ID_SIZE;
data = id_buffer;
break;
case TAG_TYPE_IOPROX:
status = scan_ioprox(id_buffer, 0);
size = LF_IOPROX_TAG_ID_SIZE;
data = id_buffer;
break;
case TAG_TYPE_EM410X:
case TAG_TYPE_EM410X_ELECTRA: {
status = scan_em410x(id_buffer);
@@ -700,11 +689,6 @@ static void btn_fn_copy_lf(uint8_t slot, tag_specific_type_t type) {
size = LF_VIKING_TAG_ID_SIZE;
data = id_buffer;
break;
case TAG_TYPE_JABLOTRON:
status = scan_jablotron(id_buffer);
size = LF_JABLOTRON_TAG_ID_SIZE;
data = id_buffer;
break;
default:
NRF_LOG_ERROR("Unsupported LF tag type")
offline_status_error();
@@ -859,16 +843,16 @@ static void run_button_function_by_settings(settings_button_function_t sbf) {
nrf_gpio_pin_set(READER_POWER); // reader power enable
nrf_gpio_cfg_output(HF_ANT_SEL);
nrf_gpio_pin_clear(HF_ANT_SEL); // hf ant switch to reader mode
pcd_14a_reader_init();
bsp_delay_ms(10);
}
pcd_14a_reader_reset();
pcd_14a_reader_antenna_on();
m_is_field_on = true;
NRF_LOG_INFO("NFC field ON");
// Set initial rainbow state
set_slot_light_color(RGB_RED);
uint32_t *led_pins = hw_get_led_array();
@@ -884,7 +868,7 @@ static void run_button_function_by_settings(settings_button_function_t sbf) {
pcd_14a_reader_antenna_off();
m_is_field_on = false;
NRF_LOG_INFO("NFC field OFF");
// If we're not in reader mode, clean up the hardware
device_mode_t current_mode = get_device_mode();
if (current_mode != DEVICE_MODE_READER) {
@@ -892,7 +876,7 @@ static void run_button_function_by_settings(settings_button_function_t sbf) {
nrf_gpio_pin_clear(READER_POWER); // reader power disable
nrf_gpio_pin_set(HF_ANT_SEL); // hf ant switch back to tag mode
}
// Restore normal LED
light_up_by_slot();
@@ -1040,17 +1024,17 @@ int main(void) {
lesc_event_process();
// Button event process
button_press_process();
#if defined(PROJECT_CHAMELEON_ULTRA)
// Field generator rainbow animation
field_generator_rainbow_loop();
#endif
// Led blink at usb status (only if field generator is off)
if (!m_is_field_on) {
blink_usb_led_status();
}
// Data pack process
data_frame_process();
// Log print process
-1
View File
@@ -19,7 +19,6 @@
/////////////////////////////////////////////////////////////////////
#define STATUS_LF_TAG_OK (0x40) // Some of the low -frequency cards are successful!
#define STATUS_LF_TAG_NO_FOUND (0x41) // Can't search for valid LF tags
#define STATUS_LF_TAG_LOGIN_REQUIRED (0x42) // Tag requires LOGIN before read
/////////////////////////////////////////////////////////////////////
// other status
+7 -7
View File
@@ -90,7 +90,7 @@ BLE_ADVERTISING_DEF(m_advertising);
uint16_t batt_lvl_in_milli_volts = 0;
uint8_t percentage_batt_lvl = 0;
static nrf_saadc_value_t adc_buf[ADC_BUF_COUNT][ADC_BUF_SIZE];
static nrf_saadc_value_t adc_buf[ADC_BUF_SIZE][ADC_BUF_COUNT];
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
lf_adc_callback_t m_lf_adc_callback = NULL;
@@ -736,11 +736,11 @@ static void battery_level_meas_timeout_handler(void *p_context) {
// if battery service is notification enable, we can send msg to device.
err_code = ble_bas_battery_level_update(&m_bas, percentage_batt_lvl, BLE_CONN_HANDLE_ALL);
if ((err_code != NRF_SUCCESS) &&
(err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_BUSY) &&
(err_code != NRF_ERROR_FORBIDDEN) &&
(err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)) {
(err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_BUSY) &&
(err_code != NRF_ERROR_FORBIDDEN) &&
(err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)) {
APP_ERROR_HANDLER(err_code);
}
@@ -806,4 +806,4 @@ void unregister_lf_adc_callback(void) {
nrfx_saadc_uninit();
adc_configure();
m_lf_adc_callback = NULL;
}
}
-40
View File
@@ -46,8 +46,6 @@
#define DATA_CMD_GET_BLE_PAIRING_ENABLE (1036)
#define DATA_CMD_SET_BLE_PAIRING_ENABLE (1037)
#define DATA_CMD_GET_ALL_SLOT_NICKS (1038)
#define DATA_CMD_GET_SLEEP_TIMEOUT (1039)
#define DATA_CMD_SET_SLEEP_TIMEOUT (1040)
//
// ******************************************************************
@@ -69,8 +67,6 @@
#define DATA_CMD_MF1_READ_ONE_BLOCK (2008)
#define DATA_CMD_MF1_WRITE_ONE_BLOCK (2009)
#define DATA_CMD_HF14A_RAW (2010)
#define DATA_CMD_HF14A_SCAN_KEEP (2016) /* scan+RATS, keep field alive for APDU exchange */
#define DATA_CMD_HF14A_AUTH_TRACE (2017) /* full anticoll + Crypto1 auth, every frame returned for inspection */
#define DATA_CMD_MF1_MANIPULATE_VALUE_BLOCK (2011)
#define DATA_CMD_MF1_CHECK_KEYS_OF_SECTORS (2012)
#define DATA_CMD_MF1_HARDNESTED_ACQUIRE (2013)
@@ -82,7 +78,6 @@
#define DATA_CMD_HF14A_GET_CONFIG (2200)
#define DATA_CMD_HF14A_SET_CONFIG (2201)
#define DATA_CMD_HF14A_SNIFF (2020)
//
// ******************************************************************
@@ -98,21 +93,11 @@
#define DATA_CMD_EM410X_ELECTRA_WRITE_TO_T55XX (3006)
#define DATA_CMD_HIDPROX_SCAN (3002)
#define DATA_CMD_HIDPROX_WRITE_TO_T55XX (3003)
#define DATA_CMD_PAC_SCAN (3014)
#define DATA_CMD_PAC_WRITE_TO_T55XX (3015)
#define DATA_CMD_VIKING_SCAN (3004)
#define DATA_CMD_VIKING_WRITE_TO_T55XX (3005)
#define DATA_CMD_ADC_GENERIC_READ (3009)
#define DATA_CMD_GENERIC_READ (3007)
#define DATA_CMD_CORR_GENERIC_READ (3008)
#define DATA_CMD_IOPROX_SCAN (3010)
#define DATA_CMD_IOPROX_WRITE_TO_T55XX (3011)
#define DATA_CMD_IOPROX_DECODE_RAW (3012)
#define DATA_CMD_IOPROX_COMPOSE_ID (3013)
#define DATA_CMD_LF_T55XX_WRITE (3016)
#define DATA_CMD_IDTECK_WRITE_TO_T55XX (3018)
#define DATA_CMD_JABLOTRON_SCAN (3019)
#define DATA_CMD_JABLOTRON_WRITE_TO_T55XX (3020)
//
// ******************************************************************
@@ -163,11 +148,6 @@
#define DATA_CMD_MF0_NTAG_GET_EMULATOR_CONFIG (4037)
#define DATA_CMD_MF1_SET_FIELD_OFF_DO_RESET (4038)
#define DATA_CMD_MF1_GET_FIELD_OFF_DO_RESET (4039)
#define DATA_CMD_MF1_GET_PRNG_TYPE (4040) // 0=static 1=weak(LFSR) 2=hard(rand)
#define DATA_CMD_MF1_SET_PRNG_TYPE (4041)
#define DATA_CMD_SEOS_READ_EMU_DATA (4042)
#define DATA_CMD_SEOS_WRITE_EMU_DATA (4043)
#define DATA_CMD_SEOS_WRITE_EMU_KEYS (4044)
//
// ******************************************************************
@@ -180,31 +160,11 @@
//
// ******************************************************************
/* ISO14443-4 T=CL emulation commands */
#define DATA_CMD_HF14A_4_APDU_RECV (6000) /* non-blocking poll: firmware->host APDU */
#define DATA_CMD_HF14A_4_APDU_SEND (6001) /* host->firmware APDU response */
#define DATA_CMD_HF14A_4_SET_ANTI_COLL (6002) /* set UID/ATQA/SAK/ATS */
#define DATA_CMD_HF14A_4_STATIC_RESP (6003) /* add/clear static APDU response pair */
#define DATA_CMD_HF14A_4_READER_APDU (6004) /* select+RATS+send APDU, keep field */
#define DATA_CMD_HF14A_4_EMV_SCAN (6005) /* full EMV scan in one call */
#define DATA_CMD_EM410X_SET_EMU_ID (5000)
#define DATA_CMD_EM410X_GET_EMU_ID (5001)
#define DATA_CMD_HIDPROX_SET_EMU_ID (5002)
#define DATA_CMD_HIDPROX_GET_EMU_ID (5003)
#define DATA_CMD_VIKING_SET_EMU_ID (5004)
#define DATA_CMD_VIKING_GET_EMU_ID (5005)
#define DATA_CMD_PAC_SET_EMU_ID (5006)
#define DATA_CMD_PAC_GET_EMU_ID (5007)
#define DATA_CMD_IOPROX_SET_EMU_ID (5008)
#define DATA_CMD_IOPROX_GET_EMU_ID (5009)
#define DATA_CMD_JABLOTRON_SET_EMU_ID (5010)
#define DATA_CMD_JABLOTRON_GET_EMU_ID (5011)
#define DATA_CMD_IDTECK_SET_EMU_ID (5012)
#define DATA_CMD_IDTECK_GET_EMU_ID (5013)
#define DATA_CMD_EM4X05_SCAN (3030)
#define DATA_CMD_EM4X05_READSNIFF (3032)
#define DATA_CMD_LF_SNIFF (3031)
#endif

Some files were not shown because too many files have changed in this diff Show More