52 Commits

Author SHA1 Message Date
Steven Dan
d0c20efd15 don't go through dnr process when it's not enabled 2026-04-11 21:52:20 +08:00
Steven Dan
e3fb9b0499 fix mic insertion issue 2026-04-11 21:49:09 +08:00
Steven Dan
f90a49d763 adc monitor for F1 2026-04-11 21:12:40 +08:00
Steven Dan
6678d21d9d output low for 100ms when insertion 2026-04-11 14:45:03 +08:00
Steven Dan
f6e4dd55ab 1.0.10 2026-04-11 11:47:26 +08:00
Steven Dan
961615b0f0 mute headphone when mic insertion 2026-04-11 11:46:44 +08:00
Steven Dan
42b7f4e7ce Reapply "mic detection"
This reverts commit 3880b56108.
2026-04-11 09:19:59 +08:00
Steven Dan
50a722b96a update dnr_init_flag 2026-04-10 22:02:36 +08:00
Steven Dan
85fce4673b add uac1 modes 2026-04-10 16:46:12 +08:00
Steven Dan
05a5ac80ef add more flash protect for key verification 2026-04-09 18:59:17 +08:00
Steven Dan
3880b56108 Revert "mic detection"
This reverts commit 35846cffd3.
2026-04-09 17:59:07 +08:00
Steven Dan
01360b1650 update f5 2026-04-09 16:00:53 +08:00
Steven Dan
4b4a76d7b0 update flash id 2026-04-09 16:00:29 +08:00
Steven Dan
418ea8fdd4 1.0.9 2026-04-09 14:30:23 +08:00
Steven Dan
35846cffd3 mic detection 2026-04-09 14:30:04 +08:00
Steven Dan
f1c0084325 flash attribure 2026-04-09 10:53:00 +08:00
Steven Dan
1b1259cdbf add mute2 2026-04-08 13:26:15 +08:00
Steven Dan
8262e59344 1.0.8 2026-04-08 09:52:34 +08:00
Steven Dan
c4b10f7b4e add flash supprt 2026-04-08 09:52:19 +08:00
Steven Dan
9073ed3b3a mute led act as blinking 2026-03-31 11:39:21 +08:00
Steven Dan
eae7e2178b update eq_flash_storage 2026-03-31 10:58:58 +08:00
Steven Dan
00e7cab17a update stackfunction 2026-03-31 10:58:35 +08:00
Steven Dan
38f033ace0 add SetEqDataChan for EQ_EN only 2026-03-31 10:19:43 +08:00
Steven Dan
cb4a7bad5b update f2 f3 to 16bit 2026-03-31 10:19:11 +08:00
Steven Dan
8246d6fbda 1.0.6 2026-03-30 20:14:15 +08:00
Steven Dan
19d9c64b62 add mute handler 2 2026-03-30 20:13:47 +08:00
Steven Dan
c3202488f6 remove stackfunction 2026-03-30 20:13:05 +08:00
Steven Dan
fe0028bba4 update fptrgroup 2026-03-30 20:07:01 +08:00
Steven Dan
898ef085c0 add mute handler 2026-03-30 20:01:40 +08:00
Steven Dan
f548845a29 key_program 2026-03-30 18:29:19 +08:00
Steven Dan
a4bd3cfc69 update sy102_hid_protocol.md 2026-03-30 16:24:47 +08:00
Steven Dan
c0335779de music 24bit only 2026-03-30 12:19:23 +08:00
Steven Dan
5dbe5d57f3 update uac1 reboot check 2026-03-30 12:18:55 +08:00
Steven Dan
ac774400b3 uac1 playback distortion 2026-03-30 11:32:44 +08:00
Steven Dan
f8ea57d683 uac1 hid 2026-03-30 10:28:50 +08:00
Steven Dan
12c1535e51 uac1 settings 2026-03-28 22:44:14 +08:00
Steven Dan
6c7d3419d7 mute before change mclk 2026-03-28 18:34:12 +08:00
Steven Dan
c821c007a3 uac1 use uac2 mode 2026-03-28 18:33:32 +08:00
Steven Dan
b64f28698f update hid protocol 2026-03-28 14:11:50 +08:00
Steven Dan
7b218d47ac update monitor sw 2026-03-28 14:07:00 +08:00
Steven Dan
f5f6426a0f update hid.xc 2026-03-28 12:27:17 +08:00
Steven Dan
a15bfeb615 update hid commands 2026-03-28 12:27:05 +08:00
Steven Dan
d5338de59b update hid.xc 2026-03-27 23:52:30 +08:00
Steven Dan
d0e98ea135 ai level hid command 2026-03-27 23:50:03 +08:00
Steven Dan
8b56f5cd2d support factory restore key 2026-03-27 23:26:03 +08:00
Steven Dan
9696395dcf switch game and ai71 button 2026-03-27 22:45:14 +08:00
Steven Dan
7d9ea4b367 mute mic when level is 1 2026-03-27 17:57:56 +08:00
Steven Dan
38c105d37d udpate sy102_hid_protocol.md 2026-03-27 15:51:08 +08:00
Steven Dan
e9aa3b4f51 fix mic dac init volume 2026-03-27 12:10:25 +08:00
Steven Dan
207ea21b3f 1.0.2 2026-03-27 11:20:33 +08:00
Steven Dan
5a9bdf6936 1024x mclk 2026-03-27 11:20:00 +08:00
Steven Dan
fcb0ddd7f5 hid dfu 2026-03-27 00:18:35 +08:00
33 changed files with 4981 additions and 877 deletions

View File

@@ -161,32 +161,34 @@ struct lfs_config {
// Read a region in a block. Negative error codes are propagated
// to the user.
int (*read)(const struct lfs_config *c, lfs_block_t block,
int (* __attribute__((fptrgroup("local_block_device_read_fptr_grp"))) read)(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a region in a block. The block must have previously
// been erased. Negative error codes are propagated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*prog)(const struct lfs_config *c, lfs_block_t block,
int (* __attribute__((fptrgroup("local_block_device_prog_fptr_grp"))) prog)(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propagated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*erase)(const struct lfs_config *c, lfs_block_t block);
int (* __attribute__((fptrgroup("local_block_device_erase_fptr_grp"))) erase)(const struct lfs_config *c, lfs_block_t block);
// Sync the state of the underlying block device. Negative error codes
// are propagated to the user.
int (*sync)(const struct lfs_config *c);
int (* __attribute__((fptrgroup("local_block_device_sync_fptr_grp"))) sync)(const struct lfs_config *c);
#ifdef LFS_THREADSAFE
// Lock the underlying block device. Negative error codes
// are propagated to the user.
LFS_FPTRGROUP("lfs_cfg_lock_fptr_grp")
int (*lock)(const struct lfs_config *c);
// Unlock the underlying block device. Negative error codes
// are propagated to the user.
LFS_FPTRGROUP("lfs_cfg_unlock_fptr_grp")
int (*unlock)(const struct lfs_config *c);
#endif
@@ -730,7 +732,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// blocks are in use or how much of the storage is available.
//
// Returns a negative error code on failure.
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
int lfs_fs_traverse(lfs_t *lfs, int (* __attribute__((fptrgroup("lfs_cb_block_fptr_grp"))) cb)(void*, lfs_block_t), void *data);
#ifndef LFS_READONLY
// Attempt to make the filesystem consistent and ready for writing

View File

@@ -63,6 +63,13 @@ extern "C"
#endif
// xCORE fptrgroup attribute for stack analysis
#ifdef __xcore__
#define LFS_FPTRGROUP(name) __attribute__((fptrgroup(name)))
#else
#define LFS_FPTRGROUP(name)
#endif
// Macros, may be replaced by system specific wrappers. Arguments to these
// macros must not have side-effects as the macros can be removed for a smaller
// code footprint

View File

@@ -41,7 +41,7 @@ static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
pcache->block = LFS_BLOCK_NULL;
}
#pragma stackfunction 100
static int lfs_bd_read(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off,
@@ -125,7 +125,7 @@ static int lfs_bd_read(lfs_t *lfs,
return 0;
}
#pragma stackfunction 100
static int lfs_bd_cmp(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off,
@@ -153,7 +153,7 @@ static int lfs_bd_cmp(lfs_t *lfs,
return LFS_CMP_EQ;
}
#pragma stackfunction 100
static int lfs_bd_crc(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off, lfs_size_t size, uint32_t *crc) {
@@ -176,7 +176,7 @@ static int lfs_bd_crc(lfs_t *lfs,
}
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_bd_flush(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) {
@@ -212,7 +212,7 @@ static int lfs_bd_flush(lfs_t *lfs,
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_bd_sync(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
lfs_cache_drop(lfs, rcache);
@@ -229,7 +229,7 @@ static int lfs_bd_sync(lfs_t *lfs,
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_bd_prog(lfs_t *lfs,
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate,
lfs_block_t block, lfs_off_t off,
@@ -278,7 +278,7 @@ static int lfs_bd_prog(lfs_t *lfs,
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
LFS_ASSERT(block < lfs->block_count);
int err = lfs->cfg->erase(lfs->cfg, block);
@@ -593,6 +593,7 @@ static void lfs_fs_prepsuperblock(lfs_t *lfs, bool needssuperblock);
#ifdef LFS_MIGRATE
static int lfs1_traverse(lfs_t *lfs,
LFS_FPTRGROUP("lfs_traverse_cb_fptr_grp")
int (*cb)(void*, lfs_block_t), void *data);
#endif
@@ -607,7 +608,7 @@ static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file);
static lfs_ssize_t lfs_fs_size_(lfs_t *lfs);
static int lfs_fs_traverse_(lfs_t *lfs,
int (*cb)(void *data, lfs_block_t block), void *data,
int (* __attribute__((fptrgroup("lfs_cb_block_fptr_grp"))) cb)(void *data, lfs_block_t block), void *data,
bool includeorphans);
static int lfs_deinit(lfs_t *lfs);
@@ -633,6 +634,7 @@ static void lfs_alloc_drop(lfs_t *lfs) {
}
#ifndef LFS_READONLY
__attribute__((fptrgroup("lfs_cb_block_fptr_grp")))
static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
lfs_t *lfs = (lfs_t*)p;
lfs_block_t off = ((block - lfs->lookahead.start)
@@ -652,7 +654,7 @@ static int lfs_alloc_scan(lfs_t *lfs) {
//
// note we limit the lookahead buffer to at most the amount of blocks
// checkpointed, this prevents the math in lfs_alloc from underflowing
lfs->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next)
lfs->lookahead.start = (lfs->lookahead.start + lfs->lookahead.next)
% lfs->block_count;
lfs->lookahead.next = 0;
lfs->lookahead.size = lfs_min(
@@ -859,7 +861,7 @@ static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir,
}
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_dir_traverse_filter(void *p,
lfs_tag_t tag, const void *buffer) {
lfs_tag_t *filtertag = p;
@@ -912,7 +914,7 @@ struct lfs_dir_traverse {
uint16_t end;
int16_t diff;
int (*cb)(void *data, lfs_tag_t tag, const void *buffer);
int (* __attribute__((fptrgroup("lfs_cb_tag_fptr_grp"))) cb)(void *data, lfs_tag_t tag, const void *buffer);
void *data;
lfs_tag_t tag;
@@ -920,13 +922,13 @@ struct lfs_dir_traverse {
struct lfs_diskoff disk;
};
#pragma stackfunction 200
static int lfs_dir_traverse(lfs_t *lfs,
const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag,
const struct lfs_mattr *attrs, int attrcount,
lfs_tag_t tmask, lfs_tag_t ttag,
uint16_t begin, uint16_t end, int16_t diff,
int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
int (* __attribute__((fptrgroup("lfs_cb_tag_fptr_grp"))) cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
// This function in inherently recursive, but bounded. To allow tool-based
// analysis without unnecessary code-cost we use an explicit stack
struct lfs_dir_traverse stack[LFS_DIR_TRAVERSE_DEPTH-1];
@@ -1116,18 +1118,18 @@ popped:
}
#endif
#pragma stackfunction 100
static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
lfs_mdir_t *dir, const lfs_block_t pair[2],
lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id,
int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
int (* __attribute__((fptrgroup("lfs_cb_tag_fptr_grp"))) cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
// we can find tag very efficiently during a fetch, since we're already
// scanning the entire directory
lfs_stag_t besttag = -1;
// if either block address is invalid we return LFS_ERR_CORRUPT here,
// otherwise later writes to the pair could fail
if (lfs->block_count
if (lfs->block_count
&& (pair[0] >= lfs->block_count || pair[1] >= lfs->block_count)) {
return LFS_ERR_CORRUPT;
}
@@ -1462,6 +1464,7 @@ struct lfs_dir_find_match {
lfs_size_t size;
};
__attribute__((fptrgroup("lfs_cb_tag_fptr_grp")))
static int lfs_dir_find_match(void *data,
lfs_tag_t tag, const void *buffer) {
struct lfs_dir_find_match *name = data;
@@ -1924,6 +1927,7 @@ static int lfs_dir_split(lfs_t *lfs,
#endif
#ifndef LFS_READONLY
__attribute__((fptrgroup("lfs_cb_tag_fptr_grp")))
static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) {
lfs_size_t *size = p;
(void)buffer;
@@ -1941,7 +1945,8 @@ struct lfs_dir_commit_commit {
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
__attribute__((fptrgroup("lfs_cb_tag_fptr_grp")))
static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) {
struct lfs_dir_commit_commit *commit = p;
return lfs_dir_commitattr(commit->lfs, commit->commit, tag, buffer);
@@ -1949,7 +1954,7 @@ static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) {
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static bool lfs_dir_needsrelocation(lfs_t *lfs, lfs_mdir_t *dir) {
// If our revision count == n * block_cycles, we should force a relocation,
// this is how littlefs wear-levels at the metadata-pair level. Note that we
@@ -1963,7 +1968,7 @@ static bool lfs_dir_needsrelocation(lfs_t *lfs, lfs_mdir_t *dir) {
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_dir_compact(lfs_t *lfs,
lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
lfs_mdir_t *source, uint16_t begin, uint16_t end) {
@@ -2137,7 +2142,7 @@ relocate:
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
const struct lfs_mattr *attrs, int attrcount,
lfs_mdir_t *source, uint16_t begin, uint16_t end) {
@@ -2247,7 +2252,7 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_dir_relocatingcommit(lfs_t *lfs, lfs_mdir_t *dir,
const lfs_block_t pair[2],
const struct lfs_mattr *attrs, int attrcount,
@@ -2421,7 +2426,7 @@ fixmlist:;
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_dir_orphaningcommit(lfs_t *lfs, lfs_mdir_t *dir,
const struct lfs_mattr *attrs, int attrcount) {
// check for any inline files that aren't RAM backed and
@@ -2615,7 +2620,7 @@ static int lfs_dir_orphaningcommit(lfs_t *lfs, lfs_mdir_t *dir,
#endif
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
const struct lfs_mattr *attrs, int attrcount) {
int orphans = lfs_dir_orphaningcommit(lfs, dir, attrs, attrcount);
@@ -2640,7 +2645,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
/// Top level directory operations ///
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_mkdir_(lfs_t *lfs, const char *path) {
// deorphan if we haven't yet, needed at most once after poweron
int err = lfs_fs_forceconsistency(lfs);
@@ -2736,7 +2741,7 @@ static int lfs_mkdir_(lfs_t *lfs, const char *path) {
return 0;
}
#endif
#pragma stackfunction 100
static int lfs_dir_open_(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL);
if (tag < 0) {
@@ -2781,7 +2786,7 @@ static int lfs_dir_open_(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
return 0;
}
#pragma stackfunction 100
static int lfs_dir_close_(lfs_t *lfs, lfs_dir_t *dir) {
// remove from list of mdirs
lfs_mlist_remove(lfs, (struct lfs_mlist *)dir);
@@ -2789,7 +2794,7 @@ static int lfs_dir_close_(lfs_t *lfs, lfs_dir_t *dir) {
return 0;
}
#pragma stackfunction 100
static int lfs_dir_read_(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
memset(info, 0, sizeof(*info));
@@ -2835,7 +2840,7 @@ static int lfs_dir_read_(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
return true;
}
#pragma stackfunction 100
static int lfs_dir_seek_(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
// simply walk from head dir
int err = lfs_dir_rewind_(lfs, dir);
@@ -3042,7 +3047,7 @@ relocate:
static int lfs_ctz_traverse(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache,
lfs_block_t head, lfs_size_t size,
int (*cb)(void*, lfs_block_t), void *data) {
int (* __attribute__((fptrgroup("lfs_cb_block_fptr_grp"))) cb)(void*, lfs_block_t), void *data) {
if (size == 0) {
return 0;
}
@@ -3285,7 +3290,7 @@ static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file) {
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
while (true) {
// just relocate what exists into new block
@@ -3451,7 +3456,7 @@ relocate:
}
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file) {
if (file->flags & LFS_F_ERRED) {
// it's not safe to do anything if our file errored
@@ -3593,7 +3598,7 @@ static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
#ifndef LFS_READONLY
#pragma stackfunction 100
static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size) {
const uint8_t *data = buffer;
@@ -3678,7 +3683,7 @@ relocate:
return size;
}
#pragma stackfunction 100
static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size) {
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
@@ -3723,7 +3728,7 @@ static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
}
#endif
#pragma stackfunction 100
static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t off, int whence) {
// find new pos
@@ -3782,7 +3787,7 @@ static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file,
}
#ifndef LFS_READONLY
#pragma stackfunction 100
static int lfs_file_truncate_(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
@@ -4679,7 +4684,7 @@ static int lfs_unmount_(lfs_t *lfs) {
/// Filesystem filesystem operations ///
#pragma stackfunction 100
static int lfs_fs_stat_(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
// if the superblock is up-to-date, we must be on the most recent
// minor version of littlefs
@@ -4720,9 +4725,9 @@ static int lfs_fs_stat_(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
return 0;
}
#pragma stackfunction 100
int lfs_fs_traverse_(lfs_t *lfs,
int (*cb)(void *data, lfs_block_t block), void *data,
int (* __attribute__((fptrgroup("lfs_cb_block_fptr_grp"))) cb)(void *data, lfs_block_t block), void *data,
bool includeorphans) {
// iterate over metadata pairs
lfs_mdir_t dir = {.tail = {0, 1}};
@@ -5200,6 +5205,7 @@ static int lfs_fs_mkconsistent_(lfs_t *lfs) {
}
#endif
__attribute__((fptrgroup("lfs_cb_block_fptr_grp")))
static int lfs_fs_size_count(void *p, lfs_block_t block) {
(void)block;
lfs_size_t *size = p;
@@ -5550,7 +5556,9 @@ static int lfs1_dir_next(lfs_t *lfs, lfs1_dir_t *dir, lfs1_entry_t *entry) {
}
/// littlefs v1 specific operations ///
int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
int lfs1_traverse(lfs_t *lfs,
LFS_FPTRGROUP("lfs_traverse_cb_fptr_grp")
int (*cb)(void*, lfs_block_t), void *data) {
if (lfs_pair_isnull(lfs->lfs1->root)) {
return 0;
}
@@ -6196,7 +6204,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
}
#ifndef LFS_READONLY
#pragma stackfunction 100
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
int err = LFS_LOCK(lfs->cfg);
if (err) {
@@ -6459,7 +6467,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs) {
return res;
}
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
int lfs_fs_traverse(lfs_t *lfs, int (* __attribute__((fptrgroup("lfs_cb_block_fptr_grp"))) cb)(void *, lfs_block_t), void *data) {
int err = LFS_LOCK(lfs->cfg);
if (err) {
return err;
@@ -6552,4 +6560,3 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
return err;
}
#endif

View File

@@ -579,7 +579,7 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
unsigned char hidReportDescriptorLengthLo = hidReportDescriptorLength & 0xFF;
unsigned char hidReportDescriptorLengthHi = (hidReportDescriptorLength & 0xFF00) >> 8;
#if( AUDIO_CLASS == 1 )
#if( AUDIO_CLASS == 1 && HID_CONTROLS_UAC1 == 1)
cfgDesc_Audio1[USB_HID_DESCRIPTOR_OFFSET + HID_DESCRIPTOR_LENGTH_FIELD_OFFSET ] = hidReportDescriptorLengthLo;
cfgDesc_Audio1[USB_HID_DESCRIPTOR_OFFSET + HID_DESCRIPTOR_LENGTH_FIELD_OFFSET + 1] = hidReportDescriptorLengthHi;
#endif

View File

@@ -2392,12 +2392,18 @@ const unsigned num_freqs_a1 = MAX(3, (0
* - xua_hid_endpoint_descriptor_contents.h and
* - xua_hid_interface_descriptor_contents.h
*/
#if (HID_CONTROLS_UAC1 == 1)
#define HID_INTERFACE_BYTES ( 9 + 9 + (7 * (1 + HID_OUT_REQUIRED))) // always IN
#define HID_INTERFACES_A1 1
#else
#define HID_INTERFACE_BYTES 0
#define HID_INTERFACES_A1 0
#endif
#else
#define HID_INTERFACE_BYTES 0
#define HID_INTERFACES_A1 0
#endif
/* Total number of bytes returned for the class-specific AudioControl interface descriptor.
* Includes the combined length of this descriptor header and all Unit and Terminal descriptors
@@ -2409,13 +2415,13 @@ const unsigned num_freqs_a1 = MAX(3, (0
#define STREAMING_INTERFACES (INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1)
/* Number of interfaces for Audio 1.0 (+1 for control ) */
/* Note, this is different than INTERFACE_COUNT since we dont support items such as MIDI, iAP etc in UAC1 mode */
#define NUM_INTERFACES_A1 (1 + INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1 + MIDI_INTERFACES_A1 + NUM_CONTROL_USB_INTERFACES + DFU_INTERFACES_A1 + HID_INTERFACES_A1)
/* Note, this is different that INTERFACE_COUNT since we dont support items such as MIDI, iAP etc in UAC1 mode */
#define NUM_INTERFACES_A1 (1 + INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1 + NUM_CONTROL_USB_INTERFACES + DFU_INTERFACES_A1 + HID_INTERFACES_A1)
#if ((NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP)) && (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + MIDI_INTERFACE_BYTES + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES)
#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES)
#else
#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + MIDI_INTERFACE_BYTES + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES)
#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES)
#endif
#define INTERFACE_DESCRIPTOR_BYTES (9)
@@ -2435,7 +2441,7 @@ const unsigned num_freqs_a1 = MAX(3, (0
#endif
#if XUA_OR_STATIC_HID_ENABLED
#define USB_HID_DESCRIPTOR_OFFSET (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + MIDI_INTERFACE_BYTES + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + INTERFACE_DESCRIPTOR_BYTES)
#define USB_HID_DESCRIPTOR_OFFSET (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + 9 + 9 )
#endif
#define CHARIFY_SR(x) (x & 0xff),((x & 0xff00)>> 8),((x & 0xff0000)>> 16)

View File

@@ -23,7 +23,7 @@
*/
#ifndef FLASH_MAX_UPGRADE_SIZE
//#define FLASH_MAX_UPGRADE_SIZE (512 * 1024)
#define FLASH_MAX_UPGRADE_SIZE (0x1a0000)
#define FLASH_MAX_UPGRADE_SIZE (2200 * 1024)
#endif
#define FLASH_ERROR() do {} while(0)

View File

@@ -31,9 +31,9 @@ XUD_Result_t HidInterfaceClassRequests(
#endif
USB_SetupPacket_t &sp )
{
unsigned char buffer[65] = {0};
#if ((USE_EX3D == 1) || (EQ_EN == 1) || (DEBUG_MEMORY_LOG_ENABLED == 1) )
unsigned datalength;
unsigned char buffer[65] = {0};
#endif
XUD_Result_t result = XUD_RES_ERR;
@@ -83,7 +83,8 @@ XUD_Result_t HidInterfaceClassRequests(
#endif
}
if (buffer[1] == 0x77 && buffer[2] >= 0x8A)
if (buffer[1] == 0x77 && ((buffer[2] >= 0x82) || (buffer[2] == 0x5b)))
{
process_send_params(&buffer[1], datalength - 1);
}

View File

@@ -38,7 +38,7 @@ endif()
# Firmware version (maps to BCD_DEVICE_J.M.N in USB descriptor)
set(FW_VER_J 1)
set(FW_VER_M 0)
set(FW_VER_N 0)
set(FW_VER_N 10)
set(FW_VERSION "v${FW_VER_J}.${FW_VER_M}.${FW_VER_N}")
set(SW_USB_AUDIO_FLAGS ${EXTRA_BUILD_FLAGS} -Os
@@ -54,8 +54,7 @@ set(SW_USB_AUDIO_FLAGS ${EXTRA_BUILD_FLAGS} -Os
-DBCD_DEVICE_M=${FW_VER_M}
-DBCD_DEVICE_N=${FW_VER_N}
-D${CODEC_IC}
-DWINDOWS_OS_DESCRIPTOR_SUPPORT
-DDEBUG_PRINT_ENABLE=0)
-DWINDOWS_OS_DESCRIPTOR_SUPPORT)
set(SW_USB_FACT_FLAGS ${EXTRA_BUILD_FLAGS} -Os
-report
@@ -70,8 +69,7 @@ set(SW_USB_FACT_FLAGS ${EXTRA_BUILD_FLAGS} -Os
-DBCD_DEVICE_M=5
-DBCD_DEVICE_N=6
-D${CODEC_IC}
-DWINDOWS_OS_DESCRIPTOR_SUPPORT
-DDEBUG_PRINT_ENABLE=0)
-DWINDOWS_OS_DESCRIPTOR_SUPPORT)
@@ -82,32 +80,33 @@ set(APP_COMPILER_FLAGS_f5_music_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC
-DAUDIO_CLASS=1
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DMCLK_441=512*44100
-DMCLK_48=512*48000
-DUAC1_MODE=1
-DF5_MUSIC_UAC1=1
-DUSE_EX3D
#-DUSE_EX3D
-DMIXER=0
#-ldnr_50ms
#-DDNR_ENABLE=1
-llib_ex3d_all
-ldnr_50ms
-DDNR_ENABLE=1
#-llib_ex3d_all
-DEQ_EN=1
-DEX3D_SF_NUM=3
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_OUT_FS=2
-DNUM_USB_CHAN_IN=2
-DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=16
-DSTREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS=16
-DSTREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_2_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_3_RESOLUTION_BITS=16
-DNUM_EX3D_CHAN_OUT=2
-DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=24
-DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=24
-DINPUT_FORMAT_COUNT=1
-DOUTPUT_FORMAT_COUNT=1
#-DNUM_EX3D_CHAN_OUT=2
-DMIN_VOLUME=0xE000
-DINPUT_VOLUME_CONTROL=1
-DOUTPUT_VOLUME_CONTROL=1
-DDEBUG_MEMORY_LOG_ENABLED=1
-DINPUT_VOLUME_CONTROL=0
-DOUTPUT_VOLUME_CONTROL=0
#-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=0
-DIR_SWITCHING_MODE
-DHID_CONTROLS=0)
-DHID_CONTROLS_UAC1=1
#-DIR_SWITCHING_MODE
-DHID_CONTROLS=1)
@@ -130,9 +129,10 @@ set(APP_COMPILER_FLAGS_fact ${SW_USB_FACT_FLAGS} -DI2S_CHANS_DAC=2
-DINPUT_VOLUME_CONTROL=0
-DOUTPUT_VOLUME_CONTROL=0
-DDEBUG_MEMORY_LOG_ENABLED=1
-DHID_DFU_EN=1
-DXUA_DFU_EN=1
#-DIR_SWITCHING_MODE
-DHID_CONTROLS=0)
-DHID_CONTROLS=1)
@@ -141,6 +141,12 @@ set(APP_COMPILER_FLAGS_f1_music_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC
-DMIN_FREQ=44100
-DMAX_FREQ=192000
-DF1_MUSIC_UAC2=1
-DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=24
-DSTREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS=24
-DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=24
-DSTREAM_FORMAT_INPUT_2_RESOLUTION_BITS=24
-DINPUT_FORMAT_COUNT=1
-DOUTPUT_FORMAT_COUNT=1
#-DUSE_EX3D
-DMIXER=0
-DUAC2_MODE=1
@@ -156,6 +162,7 @@ set(APP_COMPILER_FLAGS_f1_music_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC
-DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1
-DHID_DFU_EN=1
#-DIR_SWITCHING_MODE
-DHID_CONTROLS=1)
@@ -172,6 +179,10 @@ set(APP_COMPILER_FLAGS_f3_f4_fps_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-llib_ex3d_all
-DEQ_EN=1
-DDNR_ENABLE=1
-DSTREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS=16
-DSTREAM_FORMAT_INPUT_1_RESOLUTION_BITS=16
-DINPUT_FORMAT_COUNT=1
-DOUTPUT_FORMAT_COUNT=1
-DEX3D_SF_NUM=3
-DNUM_USB_CHAN_OUT=8
-DNUM_USB_CHAN_IN=2
@@ -181,13 +192,17 @@ set(APP_COMPILER_FLAGS_f3_f4_fps_uac2 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1
-DHID_DFU_EN=1
-DIR_SWITCHING_MODE
-DHID_CONTROLS=1)
set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DI2S_CHANS_ADC=2
-DAUDIO_CLASS=1
-DMIN_FREQ=48000
-DMAX_FREQ=48000
-DMCLK_441=512*44100
-DMCLK_48=512*48000
-DUAC1_MODE=1
-DUSE_EX3D=1
-DF6_F7_FPS_UAC1=1
@@ -204,6 +219,7 @@ set(APP_COMPILER_FLAGS_f6_f7_fps_uac1 ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
-DOUTPUT_VOLUME_CONTROL=1
#-DDEBUG_MEMORY_LOG_ENABLED=1
-DXUA_DFU_EN=1
-DHID_DFU_EN=1
-DIR_SWITCHING_MODE
-DHID_CONTROLS=1)

View File

@@ -1,3 +1,3 @@
xflash bin/fact/app_usb_aud_sy102_fact.xe --loader loader.o --upgrade 2 bin/f5_music_uac1/app_usb_aud_sy102_f5_music_uac1.xe --upgrade 3 bin/f1_music_uac2/app_usb_aud_sy102_f1_music_uac2.xe --upgrade 1 bin/f3_f4_fps_uac2/app_usb_aud_sy102_f3_f4_fps_uac2.xe -o %1
xflash bin/fact/app_usb_aud_sy102_fact.xe --loader loader.o --upgrade 2 bin/f5_music_uac1/app_usb_aud_sy102_f5_music_uac1.xe --upgrade 3 bin/f1_music_uac2/app_usb_aud_sy102_f1_music_uac2.xe --upgrade 1 bin/f3_f4_fps_uac2/app_usb_aud_sy102_f3_f4_fps_uac2.xe --upgrade 4 bin/f6_f7_fps_uac1/app_usb_aud_sy102_f6_f7_fps_uac1.xe -o %1
rem --upgrade 4 bin/f6_f7_fps_uac1/app_usb_aud_sy102_f6_f7_fps_uac1.xe

View File

@@ -1,2 +1 @@
xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin\ex3d_UAC1\app_usb_aud_phaten_gs_ex3d_UAC1.xe --upgrade 4 bin/ex3d_stereo_2k/app_usb_aud_phaten_gs_ex3d_stereo_2k.xe --upgrade 1 bin\ex3d_71_game\app_usb_aud_phaten_gs_ex3d_71_game.xe --upgrade 3 bin\ex3d_71_movie\app_usb_aud_phaten_gs_ex3d_71_movie.xe -o %1
xflash --factory-version 15.3 --target-file src/core/synido.xn --upgrade 2 bin/f5_music_uac1/app_usb_aud_sy102_f5_music_uac1.xe --upgrade 3 bin/f1_music_uac2/app_usb_aud_sy102_f1_music_uac2.xe --upgrade 1 bin/f3_f4_fps_uac2/app_usb_aud_sy102_f3_f4_fps_uac2.xe -o %1

View File

@@ -35,8 +35,8 @@
<Port Location="XS1_PORT_8D" Name="PORT_HP_GAIN_ENCODER"/> <!-- 8D4: HP_GAIN_ENCODER_INPUT_1; 8D5: HP_GAIN_ENCODER_INPUT_2; 8D6: HP MUTE -->
<!-- Buttons -->
<Port Location="XS1_PORT_1A" Name="PORT_BUTTON_MUSIC_MODE"/>
<Port Location="XS1_PORT_1L" Name="PORT_BUTTON_GAME_MODE"/>
<Port Location="XS1_PORT_1M" Name="PORT_BUTTON_AI71_ONOFF"/>
<Port Location="XS1_PORT_1M" Name="PORT_BUTTON_GAME_MODE"/>
<Port Location="XS1_PORT_1L" Name="PORT_BUTTON_AI71_ONOFF"/>
<!-- Clocking -->
<Port Location="XS1_PORT_16B" Name="PORT_MCLK_COUNT"/>
@@ -52,7 +52,8 @@
<Port Location="XS1_PORT_1K" Name="PORT_I2S_DAC0"/> <!-- orig 1P, Synido 1K -->
<Port Location="XS1_PORT_1A" Name="PORT_I2S_ADC0"/> <!-- orig 1I, Synido 1A -->
<Port Location="XS1_PORT_4D" Name="PORT_CTL_MUTE"/> <!-- Tile1 4D0 -->
<Port Location="XS1_PORT_4A" Name="PORT_CTL_MUTE"/> <!-- Tile1 4D0 -->
<Port Location="XS1_PORT_4D" Name="PORT_CTL_DET"/> <!-- Tile1 4D0 -->
</Tile>
</Node>

View File

@@ -110,19 +110,11 @@
/*** Defines relating to audio frequencies ***/
/* Master clock defines (in Hz) */
#ifndef MCLK_441
#if defined(F1_MUSIC_UAC2)
#define MCLK_441 (1024*44100) /* 44.1, 88.2 etc */
#else
#define MCLK_441 (256*44100) /* 44.1, 88.2 etc */
#endif
#endif
#ifndef MCLK_48
#if defined(F1_MUSIC_UAC2)
#define MCLK_48 (1024*48000) /* 48, 96 etc */
#else
#define MCLK_48 (256*48000) /* 48, 96 etc */
#endif
#endif
/* Minumum sample frequency device runs at */
@@ -197,6 +189,139 @@
/*
* New spispec for QF60 board
* */
#define FL_QUADDEVICE_GD25Q32E \
{ \
0, /* XT25F16F - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0xc84016, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x0,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_ZB25VQ32D_2 \
{ \
0, /* XT25F16F - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0x5E6016, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x0,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_ZB25VQ32D \
{ \
0, /* XT25F16F - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0x5E4016, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x0,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_PY25Q32SH \
{ \
0, /* XT25F16F - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0x856016, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x0,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_PY25Q32H \
{ \
0, /* XT25F16F - Just specify 0 as flash_id */ \
256, /* page size */ \
16384, /* num pages */ \
3, /* address size */ \
4, /* log2 clock divider */ \
0x9F, /* QSPI_RDID */ \
0, /* id dummy bytes */ \
3, /* id size in bytes */ \
0x852016, /* device id */ \
0x20, /* QSPI_SE */ \
4096, /* Sector erase is always 4KB */ \
0x06, /* QSPI_WREN */ \
0x04, /* QSPI_WRDI */ \
PROT_TYPE_SR, /* Protection via SR */ \
{{0x0,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \
0x02, /* QSPI_PP */ \
0xEB, /* QSPI_READ_FAST */ \
1, /* 1 read dummy byte */ \
SECTOR_LAYOUT_REGULAR, /* mad sectors */ \
{4096,{0,{0}}}, /* regular sector sizes */ \
0x05, /* QSPI_RDSR */ \
0x01, /* QSPI_WRSR */ \
0x01, /* QSPI_WIP_BIT_MASK */ \
}
#define FL_QUADDEVICE_XT25F16F \
{ \
@@ -370,7 +495,7 @@
// DFU_FLASH_DEVICE is a comma-separated list of flash spec structures
// This define is used in lib_xua/lib_xua/src/dfu/flashlib_user.c
#define DFU_FLASH_DEVICE FL_QUADDEVICE_XT25F16F, FL_QUADDEVICE_WINBOND_W25Q16JW, FL_QUADDEVICE_UC25HQ16B, FL_QUADDEVICE_WINBOND_W25Q32JVxxxM, FL_QUADDEVICE_MX25R3235, FL_QUADDEVICE_MX25L160E
#define DFU_FLASH_DEVICE FL_QUADDEVICE_GD25Q32E, FL_QUADDEVICE_ZB25VQ32D, FL_QUADDEVICE_ZB25VQ32D_2, FL_QUADDEVICE_PY25Q32SH, FL_QUADDEVICE_PY25Q32H, FL_QUADDEVICE_XT25F16F, FL_QUADDEVICE_WINBOND_W25Q16JW, FL_QUADDEVICE_UC25HQ16B, FL_QUADDEVICE_WINBOND_W25Q32JVxxxM, FL_QUADDEVICE_MX25R3235, FL_QUADDEVICE_MX25L160E
//:
#include "user_main.h"

View File

@@ -15,8 +15,13 @@
#include "share_buffer.h"
void dnr_exchange_buffer(int32_t *data);
void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]) {
extern uint32_t init_eq_data(unsigned sample_freq);
void dnr_exchange_buffer(int32_t *data);
// sample_freq 作为首字发送给 tile[0] 的 dsp_main用于采样率变化检测和 EQ 初始化
void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[], unsigned sample_freq) {
chan_out_word(c_data, sample_freq);
chan_out_buf_word (c_data, sampsFromUsbToAudio, 2);
chan_in_buf_word (c_data , sampsFromUsbToAudio, 2);
#if DNR_ENABLE == 1
@@ -29,12 +34,27 @@ void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned
void dsp_main (chanend_t c_data) {
int play_input[NUM_USB_CHAN_OUT];
int play_output[I2S_CHANS_DAC];
int mic_input[NUM_USB_CHAN_IN];
int mic_input[I2S_CHANS_ADC];
int mic_output[I2S_CHANS_ADC];
int count = 0;
unsigned ch[1] = {2};
unsigned current_sample_freq = 0;
while (1) {
chan_in_buf_word (c_data , play_input, 2) ;
unsigned sample_freq = (unsigned)chan_in_word(c_data);
chan_in_buf_word (c_data , play_input, 2);
// 采样率变化:重新初始化 EQ 系数并清空 ring buffer避免残留状态污染
if (sample_freq != current_sample_freq && sample_freq != 0) {
current_sample_freq = sample_freq;
init_eq_data(sample_freq);
clear_ring_buffer(0);
clear_ring_buffer(1);
clear_ring_buffer(2);
clear_ring_buffer(3);
play_output[0] = 0;
play_output[1] = 0;
}
chan_out_buf_word (c_data , play_output, I2S_CHANS_DAC);
#if DNR_ENABLE == 1
chan_in_buf_word (c_data , mic_input, 2) ;
@@ -49,6 +69,5 @@ void dsp_main (chanend_t c_data) {
mic_output[0] = mic_input[0];
mic_output[1] = mic_input[1];
#endif
// dnr_exchange_buffer((int32_t *)mic_input, (int32_t *)mic_output);
}
}
}

View File

@@ -0,0 +1,273 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#define DEBUG_PRINT_ENABLE 0
#include <xs1.h>
#include <flash.h>
#include <flashlib.h>
#include <string.h>
#include <xclib.h>
#include <stdio.h>
#include "debug_print.h"
#include "xua.h"
#if HID_DFU_EN
#ifndef DFU_FLASH_MAX_UPGRADE_SIZE
#define DFU_FLASH_MAX_UPGRADE_SIZE (2200 * 1024)
#endif
#define DFU_FLASH_ERROR()
static int dfu_flash_device_open = 0;
static fl_BootImageInfo dfu_factory_image;
static fl_BootImageInfo dfu_upgrade_image;
static int dfu_upgrade_image_valid = 0;
static int dfu_current_flash_subpage_index = 0;
static unsigned char dfu_current_flash_page_data[256];
int dfu_flash_cmd_enable_ports() __attribute__ ((weak));
int dfu_flash_cmd_enable_ports() {
return 0;
}
int dfu_flash_cmd_disable_ports() __attribute__ ((weak));
int dfu_flash_cmd_disable_ports() {
return 0;
}
void DFUCustomFlashEnable() __attribute__ ((weak));
void DFUCustomFlashEnable()
{
return;
}
void DFUCustomFlashDisable() __attribute__ ((weak));
void DFUCustomFlashDisable()
{
return;
}
/* Returns non-zero for error */
int dfu_flash_cmd_init(void)
{
debug_printf("dfu_flash_cmd_init: dfu_flash_cmd_init\n");
fl_BootImageInfo image;
if (!dfu_flash_device_open)
{
if (dfu_flash_cmd_enable_ports())
dfu_flash_device_open = 1;
debug_printf("dfu_flash_cmd_init: dfu_flash_device_open = 1\n");
}
if (!dfu_flash_device_open)
{
debug_printf("dfu_flash_cmd_init: dfu_flash_device_open = 0\n");
return 1;
}
#if (!XUA_QUAD_SPI_FLASH)
// Disable flash protection
fl_setProtection(0);
#endif
if (fl_getFactoryImage(&image) != 0)
{
return 1;
}
dfu_factory_image = image;
if (fl_getNextBootImage(&image) == 0)
{
dfu_upgrade_image_valid = 1;
dfu_upgrade_image = image;
debug_printf("dfu_flash_cmd_init: dfu_upgrade_image_valid = 1\n");
}
debug_printf("dfu_flash_cmd_init: return 0\n");
return 0;
}
int dfu_flash_cmd_deinit(void)
{
if (!dfu_flash_device_open)
return 0;
dfu_flash_cmd_disable_ports();
dfu_flash_device_open = 0;
return 0;
}
int dfu_flash_cmd_read_page(unsigned char *data)
{
if (!dfu_upgrade_image_valid)
{
*(unsigned int *)data = 1;
return 4;
}
if (*(unsigned int *)data == 0)
{
fl_startImageRead(&dfu_upgrade_image);
}
dfu_current_flash_subpage_index = 0;
if (fl_readImagePage(dfu_current_flash_page_data) == 0)
{
*(unsigned int *)data = 0;
}
else
{
*(unsigned int *)data = 1;
}
return 4;
}
int dfu_flash_cmd_read_page_data(unsigned char *data)
{
unsigned char *page_data_ptr = &dfu_current_flash_page_data[dfu_current_flash_subpage_index * 64];
memcpy(data, page_data_ptr, 64);
dfu_current_flash_subpage_index++;
return 64;
}
static int begin_write()
{
int result;
// TODO this will take a long time. To minimise the amount of time spent
// paused on this operation it would be preferable to move to this to a
// seperate command, e.g. start_write.
do
{
result = fl_startImageAdd(&dfu_factory_image, DFU_FLASH_MAX_UPGRADE_SIZE, 0);
} while (result > 0);
if (result < 0)
{
DFU_FLASH_ERROR();
}
return result;
}
static int pages_written = 0;
int dfu_flash_cmd_write_page(unsigned char *data)
{
/* 改动原因:协议仅约定第一个字节为 flag(0=第一页,1=后续页,2=结束)
* 若用 *(unsigned int *)data 读取 4 字节,而调用处只设置 data[0]=0 且未清零 data[1..3]
* 则 flag 可能非 0导致不进入 case 0begin_write() 被跳过。改为仅用首字节。 */
unsigned int flag = (unsigned int)data[0];
if (flag == 0)
debug_printf("dfu_flash_cmd_write_page: flag = %d\n", flag);
if (dfu_upgrade_image_valid)
{
debug_printf("dfu_flash_cmd_write_page: dfu_upgrade_image_valid = 1\n");
return 0;
}
switch (flag)
{
case 0:
// First page.
debug_printf("dfu_flash_cmd_write_page: begin_write\n");
int result = begin_write();
if (result < 0)
return result;
pages_written = 0;
// fallthrough
case 1:
// Do nothing.
break;
case 2:
// Termination.
if (fl_endWriteImage() != 0)
DFU_FLASH_ERROR();
// Sanity check
fl_BootImageInfo image = dfu_factory_image;
if (fl_getNextBootImage(&image) != 0)
DFU_FLASH_ERROR();
break;
}
dfu_current_flash_subpage_index = 0;
return 0;
}
int dfu_flash_cmd_write_page_data(unsigned char *data)
{
unsigned char *page_data_ptr = &dfu_current_flash_page_data[dfu_current_flash_subpage_index * 64];
if (dfu_upgrade_image_valid)
{
return 0;
}
if (dfu_current_flash_subpage_index >= 4)
{
return 0;
}
memcpy(page_data_ptr, data, 64);
dfu_current_flash_subpage_index++;
if (dfu_current_flash_subpage_index == 4)
{
if (fl_writeImagePage(dfu_current_flash_page_data) != 0)
DFU_FLASH_ERROR();
pages_written++;
}
return 0;
}
int dfu_flash_cmd_erase_all(void)
{
fl_BootImageInfo tmp_image = dfu_upgrade_image;
if (dfu_upgrade_image_valid)
{
if (fl_deleteImage(&dfu_upgrade_image) != 0)
{
DFU_FLASH_ERROR();
}
// Keep deleting all upgrade images
// TODO Perhaps using replace would be nicer...
while(1)
{
if (fl_getNextBootImage(&tmp_image) == 0)
{
if (fl_deleteImage(&tmp_image) != 0)
{
DFU_FLASH_ERROR();
}
}
else
{
break;
}
}
dfu_upgrade_image_valid = 0;
}
/* 改动原因强制升级流程中erase 后必须允许后续第一页写执行 begin_write()
* 若仅在上面 if 块内清零,某些路径(如删除失败或 while 未正确退出)可能导致
* dfu_upgrade_image_valid 仍为 1write_page(flag=0) 会直接 return 0 而不调用
* begin_write(),导致 begin_write 未执行。此处无条件清零,保证 erase 后下一
* 次 write_page(0) 必定执行 begin_write。 */
dfu_upgrade_image_valid = 0;
debug_printf("dfu_flash_cmd_erase_all: set dfu_upgrade_image_valid = 0\n");
return 0;
}
#endif

View File

@@ -0,0 +1,34 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _dfu_flash_interface_h_
#define _dfu_flash_interface_h_
int dfu_flash_cmd_init(void);
/**
* Prepare to write a page of a new upgrade image.
* The first word of data should be set to 0 if it is the first page,
* 1 for all other pages and 2 to terminate the write (no further data is sent).
*/
int dfu_flash_cmd_write_page(unsigned char []);
/**
* Provide upgrade image data. flash_cmd_write_page() must be called previously.
* Once a page of data has been provided it is written to the device.
*/
int dfu_flash_cmd_write_page_data(unsigned char []);
/**
* Read a page of data from the upgrade image.
* If the first word of data is 0 the page is read from the start of the
* upgrade image, otherwise the next page in the image will be read.
* On return the first word of data is written with 1 if there is nothing to
* read and 0 otherwise.
*/
int dfu_flash_cmd_read_page(unsigned char []);
/**
* Get data previously read by flash_cmd_read_page().
*/
int dfu_flash_cmd_read_page_data(unsigned char []);
int dfu_flash_cmd_erase_all(void);
int dfu_flash_cmd_reboot(void);
int dfu_flash_cmd_init(void);
int dfu_flash_cmd_deinit(void);
#endif /*_dfu_flash_interface_h_*/

View File

@@ -0,0 +1,129 @@
// Copyright 2012-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h"
#if (XUA_DFU_EN == 1 || UAC1 == 1)
#include "uac_hwresources.h"
#include <xs1.h>
#include <xclib.h>
#if (XUA_QUAD_SPI_FLASH)
#include <quadflashlib.h>
#else
#include <flashlib.h>
#endif
#include <print.h>
#define settw(a,b) {__asm__ __volatile__("settw res[%0], %1": : "r" (a) , "r" (b));}
#define setc(a,b) {__asm__ __volatile__("setc res[%0], %1": : "r" (a) , "r" (b));}
#define setclk(a,b) {__asm__ __volatile__("setclk res[%0], %1": : "r" (a) , "r" (b));}
#define portin(a,b) {__asm__ __volatile__("in %0, res[%1]": "=r" (b) : "r" (a));}
#define portout(a,b) {__asm__ __volatile__("out res[%0], %1": : "r" (a) , "r" (b));}
#ifdef DFU_FLASH_DEVICE
#if (XUA_QUAD_SPI_FLASH)
/* Using specified flash device rather than all supported in tools */
fl_QuadDeviceSpec dfu_flash_devices[] = {DFU_FLASH_DEVICE};
#else
/* Using specified flash device rather than all supported in tools */
fl_DeviceSpec dfu_flash_devices[] = {DFU_FLASH_DEVICE};
#endif
#endif
#if (XUA_QUAD_SPI_FLASH)
/*
typedef struct {
out port qspiCS;
out port qspiSCLK;
out buffered port:32 qspiSIO;
clock qspiClkblk;
} fl_QSPIPorts;
*/
fl_QSPIPorts dfu_p_qflash =
{
XS1_PORT_1B,
XS1_PORT_1C,
XS1_PORT_4B,
CLKBLK_FLASHLIB
};
#else
fl_PortHolderStruct p_flash =
{
XS1_PORT_1A,
XS1_PORT_1B,
XS1_PORT_1C,
XS1_PORT_1D,
CLKBLK_FLASHLIB
};
#endif
/* return 1 for opened ports successfully */
int dfu_flash_cmd_enable_ports()
{
int result = 0;
#if (XUA_QUAD_SPI_FLASH)
/* Ports not shared */
#else
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
setc(p_flash.spiSS, XS1_SETC_INUSE_OFF);
setc(p_flash.spiClkblk, XS1_SETC_INUSE_OFF);
setc(p_flash.spiMISO, XS1_SETC_INUSE_ON);
setc(p_flash.spiCLK, XS1_SETC_INUSE_ON);
setc(p_flash.spiMOSI, XS1_SETC_INUSE_ON);
setc(p_flash.spiSS, XS1_SETC_INUSE_ON);
setc(p_flash.spiClkblk, XS1_SETC_INUSE_ON);
setc(p_flash.spiClkblk, XS1_SETC_INUSE_ON);
setclk(p_flash.spiMISO, XS1_CLKBLK_REF);
setclk(p_flash.spiCLK, XS1_CLKBLK_REF);
setclk(p_flash.spiMOSI, XS1_CLKBLK_REF);
setclk(p_flash.spiSS, XS1_CLKBLK_REF);
setc(p_flash.spiMISO, XS1_SETC_BUF_BUFFERS);
setc(p_flash.spiMOSI, XS1_SETC_BUF_BUFFERS);
settw(p_flash.spiMISO, 8);
settw(p_flash.spiMOSI, 8);
#endif
#ifdef DFU_FLASH_DEVICE
#if (XUA_QUAD_SPI_FLASH)
result = fl_connectToDevice(&dfu_p_qflash, dfu_flash_devices, sizeof(dfu_flash_devices) / sizeof(fl_QuadDeviceSpec));
#else
result = fl_connectToDevice(&dfu_p_flash, dfu_flash_devices, sizeof(dfu_flash_devices) / sizeof(fl_DeviceSpec));
#endif
#else
/* Use default flash list */
#if (XUA_QUAD_SPI_FLASH)
result = fl_connect(&dfu_p_qflash);
#else
result = fl_connect(&dfu_p_flash);
#endif
#endif
if (!result)
{
/* All okay.. */
return 1;
}
else
{
return 0;
}
}
int dfu_flash_cmd_disable_ports()
{
fl_disconnect();
#if (!XUA_QUAD_SPI_FLASH)
setc(p_flash.spiMISO, XS1_SETC_INUSE_OFF);
setc(p_flash.spiCLK, XS1_SETC_INUSE_OFF);
setc(p_flash.spiMOSI, XS1_SETC_INUSE_OFF);
setc(p_flash.spiSS, XS1_SETC_INUSE_OFF);
#endif
return 1;
}
#endif

View File

@@ -0,0 +1,436 @@
// Copyright 2026 Shanling.
// HID固件升级实现文件 (adapted for app_usb_aud_phaten_golden_6ch)
#define DEBUG_PRINT_ENABLE 0
#include "dfu_upgrade.h"
#include "user_func.h"
#include "dfu_flash_interface.h"
#include <string.h>
#include <stdio.h>
#include "debug_print.h"
#if HID_DFU_EN
// 外部函数声明
extern void hidSetChangePending(unsigned int id);
extern unsigned char check_sum(unsigned char *pbuf, unsigned len);
extern void device_reboot(void);
extern unsigned hidSendData[];
// 固件升级通知MCU的标志phaten无UART MCU保留为静态变量供内部使用
static unsigned g_firmware_upgrade_mcu_notify = 0;
unsigned g_in_fw_upgrade = 0; // 升级进行中标志供其他模块检查以阻止非升级HID上报
// 升级状态(静态全局变量)
static upgrade_status_t g_upgrade_status;
// 全局标志:第一页写命令是否已执行
static uint8_t g_first_page_write_executed = 0;
// 全局标志是否已执行dfu_flash_cmd_erase_all
static uint8_t g_flash_erased = 0;
// 初始化固件升级模块
void firmware_upgrade_init(void)
{
memset(&g_upgrade_status, 0, sizeof(upgrade_status_t));
g_upgrade_status.state = UPGRADE_IDLE;
g_upgrade_status.expected_block_num = 0;
debug_printf("Firmware upgrade module initialized\n");
}
// 获取当前升级状态
upgrade_state_t firmware_upgrade_get_state(void)
{
return g_upgrade_status.state;
}
// 重置升级状态
void firmware_upgrade_reset(void)
{
memset(&g_upgrade_status, 0, sizeof(upgrade_status_t));
g_upgrade_status.state = UPGRADE_IDLE;
g_upgrade_status.expected_block_num = 0;
g_upgrade_status.first_page_written = 0;
g_first_page_write_executed = 0;
g_flash_erased = 0;
}
// 发送固件升级响应(主动上报)
// 填充hidSendData通过UserHIDGetData上报给host
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len)
{
unsigned char *ptr = (unsigned char *)hidSendData;
ptr[0] = 1;
ptr[1] = 0x77; // 同步头
ptr[2] = cmd; // 命令码
if (response_data != NULL && data_len > 0) {
uint16_t copy_len = (data_len < 61) ? data_len : 61;
memcpy(&ptr[3], response_data, copy_len);
}
for (int i = 3 + (int)data_len; i < 64; i++) {
ptr[i] = 0x00;
}
hidSetChangePending(0x1);
}
// 处理START命令
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
if (g_upgrade_status.state != UPGRADE_IDLE) {
debug_printf("Firmware upgrade error: not in IDLE state (current: %d)\n", g_upgrade_status.state);
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_FAIL;
}
uint32_t firmware_size = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24);
debug_printf("g_first_page_write_executed: %d\n", g_first_page_write_executed);
if (firmware_size == 0 || firmware_size > FLASH_MAX_UPGRADE_SIZE) {
debug_printf("Firmware upgrade error: invalid size %lu\n", firmware_size);
response[0] = STATUS_SIZE_INVALID;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_SIZE_INVALID;
}
uint32_t aligned_size = ((firmware_size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE) * FLASH_PAGE_SIZE;
if (dfu_flash_cmd_init() != 0) {
debug_printf("Firmware upgrade error: flash init failed\n");
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_FAIL;
}
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
debug_printf("Force upgrade: erasing existing upgrade image\n");
dfu_flash_cmd_erase_all();
g_flash_erased = 1;
} else {
debug_printf("Force upgrade: erase skipped (already erased or begin_write started)\n");
}
g_upgrade_status.state = UPGRADE_PREPARING;
g_upgrade_status.firmware_size = aligned_size;
g_upgrade_status.total_blocks = (aligned_size + MAX_DATA_BLOCK_SIZE - 1) / MAX_DATA_BLOCK_SIZE;
g_upgrade_status.received_blocks = 0;
g_upgrade_status.expected_block_num = 0;
g_upgrade_status.error_code = 0;
memset(g_upgrade_status.page_buf.buffer, 0, FLASH_PAGE_SIZE);
g_upgrade_status.page_buf.offset = 0;
g_upgrade_status.page_buf.total_pages = aligned_size / FLASH_PAGE_SIZE;
g_upgrade_status.page_buf.written_pages = 0;
if (g_first_page_write_executed == 0) {
debug_printf("Firmware upgrade: executing first page write command (flag=0) in START...\n");
unsigned char cmd_data[16];
memset(cmd_data, 0, sizeof(cmd_data));
cmd_data[0] = 0;
if (dfu_flash_cmd_write_page(cmd_data) != 0) {
debug_printf("Firmware upgrade error: first page write command failed (begin_write error)\n");
dfu_flash_cmd_deinit();
g_upgrade_status.state = UPGRADE_IDLE;
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 1);
return STATUS_FAIL;
}
g_first_page_write_executed = 1;
debug_printf("Firmware upgrade: first page write command completed\n");
} else {
debug_printf("Firmware upgrade: first page write command already executed in ERASE, skipping %d\n", g_first_page_write_executed);
}
g_upgrade_status.first_page_written = 1;
response[0] = STATUS_SUCCESS;
response[1] = (aligned_size >> 0) & 0xFF;
response[2] = (aligned_size >> 8) & 0xFF;
response[3] = (aligned_size >> 16) & 0xFF;
response[4] = (aligned_size >> 24) & 0xFF;
response[5] = (g_upgrade_status.total_blocks >> 0) & 0xFF;
response[6] = (g_upgrade_status.total_blocks >> 8) & 0xFF;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_START, response, 7);
g_firmware_upgrade_mcu_notify = 1;
g_in_fw_upgrade = 1;
return STATUS_SUCCESS;
}
// 处理DATA命令
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
if (g_upgrade_status.state != UPGRADE_PREPARING && g_upgrade_status.state != UPGRADE_TRANSFERRING) {
debug_printf("Firmware upgrade error: not in PREPARING or TRANSFERRING state (current: %d)\n", g_upgrade_status.state);
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
return STATUS_FAIL;
}
uint16_t block_num = data[2] | (data[3] << 8);
uint8_t data_len = data[4];
if (data_len != MAX_DATA_BLOCK_SIZE) {
debug_printf("Firmware upgrade error: invalid data length %d (must be %d)\n", data_len, MAX_DATA_BLOCK_SIZE);
response[0] = STATUS_SIZE_INVALID;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
return STATUS_SIZE_INVALID;
}
if (block_num != g_upgrade_status.expected_block_num) {
debug_printf("Firmware upgrade error: block number mismatch (expected: %d, got: %d)\n",
g_upgrade_status.expected_block_num, block_num);
response[0] = STATUS_BLOCK_NUM_ERROR;
response[1] = (g_upgrade_status.expected_block_num >> 0) & 0xFF;
response[2] = (g_upgrade_status.expected_block_num >> 8) & 0xFF;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 3);
return STATUS_BLOCK_NUM_ERROR;
}
uint8_t received_checksum = data[5 + data_len];
uint8_t calculated_checksum = check_sum(data, 5 + data_len);
if (received_checksum != calculated_checksum) {
debug_printf("Firmware upgrade error: checksum mismatch (expected: 0x%02x, got: 0x%02x)\n",
calculated_checksum, received_checksum);
response[0] = STATUS_CHECKSUM_ERROR;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 1);
return STATUS_CHECKSUM_ERROR;
}
if (g_upgrade_status.state == UPGRADE_PREPARING) {
g_upgrade_status.state = UPGRADE_TRANSFERRING;
if (block_num == 0) {
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
debug_printf("Firmware upgrade: erasing existing upgrade image\n");
dfu_flash_cmd_erase_all();
g_flash_erased = 1;
}
}
}
uint16_t buf_offset = g_upgrade_status.page_buf.offset;
uint16_t remaining = FLASH_PAGE_SIZE - buf_offset;
uint16_t to_copy = (data_len < remaining) ? data_len : remaining;
memcpy(&g_upgrade_status.page_buf.buffer[buf_offset], &data[5], to_copy);
g_upgrade_status.page_buf.offset += to_copy;
if (g_upgrade_status.page_buf.offset >= FLASH_PAGE_SIZE) {
unsigned char cmd_data[16];
if (g_upgrade_status.page_buf.written_pages == 0) {
debug_printf("Firmware upgrade: writing first page data (flag=0 already executed in START)\n");
} else {
cmd_data[0] = 1;
dfu_flash_cmd_write_page(cmd_data);
}
for (int i = 0; i < 4; i++) {
dfu_flash_cmd_write_page_data(&g_upgrade_status.page_buf.buffer[i * 64]);
}
g_upgrade_status.page_buf.written_pages++;
g_upgrade_status.page_buf.offset = 0;
}
if (to_copy < data_len) {
uint16_t remaining_data = data_len - to_copy;
memcpy(&g_upgrade_status.page_buf.buffer[0], &data[5 + to_copy], remaining_data);
g_upgrade_status.page_buf.offset = remaining_data;
}
g_upgrade_status.received_blocks++;
g_upgrade_status.expected_block_num++;
response[0] = STATUS_SUCCESS;
response[1] = (block_num >> 0) & 0xFF;
response[2] = (block_num >> 8) & 0xFF;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_DATA, response, 3);
return STATUS_SUCCESS;
}
// 处理END命令
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
if (g_upgrade_status.state != UPGRADE_TRANSFERRING) {
debug_printf("Firmware upgrade error: not in TRANSFERRING state (current: %d)\n", g_upgrade_status.state);
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
return STATUS_FAIL;
}
g_upgrade_status.state = UPGRADE_COMPLETING;
uint32_t firmware_size = data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24);
debug_printf("Firmware upgrade END: firmware_size=%lu\n", firmware_size);
if (g_upgrade_status.page_buf.offset > 0) {
for (uint16_t i = g_upgrade_status.page_buf.offset; i < FLASH_PAGE_SIZE; i++) {
g_upgrade_status.page_buf.buffer[i] = 0x00;
}
unsigned char cmd_data[16];
cmd_data[0] = 1;
dfu_flash_cmd_write_page(cmd_data);
for (int i = 0; i < 4; i++) {
dfu_flash_cmd_write_page_data(&g_upgrade_status.page_buf.buffer[i * 64]);
}
g_upgrade_status.page_buf.written_pages++;
debug_printf("Firmware upgrade: last page written (total pages: %d)\n",
g_upgrade_status.page_buf.written_pages);
}
unsigned char cmd_data[16];
cmd_data[0] = 2;
int result = dfu_flash_cmd_write_page(cmd_data);
if (result != 0) {
debug_printf("Firmware upgrade error: flash write termination failed\n");
g_upgrade_status.state = UPGRADE_ERROR;
g_upgrade_status.error_code = STATUS_FAIL;
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
return STATUS_FAIL;
}
debug_printf("Firmware upgrade: image verification passed\n");
g_upgrade_status.state = UPGRADE_COMPLETED;
response[0] = STATUS_SUCCESS;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_END, response, 1);
debug_printf("Firmware upgrade completed successfully\n");
g_firmware_upgrade_mcu_notify = 2;
g_in_fw_upgrade = 0;
g_upgrade_status.state = UPGRADE_IDLE;
return STATUS_SUCCESS;
}
// 处理STATUS命令
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
response[0] = (uint8_t)g_upgrade_status.state;
response[1] = (g_upgrade_status.received_blocks >> 0) & 0xFF;
response[2] = (g_upgrade_status.received_blocks >> 8) & 0xFF;
response[3] = (g_upgrade_status.total_blocks >> 0) & 0xFF;
response[4] = (g_upgrade_status.total_blocks >> 8) & 0xFF;
response[5] = (g_upgrade_status.page_buf.written_pages >> 0) & 0xFF;
response[6] = (g_upgrade_status.page_buf.written_pages >> 8) & 0xFF;
response[7] = (g_upgrade_status.page_buf.total_pages >> 0) & 0xFF;
response[8] = (g_upgrade_status.page_buf.total_pages >> 8) & 0xFF;
uint32_t bytes_transferred = g_upgrade_status.received_blocks * MAX_DATA_BLOCK_SIZE;
response[9] = (bytes_transferred >> 0) & 0xFF;
response[10] = (bytes_transferred >> 8) & 0xFF;
response[11] = (bytes_transferred >> 16) & 0xFF;
response[12] = (bytes_transferred >> 24) & 0xFF;
response[13] = (g_upgrade_status.firmware_size >> 0) & 0xFF;
response[14] = (g_upgrade_status.firmware_size >> 8) & 0xFF;
response[15] = (g_upgrade_status.firmware_size >> 16) & 0xFF;
response[16] = (g_upgrade_status.firmware_size >> 24) & 0xFF;
response[17] = g_upgrade_status.error_code;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_STATUS, response, 18);
return STATUS_SUCCESS;
}
// 处理ABORT命令
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
uint8_t erase_flag = data[2];
debug_printf("Firmware upgrade ABORT: erase_flag=0x%02x\n", erase_flag);
if (erase_flag == 0x01) {
debug_printf("Firmware upgrade: erasing written data\n");
dfu_flash_cmd_erase_all();
}
dfu_flash_cmd_deinit();
firmware_upgrade_reset();
g_upgrade_status.state = UPGRADE_ABORTED;
response[0] = STATUS_SUCCESS;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ABORT, response, 1);
g_firmware_upgrade_mcu_notify = 3;
g_in_fw_upgrade = 0;
g_upgrade_status.state = UPGRADE_IDLE;
return STATUS_SUCCESS;
}
// 处理ERASE命令
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len)
{
uint8_t response[64] = {0};
debug_printf("Firmware upgrade ERASE: erasing all upgrade images\n");
if (dfu_flash_cmd_init() != 0) {
debug_printf("Firmware upgrade error: flash init failed\n");
response[0] = STATUS_FAIL;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ERASE, response, 1);
return STATUS_FAIL;
}
if (g_first_page_write_executed == 0 && g_flash_erased == 0) {
dfu_flash_cmd_erase_all();
g_flash_erased = 1;
} else {
debug_printf("Firmware upgrade ERASE: erase skipped (already erased or begin_write started)\n");
}
dfu_flash_cmd_deinit();
response[0] = STATUS_SUCCESS;
send_firmware_upgrade_response(FIRMWARE_UPGRADE_ERASE, response, 1);
return STATUS_SUCCESS;
}
// 固件升级主处理函数分发0xA7-0xAC0xAE由eq.c直接处理
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len)
{
if (data[0] != 0x77) {
debug_printf("Firmware upgrade error: invalid sync header 0x%02x\n", data[0]);
return STATUS_FAIL;
}
uint8_t cmd = data[1];
debug_printf("Firmware upgrade command: 0x%02x\n", cmd);
switch (cmd) {
case FIRMWARE_UPGRADE_START:
return handle_firmware_upgrade_start(data, len);
case FIRMWARE_UPGRADE_DATA:
return handle_firmware_upgrade_data(data, len);
case FIRMWARE_UPGRADE_END:
return handle_firmware_upgrade_end(data, len);
case FIRMWARE_UPGRADE_STATUS:
return handle_firmware_upgrade_status(data, len);
case FIRMWARE_UPGRADE_ABORT:
return handle_firmware_upgrade_abort(data, len);
case FIRMWARE_UPGRADE_ERASE:
return handle_firmware_upgrade_erase(data, len);
default:
debug_printf("Firmware upgrade error: unknown command 0x%02x\n", cmd);
return STATUS_FAIL;
}
}
#endif // HID_DFU_EN

View File

@@ -0,0 +1,156 @@
// Copyright 2026 Shanling.
// HID固件升级头文件
// 改动原因实现通过HID协议进行固件升级的功能提供高效、稳定、安全的升级方案
#ifndef _DFU_UPGRADE_H_
#define _DFU_UPGRADE_H_
#include <stdint.h>
// 固件升级命令定义
#define FIRMWARE_UPGRADE_START 0xA7 // 开始固件升级
#define FIRMWARE_UPGRADE_DATA 0xA8 // 传输固件数据块
#define FIRMWARE_UPGRADE_END 0xA9 // 结束固件升级
#define FIRMWARE_UPGRADE_STATUS 0xAA // 获取升级状态
#define FIRMWARE_UPGRADE_ABORT 0xAB // 中止固件升级
#define FIRMWARE_UPGRADE_ERASE 0xAC // 擦除现有升级镜像
#define DEVICE_REBOOT 0xAE // 设备重启(通用命令,不仅限于固件升级)
// 升级状态定义
typedef enum {
UPGRADE_IDLE = 0x00, // 空闲状态,未开始升级
UPGRADE_PREPARING = 0x01, // 准备状态已调用START
UPGRADE_TRANSFERRING = 0x02, // 传输状态,正在接收数据
UPGRADE_COMPLETING = 0x03, // 完成中,正在写入最后一页
UPGRADE_COMPLETED = 0x04, // 已完成,升级成功
UPGRADE_ERROR = 0x05, // 错误状态,升级失败
UPGRADE_ABORTED = 0x06 // 已中止,升级被中止
} upgrade_state_t;
// 状态码定义
#define STATUS_SUCCESS 0x00 // 成功
#define STATUS_FAIL 0x01 // 失败
#define STATUS_SPACE_INSUFFICIENT 0x02 // Flash空间不足
#define STATUS_SIZE_INVALID 0x03 // 大小无效
#define STATUS_BLOCK_NUM_ERROR 0x04 // 块序号错误
#define STATUS_CHECKSUM_ERROR 0x05 // Checksum错误
#define STATUS_DATA_INCOMPLETE 0x06 // 数据不完整
#define STATUS_VERSION_INVALID 0x08 // 版本号无效
#define STATUS_SIZE_MISMATCH 0x09 // 大小不匹配
// Flash参数
#define FLASH_PAGE_SIZE 256 // Flash页大小
// 改动原因修正最大数据块大小HID数据包63字节不包括Report ID
// 数据包格式:同步头(1) + 命令码(1) + 块序号(2) + 数据长度(1) + 数据(N) + Checksum(1)
// 所以最大数据长度 = 63 - 5(头部) - 1(Checksum) = 57字节
#define MAX_DATA_BLOCK_SIZE 57 // 最大数据块大小63字节HID数据包 - 5字节头部 - 1字节Checksum
#define FLASH_MAX_UPGRADE_SIZE (2000 * 1024) // 最大固件大小1400KB
// 页缓冲区结构
typedef struct {
uint8_t buffer[FLASH_PAGE_SIZE]; // Flash页缓冲区
uint16_t offset; // 当前偏移
uint16_t total_pages; // 总页数
uint16_t written_pages; // 已写入页数
} page_buffer_t;
// 升级状态结构
typedef struct {
upgrade_state_t state; // 当前状态
uint32_t firmware_size; // 固件总大小
uint16_t total_blocks; // 总块数
uint16_t received_blocks; // 已接收块数
uint16_t expected_block_num; // 期望的块序号
// 改动原因:去掉固件版本号字段,不再存储版本号
uint8_t error_code; // 错误码
page_buffer_t page_buf; // 页缓冲区
uint8_t first_page_written; // 第一页写命令是否已执行0=未执行1=已执行)
} upgrade_status_t;
// 固件升级主处理函数
// 改动原因处理HID固件升级命令支持START、DATA、END等命令
// 参数:
// - data: HID数据包63字节不包括Report ID
// - len: 数据长度
// 返回值0=成功非0=失败
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len);
/* 改动原因:声明 DFU channel 转发函数,供 eq.c (process_send_params) 调用,
* 将 HID 固件升级命令通过 streaming channel 转发到 uart_handler 处理。
* 实现在 audiohw.xc 中。 */
void dfu_chan_forward(unsigned char data[], unsigned len);
// 各个固件升级命令的独立处理函数
// 改动原因在eq.c中为每个命令添加独立处理支持HID一条一条指令发送
// 参数:
// - data: HID数据包63字节不包括Report ID
// - len: 数据长度
// 返回值0=成功非0=失败(状态码)
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len);
// 发送固件升级响应(主动上报)
// 改动原因通过HID主动上报机制发送响应与音量上报机制一致
// 参数:
// - cmd: 命令码
// - response_data: 响应数据
// - data_len: 响应数据长度
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len);
// 升级进行中标志升级期间阻止其他HID主动上报
extern unsigned g_in_fw_upgrade;
// 初始化固件升级模块
// 改动原因:初始化升级状态和缓冲区
void firmware_upgrade_init(void);
// 获取当前升级状态
// 改动原因:供外部查询当前升级状态
upgrade_state_t firmware_upgrade_get_state(void);
// 重置升级状态
// 改动原因:升级完成或中止后重置状态
void firmware_upgrade_reset(void);
// ====================== UART DFU 友好接口 ======================
// 改动原因:为 UART 串口升级提供不依赖 g_hid_pass_data 的接口,
// 内部仍然复用 HID DFU 的状态机和 Flash 写入流程。
//
// 这些函数只操作内部的 g_upgrade_status并通过参数返回需要的字段
// 方便 user_uart.xc 根据 UART 协议打包响应。
// UART 版 START输入固件原始大小返回对齐后的大小和总块数
unsigned char uart_firmware_upgrade_start(uint32_t firmware_size,
uint32_t *aligned_size_out,
uint16_t *total_blocks_out);
// UART 版 DATA输入块号和数据返回状态码和“确认的块号”成功时等于块号序号错误时为期望块号
unsigned char uart_firmware_upgrade_data(uint16_t block_num,
uint8_t data_len,
const uint8_t *data,
uint16_t *confirmed_block_out);
// UART 版 END结束升级写入最后一页并终止 Flash 写入
unsigned char uart_firmware_upgrade_end(uint32_t firmware_size);
// UART 版 STATUS直接从 g_upgrade_status 中读取当前状态和进度
unsigned char uart_firmware_upgrade_status(uint8_t *state_out,
uint16_t *received_blocks_out,
uint16_t *total_blocks_out,
uint16_t *written_pages_out,
uint16_t *total_pages_out,
uint32_t *bytes_transferred_out,
uint32_t *firmware_size_out,
uint8_t *error_code_out);
// UART 版 ABORT中止升级可选择是否擦除已写入数据
unsigned char uart_firmware_upgrade_abort(uint8_t erase_flag);
// UART 版 ERASE擦除现有 upgrade image 并执行 begin_write 初始化
unsigned char uart_firmware_upgrade_erase(void);
#endif // _DFU_UPGRADE_H_

View File

@@ -16,12 +16,17 @@
#if DNR_ENABLE == 1
unsigned g_dsp_eof = 0;
extern float g_dnr_level;
void dnr_exchange_buffer(int32_t *data) {
static unsigned buff_index = 0;
write_to_sample_in_buf(data[1], buff_index, 0);
read_from_sample_out_buf(&data[1],buff_index, 0);
int dnr_level = (int)g_dnr_level;
if (dnr_level != 0) {
write_to_sample_in_buf(data[1], buff_index, 0);
read_from_sample_out_buf(&data[1],buff_index, 0);
}
data[0] = data[1];
buff_index++;
#if DNR_11MS
if (buff_index == 128)

View File

@@ -96,6 +96,15 @@ void dnr_set_mode(unsigned char mode)
g_dnr_level = -200;
}
// 按HID强度值0=关2-100步进2设置降噪深度strength * 2 → dB100→-200dB
void dnr_set_strength_level(unsigned char strength)
{
if (strength == 0)
g_dnr_level = 0;
else
g_dnr_level = -(float)(strength * 2);
}
void start_dsp_processing(void)
{
setNoisy_mix_factor(g_dnr_level);

View File

@@ -39,6 +39,7 @@ int32_t sys_vol = 0;
unsigned g_mic_vol_cmd_pending = 0;
chanend_t uc_ex3d_to_ubm, uc_eq_data;
static unsigned ubm_sample_freq = 0;
#if (STEREO_8K == 1) || (STEREO_2K == 1)
#define UBM_TO_EX3D_CHANS (2)
@@ -66,6 +67,9 @@ unsigned g_dnr_on_off_t1 = DNR_OFF; // Default DNR off
#define MUTE_OFF 0
unsigned g_mute_on_off_t1 = MUTE_ON;
// 数字监听 tile1 共享变量(由 tile0 通过 cc_mic_level 通道同步)
unsigned g_monitor_switch_t1 = 0; // 耳返开关 tile1 副本0=关闭1=开启)
unsigned g_mute_on_off_t0 = MUTE_OFF;
unsigned g_game_mode = 0;
@@ -83,12 +87,21 @@ chanend_t uc_dsp_to_dnr_t1;
//chanend_t uc_dsp_to_dnr_t0;
chanend_t uc_key_to_ubm_t0;
volatile EXTERN DS_BOOL m_hThread;
extern unsigned g_dnr_init_flag;
void SetEqDataChan (chanend_t c) {
uc_eq_data = c;
}
void key_receiver(chanend_t c)
{
debug_printf("===> key_receiver\n");
#if DNR_ENABLE
unsigned dnr_init_flag = 0;
while (dnr_init_flag == 0) {
GET_SHARED_GLOBAL(dnr_init_flag, g_dnr_init_flag);
asm("nop");
}
#endif
// tile0
// load the license key
// This function must be called before audio_ex3d_activate_key.
@@ -113,7 +126,7 @@ void key_sender(chanend_t c)
void UserBufferManagementInit(unsigned sampFreq)
{
(void)sampFreq;
ubm_sample_freq = sampFreq;
#if USE_EX3D == 1
memset(ubm_ingress, 0, sizeof(ubm_ingress));
memset(ubm_egress, 0, sizeof(ubm_egress));
@@ -131,14 +144,17 @@ void UserBufferManagementInit(unsigned sampFreq)
}
float fLevel[NUM_USB_CHAN_OUT] = {0,};
enum {UBM_A3D_OFF=0, UBM_A3D_VON=1, UBM_A3D_ON=2};
extern void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
extern void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[], unsigned sample_freq);
extern unsigned int is_eq_disabled(void);
extern unsigned int g_eq_enable;
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[])
{
uint32_t is_3d;
uint32_t is_dnr;
uint32_t is_mute;
unsigned is_monitor;
#if UAC1_MODE
return;
#endif
#if USE_EX3D == 1
#if defined(SPATIAL_DRAMA) || defined(SPATIAL_GAME) || defined(SPATIAL_MOVIE) || defined(SPATIAL_MUSIC)
@@ -147,8 +163,6 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi
#endif
GET_SHARED_GLOBAL(is_3d, g_3d_on_off_t1);
GET_SHARED_GLOBAL(is_dnr, g_dnr_on_off_t1);
GET_SHARED_GLOBAL(is_mute, g_mute_on_off_t1);
#if (HID_CONTROLS > 0)
AUDIO_T absVal, maxVal;
#endif
@@ -234,9 +248,16 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi
chan_in_buf_word(uc_ex3d_to_ubm, (uint32_t *)ubm_ingress, EX3D_TO_UBM_CHANS * DSP_BLOCK_LENGTH);
};
#endif
#if DNR_ENABLE == 1
buffer_exchange(uc_eq_data, sampsFromUsbToAudio, sampsFromAudioToUsb);
#if EQ_EN == 1 && USE_EX3D == 0
buffer_exchange(uc_eq_data, sampsFromUsbToAudio, sampsFromAudioToUsb, ubm_sample_freq);
#elif DNR_ENABLE == 1
buffer_exchange(uc_eq_data, sampsFromUsbToAudio, sampsFromAudioToUsb, ubm_sample_freq);
#endif
GET_SHARED_GLOBAL(is_monitor, g_monitor_switch_t1);
if (is_monitor) {
sampsFromUsbToAudio[0] += (sampsFromAudioToUsb[0]);
sampsFromUsbToAudio[1] += (sampsFromAudioToUsb[1]);
}
}
@@ -493,10 +514,10 @@ void hid_receive_task_in_c(unsigned char * RcvData, unsigned * SendData)
// if (cur_mode == IR_MUSIC) {
// sfIdxName = spatial_music;
// } else {
// sfIdxName = spatial_movie;
// sfIdxName = spatial_movie;
// }
// }
#else
#else
const char * sfIdxName = "EXTREME";
#endif
int32_t NameLen = strlen(sfIdxName);
@@ -862,13 +883,13 @@ void hid_button_task(chanend_t cc_mic_level, chanend_t c_hidRcvData, chanend_t c
tmp = chan_in_word(cc_mic_level);
debug_printf("event_mic_vol received: 0x%02X\n", tmp);
#if USE_EX3D == 1
if (tmp == 0xFC) {
// 音频模式命令:来自 audiohw.xc button_task 的模式切换
// 必须先读取payload无论是否启用EX3D
current_mode_local = chan_in_word(cc_mic_level);
if (current_mode_local > 3) current_mode_local = 0;
debug_printf("hid_button_task received audio_mode: %d\n", current_mode_local);
#if USE_EX3D == 1
if (current_mode_local == 0) {
// 无音效模式关闭EX3D和EQ算法
audio_ex3d_set_onoff(0);
@@ -882,7 +903,7 @@ void hid_button_task(chanend_t cc_mic_level, chanend_t c_hidRcvData, chanend_t c
} else if (current_mode_local == 1) {
// 音乐模式EX3D关闭EQ开启
audio_ex3d_set_onoff(0);
g_eq_enable = 1;
//g_eq_enable = 1;
#if IR_SWITCHING_MODE
is_3d_on = IR_OFF;
#else
@@ -890,8 +911,15 @@ void hid_button_task(chanend_t cc_mic_level, chanend_t c_hidRcvData, chanend_t c
#endif
debug_printf("Mode 1: MUSIC, EQ ON, EX3D OFF\n");
} else if (current_mode_local == 2) {
#if (F6_F7_FPS_UAC1 == 1)
// UAC1 Game模式: EX3D关闭, EQ开启, IR_OFF
//g_eq_enable = 1;
audio_ex3d_set_onoff(0);
is_3d_on = IR_OFF;
debug_printf("Mode 2: UAC1 GAME, EQ ON, EX3D OFF (IR_OFF)\n");
#else
// 游戏模式 (IR_GAME, stereo): SF index 0EQ开启
g_eq_enable = 1;
//g_eq_enable = 1;
#if IR_SWITCHING_MODE
audio_ex3d_set_sf(0); // SF 0 = STEREO GAME
is_3d_on = IR_GAME;
@@ -900,7 +928,16 @@ void hid_button_task(chanend_t cc_mic_level, chanend_t c_hidRcvData, chanend_t c
#endif
audio_ex3d_set_onoff(1);
debug_printf("Mode 2: GAME (IR_GAME) ON, sf=0, EQ ON\n");
#endif
} else if (current_mode_local == 3) {
#if (F6_F7_FPS_UAC1 == 1)
// UAC1 AI71模式: EX3D开启, SF index 0 (stereo game), EQ开启, IR_GAME
//g_eq_enable = 1;
audio_ex3d_set_sf(0); // SF 0 = STEREO GAME
is_3d_on = IR_GAME;
audio_ex3d_set_onoff(1);
debug_printf("Mode 3: UAC1 AI71 (IR_GAME) ON, sf=0, EQ ON\n");
#else
// AI7.1模式 (IR_7_1_GAME, 7.1): SF index 1EQ开启
g_eq_enable = 1;
#if IR_SWITCHING_MODE
@@ -911,18 +948,28 @@ void hid_button_task(chanend_t cc_mic_level, chanend_t c_hidRcvData, chanend_t c
#endif
audio_ex3d_set_onoff(1);
debug_printf("Mode 3: AI7.1 (IR_7_1_GAME) ON, sf=1, EQ ON\n");
#endif
}
SET_SHARED_GLOBAL(g_3d_on_off_t1, is_3d_on);
#endif
} else if (tmp == 0xFD) {
// 脚步增强按键发来的 expand gain 命令
// 必须先读取payload无论是否启用EX3D
int32_t gain = (int32_t)chan_in_word(cc_mic_level);
#if USE_EX3D == 1
if ((0 <= gain) && (gain <= 20)) {
Ex3dExpandGain = gain;
EX3DAudio_SetExpandGain(Ex3dExpandGain);
debug_printf("Button set CMD_EXPAND_GAIN: %d\n", gain);
}
#endif
} else if (tmp == 0xFE) {
// 数字监听开关同步命令:来自 tile0所有模式都需要处理
unsigned mon_sw = chan_in_word(cc_mic_level);
SET_SHARED_GLOBAL(g_monitor_switch_t1, mon_sw);
debug_printf("Monitor sync: sw=%d\n", mon_sw);
} else {
// Mic 静音状态命令
// Mic 静音状态命令(所有模式都需要处理)
switch (tmp) {
case MUTED_MIC:
SET_SHARED_GLOBAL(g_mute_on_off_t1, MUTE_ON);
@@ -939,7 +986,6 @@ void hid_button_task(chanend_t cc_mic_level, chanend_t c_hidRcvData, chanend_t c
break;
}
}
#endif
}
continue;
@@ -1361,4 +1407,4 @@ int dsp_worker_tile(chanend_t c_dsp_to_ex3d, int worker_id){
return 0;
}
#endif
#endif

View File

@@ -34,7 +34,10 @@ extern unsigned int g_saved_eq_mode; // 改动原因:添加保存模式外部
extern void debug_print_eq_params(unsigned sample_freq);
extern uint32_t get_reference_time(void);
extern void update_eq_post_gain(void);
extern unsigned int g_eq_sample_rate;
extern unsigned g_windows_detect_done;
extern unsigned g_dnr_init_flag;
extern unsigned g_ex3d_key_verified;
#pragma unsafe arrays
void dsp_core0(void)
@@ -45,7 +48,7 @@ void dsp_core0(void)
static unsigned int usb_to_dsp_ratio = 1;
static int buffer_in_active = 0;
static int buffer_out_active = 0;
static unsigned int sample_freq = 48000;
static unsigned int sample_freq = 48000 ;
unsigned b_fade_in = 0;
unsigned u_in_step;
unsigned b_fade_out = 0;
@@ -54,11 +57,31 @@ void dsp_core0(void)
// EQ Flash存储初始化标志
delay_milliseconds(300);
unsigned windows_detect_done;
unsigned windows_detect_done, dnr_init_flag, ex3d_key_verified;
GET_SHARED_GLOBAL(windows_detect_done, g_windows_detect_done);
while (windows_detect_done == 0) {
#if DNR_ENABLE
GET_SHARED_GLOBAL(dnr_init_flag, g_dnr_init_flag);
#endif
#if USE_EX3D
GET_SHARED_GLOBAL(ex3d_key_verified, g_ex3d_key_verified);
#endif
while ((windows_detect_done == 0)
#if DNR_ENABLE
|| (dnr_init_flag == 0)
#endif
#if USE_EX3D
|| (ex3d_key_verified == 0)
#endif
) {
asm("nop");
GET_SHARED_GLOBAL(windows_detect_done, g_windows_detect_done);
#if DNR_ENABLE
GET_SHARED_GLOBAL(dnr_init_flag, g_dnr_init_flag);
#endif
#if USE_EX3D
GET_SHARED_GLOBAL(ex3d_key_verified, g_ex3d_key_verified);
#endif
}
#if EQ_EN
@@ -138,7 +161,8 @@ void dsp_core0(void)
}
else
{
sample_freq = 48000;
GET_SHARED_GLOBAL(sample_freq, g_eq_sample_rate);
if (sample_freq == 0) sample_freq = 48000;
audio_in_samples[0] = read_from_ring_buffer(0);
audio_in_samples[1] = read_from_ring_buffer(1);

View File

@@ -9,6 +9,10 @@
extern void device_reboot(void);
#if HID_DFU_EN
#include "dfu_upgrade.h"
#endif
// 常量定义
#define EQ_DISABLED_MODE 10 // 禁用EQ的模式编号
@@ -634,6 +638,7 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
extern unsigned g_request_mic_volume_set;
g_mic_volume_level = mic_level;
g_request_mic_volume_set = 1;
read_request.pending_cmd = 0x83; // 设置后用0x83格式回报当前增益
return true;
}
@@ -644,6 +649,48 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
return true;
}
// 处理设置AI降噪强度命令 (0x85) - SET_AI_NOISE_STRENGTH
// 有效值: 0(关闭), 2,4,...,100(步进2); 强度映射: strength*2 → dB (100→-200dB)
if (data[1] == 0x85) {
uint8_t strength = data[2];
if (strength > 100 || (strength != 0 && strength % 2 != 0)) {
return false;
}
extern unsigned g_dnr_strength;
extern unsigned g_request_dnr_strength_set;
g_dnr_strength = strength;
g_request_dnr_strength_set = 1;
read_request.pending_cmd = 0x86; // 设置后用0x86格式回报当前强度
return true;
}
// 处理读取AI降噪强度命令 (0x86) - GET_AI_NOISE_STRENGTH
if (data[1] == 0x86) {
read_request.pending_cmd = 0x86;
return true;
}
// 处理设置耳返开关命令 (0x87) - SET_MONITOR_SWITCH
// 0=关闭耳返ADC不路由到耳机输出1=开启耳返
if (data[1] == 0x87) {
uint8_t mon_sw = data[2];
if (mon_sw > 1) {
return false;
}
extern unsigned g_monitor_switch;
extern unsigned g_request_monitor_switch_set;
g_monitor_switch = mon_sw;
g_request_monitor_switch_set = 1;
read_request.pending_cmd = 0x88; // 设置后用0x88格式回报当前状态
return true;
}
// 处理读取耳返开关命令 (0x88) - GET_MONITOR_SWITCH
if (data[1] == 0x88) {
read_request.pending_cmd = 0x88;
return true;
}
// 处理设置音量命令 (0x93) - SET_VOLUME
// 范围: 0-15 (0=静音, 1-15=-28dB~0dB, 2dB/步)
if (data[1] == 0x93) {
@@ -733,6 +780,9 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
lfs_remove_file("mic_vol");
lfs_remove_file("dac_vol");
lfs_remove_file("footstep");
lfs_remove_file("monitor_sw");
lfs_remove_file("mic_mute");
lfs_remove_file("hp_mute");
// 删除EQ flash数据
eq_flash_clear_all();
// 通知button_task在合适时机重启避免在USB上下文中直接reboot
@@ -805,6 +855,39 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
}
#endif // #if EQ_EN (for process_send_params EQ commands section starting at line 1228)
#if HID_DFU_EN
// 0xA7 START: 转发到button_task (tile[0])执行因为flash访问需要在tile[0]进行
if (data[1] == FIRMWARE_UPGRADE_START) {
dfu_chan_forward(data, len);
return true;
}
// 0xA8 DATA / 0xA9 END / 0xAA STATUS / 0xAB ABORT / 0xAC ERASE: 直接处理
if (data[1] >= FIRMWARE_UPGRADE_DATA && data[1] <= FIRMWARE_UPGRADE_ERASE) {
unsigned char result;
if (data[1] == FIRMWARE_UPGRADE_DATA)
result = handle_firmware_upgrade_data(data, len);
else if (data[1] == FIRMWARE_UPGRADE_END)
result = handle_firmware_upgrade_end(data, len);
else if (data[1] == FIRMWARE_UPGRADE_STATUS)
result = handle_firmware_upgrade_status(data, len);
else if (data[1] == FIRMWARE_UPGRADE_ABORT)
result = handle_firmware_upgrade_abort(data, len);
else
result = handle_firmware_upgrade_erase(data, len);
(void)result;
return true;
}
#endif
// 0xAE DEVICE_REBOOT (通用命令,不仅限于固件升级)
if (data[1] == 0xAE) {
debug_printf("Received device REBOOT command (0xAE)\n");
device_reboot();
while(1);
return true;
}
return true;
}
@@ -880,17 +963,6 @@ void init_mode_info(void) {
#endif
void get_key_ret(uint8_t *buffer);
extern unsigned char g_hid_status_report_data[63];
extern unsigned int g_hid_status_report_index;
void user_read_hid_status(unsigned char hidPassData[])
{
if (g_hid_status_report_index > 0) {
memcpy(hidPassData, g_hid_status_report_data, 63);
g_hid_status_report_index = 0;
} else {
memset(hidPassData, 0, 63);
}
}
// process_read_params: build HID response from pending request state
unsigned char process_read_params(uint8_t response[]) {
@@ -1003,6 +1075,29 @@ unsigned char process_read_params(uint8_t response[]) {
read_request.pending_cmd = 0;
return true;
}
// 处理AI降噪强度请求/响应 (0x86) - GET_AI_NOISE_STRENGTH
if (read_request.pending_cmd == 0x86) {
RSP_HDR(response, 0x86);
extern unsigned g_dnr_strength;
response[2] = (uint8_t)g_dnr_strength;
read_request.pending_cmd = 0;
return true;
}
// 处理耳返开关请求/响应 (0x88) - GET_MONITOR_SWITCH
if (read_request.pending_cmd == 0x88) {
RSP_HDR(response, 0x88);
extern unsigned g_monitor_switch;
response[2] = (uint8_t)g_monitor_switch;
read_request.pending_cmd = 0;
return true;
}
// 处理读取音量请求 (0x94) - GET_VOLUME
if (read_request.pending_cmd == 0x94) {
RSP_HDR(response, 0x94);

View File

@@ -11,6 +11,10 @@
| 0x82 | SET_MIC_VOLUME | 设置麦克风增益级别 | 主机→设备 | 设置麦克风PGA增益0=静音, 1-37=0dB~36dB, 1dB/步) |
| 0x83 | GET_MIC_VOLUME | 获取麦克风增益级别 | 主机→设备 | 读取当前麦克风PGA增益级别0=静音, 1-37=0dB~36dB |
| 0x84 | FACTORY_RESET | 恢复出厂默认设置 | 主机→设备 | 删除Flash中所有已保存参数设备重启后自动恢复出厂默认值 |
| 0x85 | SET_AI_NOISE_STRENGTH | 设置AI降噪强度 | 主机→设备 | 设置AI降噪强度0=关闭2-100偶数=强度级别步进2100对应最强-200dB |
| 0x86 | GET_AI_NOISE_STRENGTH | 获取AI降噪强度 | 主机→设备 | 读取当前AI降噪强度强度变化含按键切换、开机初始值时设备主动上报 |
| 0x87 | SET_MONITOR_SWITCH | 设置耳返开关 | 主机→设备 | 设置耳返ADC→耳机监听开关0=关闭1=开启保存到Flash |
| 0x88 | GET_MONITOR_SWITCH | 获取耳返开关状态 | 主机→设备 | 读取当前耳返开关状态0=关闭1=开启) |
| 0x8A | SET_EQ_MODE | 切换EQ模式 | 主机→设备 | 切换EQ模式 |
| 0x8B | GET_EQ_MODE | 获取当前EQ模式信息 | 主机→设备 | 读取设备当前EQ模式和名称 |
| 0x8C | SET_MODE_GAIN_AND_NAME | 设置模式整体增益和名称 | 主机→设备 | 设置模式整体增益和名称 |
@@ -28,6 +32,13 @@
| 0xA4 | SET_SOUND_EFFECT_MODE | 设置音效模式 | 主机→设备 | 设置音效模式0=无音效1=音乐模式2=游戏模式3=AI7.1模式) |
| 0xA5 | GET_SOUND_EFFECT_MODE | 获取音效模式 | 主机→设备 | 读取当前音效模式0-3 |
| 0xA6 | GET_FIRMWARE_VERSION | 获取固件版本 | 主机→设备 | 读取设备固件版本号BCD格式主版本.次版本.修订版本) |
| 0xA7 | FIRMWARE_UPGRADE_START | 开始固件升级 | 主机→设备 |
| 0xA8 | FIRMWARE_UPGRADE_DATA | 传输固件数据块固定57字节 | 主机→设备 |
| 0xA9 | FIRMWARE_UPGRADE_END | 结束固件升级,验证镜像 | 主机→设备 |
| 0xAA | FIRMWARE_UPGRADE_STATUS | 获取升级状态和进度 | 主机→设备 |
| 0xAB | FIRMWARE_UPGRADE_ABORT | 中止固件升级 | 主机→设备 |
| 0xAC | FIRMWARE_UPGRADE_ERASE | 擦除现有升级镜像 | 主机→设备 |
| 0xAE | DEVICE_REBOOT | 设备重启(通用命令) | 主机→设备 |
| 0xB0 | SET_EX3D_CMD | 发送EX3D命令 | 主机→设备 | 发送EX3D设置命令封装所有EX3D SET命令 |
| 0xB1 | GET_EX3D_CMD | 读取EX3D命令 | 主机→设备 | 读取EX3D参数封装所有EX3D GET命令 |
@@ -120,6 +131,9 @@
| 监听音量 | 15 (-14dB) | DAC level 15 = 0dB - 14 = -14dB |
| EQ参数 | 头文件预设 | 删除所有用户EQ参数恢复固件内置预设 |
| AI降噪 | 开启 | 每次上电默认开启不保存到Flash |
| 耳返开关 | 0 (关闭) | ADC→耳机监听通路默认关闭 |
| 麦克风静音 | 0 (未静音) | 麦克风静音状态默认关闭 |
| 监听静音 | 0 (未静音) | 耳机输出静音状态默认关闭 |
**设备端处理**:
1. 删除Flash中保存的以下参数文件
@@ -127,6 +141,9 @@
- `mic_vol`(麦克风音量)
- `dac_vol`(监听音量)
- `footstep`(脚步增强状态)
- `monitor_sw`(耳返开关)
- `mic_mute`(麦克风静音状态)
- `hp_mute`(耳机静音状态)
- 所有EQ参数文件调用eq_flash_clear_all
2. 设置重启标志约500ms后设备自动重启
3. 重启后自动加载出厂默认参数
@@ -147,6 +164,127 @@
- 重启后所有参数将恢复为出厂默认值
- 此操作不可撤销
### 2.0d 0x85 - SET_AI_NOISE_STRENGTH (设置AI降噪强度)
**功能**: 设置AI降噪强度级别
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x85 | 命令码
2 | 1 | uint8 | 强度值 (0=关闭, 2/4/.../100=强度级别, 步进2)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **强度值范围**: 0、2、4、6、…、100共51个有效值
- **0**: 关闭AI降噪
- **2-100步进2**: 开启AI降噪强度递增内部dB映射`dB = -(strength × 2)`
- 2 → -4 dB最轻微降噪
- 50 → -100 dB
- 100 → -200 dB最强降噪出厂默认
- **奇数或 >100** 为无效值,固件将拒绝(返回无响应)
**设备端处理**:
- 强度=0关闭AI降噪算法熄灭LED_ANCflag_aidenoise_onoff=0
- 强度=2-100开启AI降噪算法点亮LED_ANCflag_aidenoise_onoff=1更新内部降噪深度
- 设置成功后设备主动上报当前强度0x86格式
- **不保存到Flash**重启后AI降噪恢复为开启强度=100即-200dB最强
**返回值**:
无直接返回设置成功后设备通过0x86格式主动上报当前强度值。
### 2.0e 0x86 - GET_AI_NOISE_STRENGTH (获取AI降噪强度)
**功能**: 读取设备当前AI降噪强度强度变化时设备主动上报
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x86 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**(含主动上报):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x86 | 同步头2
3 | 1 | uint8 | 当前强度值 (0=关闭, 2-100=强度级别)
4-62 | 59 | 0x00 | 保留字节
```
**主动上报说明**:
- **开机时**:设备初始化完成后主动上报当前强度(出厂默认=100
- **按键切换**用户按下AI降噪按键时设备主动上报新强度关闭时上报0开启时上报恢复的强度
- **HID SET_AI_NOISE_STRENGTH0x85命令成功执行后**,设备主动上报新强度
### 2.0f 0x87 - SET_MONITOR_SWITCH (设置耳返开关)
**功能**: 设置耳返ADC→耳机监听开关控制是否将麦克风输入实时路由到耳机输出
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x87 | 命令码
2 | 1 | uint8 | 开关值 (0=关闭, 1=开启)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **0**: 关闭耳返ADC数据不路由到耳机输出NAU88L21 reg 0x0035 = 0x0000
- **1**: 开启耳返ADC数据路由到耳机输出NAU88L21 reg 0x0035 = 0xCFCF0dB监听音量
- **注意**: 耳返路由需要麦克风未静音mic_mute=0且麦克风增益有效level≥2方才生效
**设备端处理**:
- 立即更新 NAU88L21 reg 0x0035耳返音量寄存器
- 若麦克风当前处于静音状态则无论耳返开关为何值reg 0x0035保持0x0000
- 保存到Flash`monitor_sw`路径),断电重启后自动恢复
- 设置成功后用0x88格式响应当前状态
- 出厂默认关闭0
**返回值**:
设置成功后设备回复0x88格式响应。
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x88 | 同步头2
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
4-62 | 59 | 0x00 | 保留字节
```
### 2.0g 0x88 - GET_MONITOR_SWITCH (获取耳返开关状态)
**功能**: 读取当前耳返开关状态
**方向**: 主机→设备(请求),设备→主机(响应)
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x88 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x88 | 同步头2
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
4-62 | 59 | 0x00 | 保留字节
```
### 2.1 0x8A - SET_EQ_MODE (切换EQ模式)
**功能**: 切换当前EQ模式
**方向**: 主机→设备
@@ -789,3 +927,123 @@
4. **错误恢复**: 通信失败时需要重新建立连接并重试
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
---
## 8. 固件升级命令 (0xA70xAE)
本节定义通过HID进行固件升级的命令。最大数据块57字节Flash页256字节字节序小端序。
### 8.1 固件升级命令列表
### 8.2 0xA7 - FIRMWARE_UPGRADE_START
**请求**:
```
字节 0: 0x77 同步头
字节 1: 0xA7 命令码
字节 2-5: uint32 固件大小(字节,小端序)
字节 6-62: 0x00 保留
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA7
字节 2: 状态码 (0x00=成功, 0x01=失败, 0x03=大小无效)
字节 3-6: uint32 页对齐后的实际大小
字节 7-8: uint16 总块数
字节 9-62: 0x00
```
### 8.3 0xA8 - FIRMWARE_UPGRADE_DATA
**请求**数据块固定57字节不足补0:
```
字节 0: 0x77
字节 1: 0xA8
字节 2-3: uint16 块序号从0开始小端序
字节 4: uint8 数据长度固定57
字节 5-61: uint8[57] 固件数据
字节 62: uint8 Checksum字节0-61累加 mod 256
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA8
字节 2: 状态码 (0x00=成功, 0x04=块号错误, 0x05=Checksum错误)
字节 3-4: uint16 已确认块序号
字节 5-62: 0x00
```
### 8.4 0xA9 - FIRMWARE_UPGRADE_END
**请求**:
```
字节 0: 0x77
字节 1: 0xA9
字节 2-5: uint32 固件总大小(用于验证)
字节 6-62: 0x00
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA9
字节 2: 状态码 (0x00=成功, 0x01=失败)
字节 3-62: 0x00
```
### 8.5 0xAA - FIRMWARE_UPGRADE_STATUS
**请求**: 字节0=0x77, 字节1=0xAA, 其余0x00
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xAA
字节 2: 升级状态 (0=空闲, 1=准备中, 2=传输中, 3=完成中, 4=已完成, 5=错误, 6=已中止)
字节 3-4: uint16 已接收块数
字节 5-6: uint16 总块数
字节 7-8: uint16 已写页数
字节 9-10: uint16 总页数
字节 11-14: uint32 已传输字节数
字节 15-18: uint32 总字节数
字节 19: 错误码
字节 20-62: 0x00
```
### 8.6 0xAB - FIRMWARE_UPGRADE_ABORT
**请求**:
```
字节 0: 0x77
字节 1: 0xAB
字节 2: 清理标志 (0x00=保留数据, 0x01=擦除数据)
字节 3-62: 0x00
```
**响应**(主动上报): 字节0=0x77, 字节1=0xAB, 字节2=状态码(0x00=成功)
### 8.7 0xAC - FIRMWARE_UPGRADE_ERASE
**请求**: 字节0=0x77, 字节1=0xAC, 其余0x00
**响应**(主动上报): 字节0=0x77, 字节1=0xAC, 字节2=状态码(0x00=成功)
### 8.8 0xAE - DEVICE_REBOOT
**请求**: 字节0=0x77, 字节1=0xAE, 其余0x00
**响应**: 无响应,设备立即重启。
### 8.9 标准升级流程
```
1. (可选) ERASE — 擦除现有upgrade image
2. START — 设置固件大小,等待响应(SUCCESS)
3. 循环 DATA — 逐块发送,每块等待响应确认
4. END — 完成写入,等待响应(SUCCESS)
5. REBOOT — 重启加载新固件
```

View File

@@ -22,8 +22,8 @@ typedef enum {
LED_MUSIC = 2, // OUT2 - 音乐模式
LED_ANC = 1, // OUT1 - ANC模式
LED_FOOTSTEP_MODE = 3, // OUT3 - 脚步模式
LED_AI7_1 = 34, // OUT34 - AI7.1模式
LED_GAME_MODE = 35, // OUT35 - 游戏模式
LED_AI7_1 = 35, // OUT34 - AI7.1模式
LED_GAME_MODE = 34, // OUT35 - 游戏模式
// OUT36未使用
// L系列LED (OUT4-OUT18)

View File

@@ -1,5 +1,18 @@
#ifndef _LFS_IO_H_
#define _LFS_IO_H_
#if __XC__
int lfs_init(void);
void lfs_deinit(void);
void lfs_read_config(unsigned char * unsafe config, unsigned char * unsafe buffer, unsigned size);
void lfs_write_config(unsigned char * unsafe config, unsigned char * unsafe buffer, unsigned size);
// EQ参数专用函数
void lfs_read_eq_config(const char * unsafe file_path, unsigned char * unsafe buffer, unsigned size);
void lfs_write_eq_config(const char * unsafe file_path, unsigned char * unsafe buffer, unsigned size);
int lfs_file_exists(const char * unsafe file_path);
int lfs_remove_file(const char * unsafe file_path);
int lfs_create_directory(const char * unsafe dir_path);
#else
int lfs_init(void);
void lfs_deinit(void);
void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned size);
@@ -10,4 +23,6 @@ void lfs_write_eq_config(const char * file_path, unsigned char * buffer, unsigne
int lfs_file_exists(const char * file_path);
int lfs_remove_file(const char * file_path);
int lfs_create_directory(const char * dir_path);
#endif
#endif

View File

@@ -13,12 +13,12 @@ swlock_t lfs_lock = SWLOCK_INITIAL_VALUE;
static rtos_qspi_flash_t qspi_flash_ctx_s;
#define FLASH_CLKBLK XS1_CLKBLK_3
#ifndef FS_BASE_ADDR
#define FS_BASE_ADDR 0x1a0000
#define FS_BASE_ADDR (2500 * 1024)
#endif
#define SECTOR_SIZE 4096
rtos_qspi_flash_t *qspi_flash_ctx = &qspi_flash_ctx_s;
__attribute__((fptrgroup(" local_block_device_read_fptr_grp")))
__attribute__((fptrgroup("local_block_device_read_fptr_grp")))
int local_block_device_read(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size)
{
@@ -27,7 +27,7 @@ int local_block_device_read(const struct lfs_config *c, lfs_block_t block,
return 0;
}
__attribute__((fptrgroup(" local_block_device_prog_fptr_grp")))
__attribute__((fptrgroup("local_block_device_prog_fptr_grp")))
int local_block_device_prog(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size)
{
@@ -36,7 +36,7 @@ int local_block_device_prog(const struct lfs_config *c, lfs_block_t block,
return 0;
}
__attribute__((fptrgroup(" local_block_device_erase_fptr_grp")))
__attribute__((fptrgroup("local_block_device_erase_fptr_grp")))
int local_block_device_erase(const struct lfs_config *c, lfs_block_t block)
{
unsigned address = (FS_BASE_ADDR + block * SECTOR_SIZE);
@@ -44,7 +44,7 @@ int local_block_device_erase(const struct lfs_config *c, lfs_block_t block)
return 0;
}
__attribute__((fptrgroup(" local_block_device_sync_fptr_grp")))
__attribute__((fptrgroup("local_block_device_sync_fptr_grp")))
int local_block_device_sync(const struct lfs_config *c)
{
return 0;
@@ -102,7 +102,8 @@ void lfs_deinit(void) {
swlock_release(&lfs_lock);
}
#pragma stackfunction 1300
#pragma stackfunction 1500
void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned size)
{
swlock_acquire(&lfs_lock);
@@ -119,7 +120,7 @@ void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned si
debug_printf("lfs_read_config: %s, result: %d\n", config, result);
if (result < 0) {
debug_printf("lfs_read_config: %s, read file failed, error: %d\n", config, result);
// Update: Added lfs_file_close to ensure file is closed even on error.
// Update: Added lfs_file_close to ensure file is closed even on error.
// Missing this caused subsequent open calls to assert/crash.
lfs_file_close(&lfs, &file);
swlock_release(&lfs_lock);
@@ -130,7 +131,7 @@ void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned si
}
#pragma stackfunction 1300
#pragma stackfunction 1500
void lfs_write_config(unsigned char * config, unsigned char * buffer, unsigned size)
{
swlock_acquire(&lfs_lock);
@@ -156,6 +157,7 @@ void lfs_write_config(unsigned char * config, unsigned char * buffer, unsigned s
// 检查文件是否存在
#pragma stackfunction 1200
int lfs_file_exists(const char * file_path)
{
swlock_acquire(&lfs_lock);
@@ -171,6 +173,7 @@ int lfs_file_exists(const char * file_path)
}
// EQ参数专用读写函数
#pragma stackfunction 1200
void lfs_read_eq_config(const char * file_path, unsigned char * buffer, unsigned size)
{
lfs_file_open(&lfs, &file, file_path, LFS_O_RDONLY);
@@ -178,6 +181,7 @@ void lfs_read_eq_config(const char * file_path, unsigned char * buffer, unsigned
lfs_file_close(&lfs, &file);
}
#pragma stackfunction 1500
void lfs_write_eq_config(const char * file_path, unsigned char * buffer, unsigned size)
{
lfs_file_open(&lfs, &file, file_path, LFS_O_RDWR | LFS_O_CREAT);
@@ -188,17 +192,19 @@ void lfs_write_eq_config(const char * file_path, unsigned char * buffer, unsigne
// 删除文件
#pragma stackfunction 1500
int lfs_remove_file(const char * file_path)
{
return lfs_remove(&lfs, file_path);
}
// 创建目录(通过创建临时文件然后删除)
#pragma stackfunction 1500
int lfs_create_directory(const char * dir_path)
{
char temp_file[256];
snprintf(temp_file, sizeof(temp_file), "%s/.dir", dir_path);
lfs_file_t file;
int result = lfs_file_open(&lfs, &file, temp_file, LFS_O_RDWR | LFS_O_CREAT);
if (result == 0) {

View File

@@ -431,15 +431,23 @@ extern int dsp_worker_tile(chanend c_dsp_to_ex3d, int worker_id);
//extern int dsp_worker_tile_1(chanend c_dsp_to_ex3d, int worker_id);
extern void ex3d_task();
extern void hid_button_task(chanend cc_mic_level, chanend c_hid, chanend c_hidSendData, chanend c_uac_vol, chanend c_ex3d_hid_cmd);
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx);
#if HID_DFU_EN
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx, streaming chanend c_dfu_rx, chanend c_mic_det);
#else
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol, chanend c_audiohw_rx, chanend c_mic_det);
#endif
extern void dnr_dsp_proc_task(void);
extern unsafe chanend uc_dsp_to_ex3d[DSP_WORKER_COUNT];
extern unsafe chanend uc_dsp_to_dnr_t1;
extern unsafe chanend uc_key_to_ubm_t0;
extern unsafe chanend uc_audiohw;
#if HID_DFU_EN
extern unsafe streaming chanend uc_dfu;
#endif
extern void key_sender(chanend c_key);
extern void key_receiver(chanend c_key);
extern void mute_handler(chanend c_mic_det);
/* Main for USB Audio Applications */
@@ -535,11 +543,15 @@ int main()
chan c_dsp_to_ex3d[DSP_WORKER_COUNT];
chan cc_mic_level;
chan c_audiohw;
#if HID_DFU_EN
streaming chan c_dfu;
#endif
chan c_key; chan c_hidSendData;
chan c_hidRcvData;
chan c_eq_data;
chan c_uac_vol;
chan c_ex3d_hid_cmd;
chan c_mic_det;
par
{
@@ -548,6 +560,9 @@ int main()
par {
unsafe {
uc_audiohw = (chanend)c_audiohw;
#if EQ_EN == 1 && USE_EX3D == 0
SetEqDataChan(c_eq_data);
#endif
hid_button_task(cc_mic_level, c_hidRcvData, c_hidSendData, c_uac_vol, c_ex3d_hid_cmd);
}
#if USE_EX3D == 1
@@ -556,6 +571,7 @@ int main()
unsafe {
SetEqDataChan(c_eq_data);
delay_milliseconds(200);
key_sender(c_key);
for (int i = 0; i < DSP_WORKER_COUNT; i++)
uc_dsp_to_ex3d[i] = (chanend)c_dsp_to_ex3d[i];
@@ -565,6 +581,7 @@ int main()
}
}
on tile[1]: mute_handler(c_mic_det);
on tile[0] : {
par {
@@ -572,13 +589,25 @@ int main()
#if USE_EX3D == 1
unsafe { key_receiver(c_key); }
#endif
AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw);
AudioHwRemote(c_hidSendData, cc_mic_level, c_uac_vol, c_audiohw
#if HID_DFU_EN
, c_dfu
#endif
, c_mic_det
);
}
}
}
#if EQ_EN == 1
on tile[0] : {
{
#if HID_DFU_EN
unsafe {
uc_dfu = (streaming chanend)c_dfu;
}
#endif
dsp_core0();
}
}

View File

@@ -4,6 +4,7 @@
#include <quadflashlib.h>
#include <xcore/chanend.h>
#include <xcore/channel.h>
#include "hmac.h"
#include "xua_conf.h"
#define WRITE_ENABLE_COMMAND (0x06)
@@ -31,7 +32,7 @@
#define PRSCUR_COMMAND (0x42)
#define ERSCUR_COMMAND (0x44)
#define RDSCUR_COMMAND (0x48)
#define HMAC_LEN 60
#define KEY_BLOCK_LEN 100
#define HMAC_GEN_LEN 20
@@ -40,19 +41,17 @@ extern unsigned short XUA_Endpoint0_getVendorId();
unsigned char hid_reply[64] = {0};
#if 0
void printArrayHex1(uint8_t array[], int size, int elementsPerLine) {
for (int i = 0; i < size; i++) {
printf("0x%x, ", array[i]);
debug_printf("0x%x ", array[i]);
// 在达到每行元素个数时换行
if ((i + 1) % elementsPerLine == 0) {
printf("\n");
debug_printf("\n");
}
}
printf("\n");
debug_printf("\n");
}
#endif
#define settw(a,b) {__asm__ __volatile__("settw res[%0], %1": : "r" (a) , "r" (b));}
#define setc(a,b) {__asm__ __volatile__("setc res[%0], %1": : "r" (a) , "r" (b));}
@@ -79,7 +78,7 @@ typedef struct {
clock qspiClkblk;
} fl_QSPIPorts;
*/
fl_QSPIPorts p_opt_qflash_tile0 =
fl_QSPIPorts p_opt_tile0 =
{
XS1_PORT_1B,
XS1_PORT_1C,
@@ -87,7 +86,7 @@ fl_QSPIPorts p_opt_qflash_tile0 =
XS1_CLKBLK_3
};
fl_QSPIPorts p_opt_qflash_tile1 =
fl_QSPIPorts p_opt_tile1 =
{
XS1_PORT_1F,
XS1_PORT_1G,
@@ -125,10 +124,12 @@ int flash_opt_enable_ports(fl_QSPIPorts *p_qflash)
if (!result)
{
/* All okay.. */
debug_printf("flash_opt_enable_ports success\n");
return 1;
}
else
{
debug_printf("flash_opt_enable_ports failed\n");
return 0;
}
}
@@ -143,15 +144,6 @@ void flash_cmd_opt(unsigned int cmd,
unsigned char input[], unsigned int num_in,
unsigned char output[], unsigned int num_out)
{
debug_printf("flash_cmd_opt: cmd = %02x, num_in = %d, num_out = %d\n", cmd, num_in, num_out);
for (size_t i = 0; i < num_in; i++)
{
debug_printf("input[%d] = %02x\n", i, input[i]);
}
for (size_t i = 0; i < num_out; i++)
{
debug_printf("output[%d] = %02x\n", i, output[i]);
}
fl_command(cmd,input,num_in,output, num_out);
}
@@ -182,7 +174,7 @@ void flash_opt_unlock(void)
uint8_t did[3];
/* Reason: 使用 tile0 端口连接 Flash保持原有逻辑 */
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0) {
if (flash_opt_enable_ports(&p_opt_tile0) == 0) {
debug_printf("flash_opt_unlock failed\n");
return;
}
@@ -293,8 +285,6 @@ unsigned compare_buff_diff(const uint8_t* actual, const uint8_t* expected, unsig
}
extern void hmac_sha1(const unsigned char *, unsigned long, const unsigned char * , unsigned long, unsigned char * );
void cal_hmac(uint8_t uid[], uint8_t did[], uint8_t hmac_bin[])
{
{
@@ -317,49 +307,64 @@ void cal_hmac(uint8_t uid[], uint8_t did[], uint8_t hmac_bin[])
hmac_sha1(key_bin, HMAC_GEN_LEN, msg_bin, HMAC_GEN_LEN, hmac_bin);
#if 0
printf("hmac_bin: \n");
printArrayHex1(hmac_bin, HMAC_LEN, 20);
#endif
}
}
uint8_t key_verify_old(unsigned sec_write, uint8_t expected_bin[], unsigned offset)
uint8_t opt_key_read(uint8_t key[], unsigned offset)
{
uint8_t read_bin[HMAC_LEN + 1];
uint8_t comp_bin[HMAC_LEN + 1];
uint8_t read_bin[KEY_BLOCK_LEN + 1];
uint8_t ret = 0;
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
return 0;
}
flash_opt_read(read_bin, KEY_BLOCK_LEN + 1);
for (int i = 0; i < 20; i++)
{
key[i] = read_bin[i + offset * 20 + 1];
}
flash_opt_disable_ports();
return 1;
}
uint8_t key_verify_program(unsigned verify_write, uint8_t expected_bin[], unsigned offset)
{
uint8_t read_bin[KEY_BLOCK_LEN + 1];
uint8_t comp_bin[KEY_BLOCK_LEN + 1];
uint8_t uid[20];
uint8_t did[4];
uint8_t ret = 0;
uint8_t hmac_bin[20];
flash_opt_read(read_bin, HMAC_LEN + 1);
flash_opt_read(read_bin, KEY_BLOCK_LEN + 1);
flash_opt_read_uid(uid, 20);
flash_opt_read_did(did, 3);
cal_hmac(uid, did, hmac_bin);
if (sec_write)
if (verify_write)
{
if (offset == 0)
if (offset == 1)
{
for (int i = 0; i < 20; i++)
cal_hmac(uid, did, hmac_bin);
if (compare_buff_diff(hmac_bin, expected_bin, 20) == 0)
{
read_bin[i + 1] = expected_bin[i];
}
}
else if (offset == 1)
{
for (int i = 0; i < 20; i++)
{
read_bin[i + 21] = expected_bin[i];
return 0;
}
}
flash_opt_write2(&read_bin[1], HMAC_LEN);
for (int i = 0; i < 20; i++)
{
read_bin[i + offset * 20 + 1] = expected_bin[i];
}
flash_opt_write2(&read_bin[1], KEY_BLOCK_LEN);
delay_milliseconds(10);
flash_opt_read(comp_bin, HMAC_LEN + 1);
if (compare_buff_diff(&comp_bin[1], &read_bin[1], HMAC_LEN) == 1)
flash_opt_read(comp_bin, KEY_BLOCK_LEN + 1);
if (compare_buff_diff(&comp_bin[1], &read_bin[1], KEY_BLOCK_LEN) == 1)
{
debug_printf("compare OK\n");
ret = 1;
@@ -367,50 +372,18 @@ uint8_t key_verify_old(unsigned sec_write, uint8_t expected_bin[], unsigned offs
}
else
{
if (offset == 0)
flash_opt_read(read_bin, KEY_BLOCK_LEN + 1);
if (compare_buff_diff(expected_bin, &read_bin[offset * 20 + 1], 20) == 1)
{
flash_opt_read(read_bin, HMAC_LEN + 1);
if (compare_buff_diff(hmac_bin, &read_bin[1], 20) == 1)
{
debug_printf("key_verified\n");
ret = 1;
}
}
else if (offset == 1)
{
flash_opt_read(read_bin, HMAC_LEN + 1);
if (compare_buff_diff(hmac_bin, &read_bin[21], 20) == 1)
{
debug_printf("key_verified\n");
ret = 1;
}
debug_printf("key_verified\n");
ret = 1;
}
}
return ret;
}
void flash_read_uid(uint8_t *uid)
{
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
return;
}
flash_opt_read_uid(uid, 20);
flash_opt_disable_ports();
}
void flash_read_did(uint8_t *did)
{
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
{
return;
}
flash_opt_read_did(did, 3);
flash_opt_disable_ports();
}
void get_key_ret(uint8_t *buffer)
{
//printf("get_key_ret2\n");
@@ -423,35 +396,6 @@ void get_key_ret(uint8_t *buffer)
//printArrayHex1(buffer, 20, 20);
}
unsigned char g_hid_pass_data[64];
extern void hidSetChangePending(unsigned int);
void user_read_hidpass(unsigned char * hidPassData)
{
int i = 0;
for (i = 0; i < 64; i++)
{
hidPassData[i] = g_hid_pass_data[i];
debug_printf("hidPassData[%d] = %02x\n", i, hidPassData[i]);
g_hid_pass_data[i] = 0;
}
}
void user_set_hidpass(unsigned char *data)
{
#if HID_CONTROLS
for (int i = 0; i < 63; i++)
{
g_hid_pass_data[i] = data[i];
debug_printf("g_hid_pass_data[%d] = %02x\n", i, g_hid_pass_data[i]);
}
hidSetChangePending(0x1);
#endif
}
static chanend_t g_flash_opt_c;
void flash_opt_set_chan(chanend_t c) {
@@ -466,72 +410,49 @@ void flash_opt_exchange_buffer(uint8_t in[64], uint8_t out[64]) {
chan_in_buf_byte(g_flash_opt_c, out, 40);
}
void flash_opt_key(chanend_t c) {
uint8_t buffer[64], reply[40] = {0, 0, 0, 0};
uint32_t ret;
delay_milliseconds(2);
while (1) {
chan_in_buf_byte(c, buffer, 40);
if (flash_opt_enable_ports(&p_opt_qflash_tile1) == 0) {
reply[0] = 0;
}
else
{
switch (buffer[3])
{
case 9:
flash_opt_read_did(&reply[1], 3);
reply[0] = 0x55;
break;
case 10:
flash_opt_read_uid(&reply[1], 21);
reply[0] = 0x55;
break;
case 8:
ret = key_verify_old(1, &buffer[4], 0);
if (ret == 1)
{
debug_printf("write key ret 0x55\n");
reply[0] = 0x55;
}
else
{
reply[0] = 0;
}
break;
}
flash_opt_disable_ports();
chan_out_buf_byte(c, reply, 40) ;
}
}
}
uint8_t key_validate(void)
uint8_t key_validate(uint8_t offset)
{
uint8_t ret = 0;
uint8_t data[1] = {0};
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
uint8_t read_bin[KEY_BLOCK_LEN + 1];
uint8_t uid[20];
uint8_t did[4];
uint8_t hmac_bin[20];
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
return 0;
}
ret = key_verify_old(0, data, 0);
if (ret == 1)
flash_opt_read(read_bin, KEY_BLOCK_LEN + 1);
flash_opt_read_uid(uid, 20);
flash_opt_read_did(did, 3);
cal_hmac(uid, did, hmac_bin);
if (compare_buff_diff(hmac_bin, &read_bin[offset * 20 + 1], 20) == 1)
{
SetKeyFlag(0x20241224);
debug_printf("key_verified\n");
ret = 1;
}
ret = key_verify_old(0, data, 1);
if (ret == 1)
{
SetKeyFlag(0x20241224);
}
flash_opt_disable_ports();
return ret;
}
void read_uid_did(uint8_t uid[])
{
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
return;
}
flash_opt_read_uid(uid, 20);
flash_opt_read_did(uid, 3);
flash_opt_disable_ports();
}
void program_key(uint8_t *buffer, int datalength)
{
if (buffer[0] == 0x77 && buffer[1] == 0x5B)
@@ -541,14 +462,13 @@ void program_key(uint8_t *buffer, int datalength)
{
case 1:
debug_printf("verify key\n");
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
uint8_t data[1] = {0};
ret = key_verify_old(0, data, 0);
ret = key_verify_program(0, &buffer[3], 1);
if (ret == 1)
{
hid_reply[0] = 0x55;
@@ -562,13 +482,13 @@ void program_key(uint8_t *buffer, int datalength)
break;
case 2:
debug_printf("write key\n");
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
ret = key_verify_old(1, &buffer[3], 0);
ret = key_verify_program(1, &buffer[3], 1);
debug_printf("write key ret %d\n", ret);
if (ret == 1)
@@ -584,7 +504,7 @@ void program_key(uint8_t *buffer, int datalength)
break;
case 3:
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
@@ -597,7 +517,7 @@ void program_key(uint8_t *buffer, int datalength)
}
break;
case 4:
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
@@ -610,7 +530,7 @@ void program_key(uint8_t *buffer, int datalength)
}
break;
case 5:
if (flash_opt_enable_ports(&p_opt_qflash_tile0) == 0)
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
@@ -623,6 +543,7 @@ void program_key(uint8_t *buffer, int datalength)
}
break;
case 6:
#if XUA_USB_EN == 1
debug_printf("get pid vid\n");
unsigned short pid = XUA_Endpoint0_getProductId();
unsigned short vid = XUA_Endpoint0_getVendorId();
@@ -631,22 +552,118 @@ void program_key(uint8_t *buffer, int datalength)
hid_reply[4] = (vid >> 8) & 0xff;
hid_reply[3] = vid & 0xff;
hid_reply[0] = 0x55;
#endif
break;
case 7:
debug_printf("write aizip key\n");
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
uint8_t ret = key_verify_program(1, &buffer[3], 0);
debug_printf("write key ret %d\n", ret);
if (ret == 1)
{
hid_reply[0] = 0x55;
}
else
{
hid_reply[0] = 0;
}
flash_opt_disable_ports();
}
break;
case 12:
debug_printf("verify aizip key\n");
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
ret = key_verify_program(0, &buffer[3], 0);
if (ret == 1)
{
hid_reply[0] = 0x55;
}
else
{
hid_reply[0] = 0;
}
flash_opt_disable_ports();
}
break;
case 13:
case 15:
case 17:
case 19:
case 21:
case 23:
case 25:
case 27:
case 29:
case 31:
case 33:
debug_printf("write key offset %d\n", ((buffer[2] - 13) / 2) + 2);
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
uint8_t ret = key_verify_program(1, &buffer[3], ((buffer[2] - 13) / 2) + 2);
debug_printf("write key ret %d\n", ret);
if (ret == 1)
{
hid_reply[0] = 0x55;
}
else
{
hid_reply[0] = 0;
}
flash_opt_disable_ports();
}
break;
case 14:
case 16:
case 18:
case 20:
case 22:
case 24:
case 26:
case 28:
case 30:
case 32:
case 34:
debug_printf("verify key offset %d\n", ((buffer[2] - 14) / 2) + 2);
if (flash_opt_enable_ports(&p_opt_tile0) == 0)
{
hid_reply[0] = 0;
}
else
{
ret = key_verify_program(0, &buffer[3], ((buffer[2] - 14) / 2) + 2);
if (ret == 1)
{
hid_reply[0] = 0x55;
}
else
{
hid_reply[0] = 0;
}
flash_opt_disable_ports();
}
break;
case 8:
case 9:
case 10:
//flash_opt_exchange_buffer(buffer, hid_reply);
// debug_printf("write aizip key tile 0 %02x\n", hid_reply[0]);
for (int i = 0; i < datalength; i++)
hid_reply[i] = 0;
case 11:
break;
}
}
else
{
//xmos_printf(&buffer[1], datalength - 1);
}
}

View File

@@ -0,0 +1,970 @@
# EQ HID通信协议详细文档
## 1. 总体框架
### 1.1 协议概述
该协议使用HID (Human Interface Device) 协议进行主机与设备之间的通信。协议支持EQ参数设置、读取、模式切换等功能。
### 1.2 支持的指令列表
| 指令码 | 命令名称 | 功能 | 方向 | 描述 |
|--------|----------|------|------|------|
| 0x82 | SET_MIC_VOLUME | 设置麦克风增益级别 | 主机→设备 | 设置麦克风PGA增益0=静音, 1-37=0dB~36dB, 1dB/步) |
| 0x83 | GET_MIC_VOLUME | 获取麦克风增益级别 | 主机→设备 | 读取当前麦克风PGA增益级别0=静音, 1-37=0dB~36dB |
| 0x84 | FACTORY_RESET | 恢复出厂默认设置 | 主机→设备 | 删除Flash中所有已保存参数设备重启后自动恢复出厂默认值 |
| 0x85 | SET_AI_NOISE_STRENGTH | 设置AI降噪强度 | 主机→设备 | 设置AI降噪强度0=关闭2-100偶数=强度级别步进2100对应最强-200dB |
| 0x86 | GET_AI_NOISE_STRENGTH | 获取AI降噪强度 | 主机→设备 | 读取当前AI降噪强度强度变化含按键切换、开机初始值时设备主动上报 |
| 0x87 | SET_MONITOR_SWITCH | 设置耳返开关 | 主机→设备 | 设置耳返ADC→耳机监听开关0=关闭1=开启保存到Flash |
| 0x88 | GET_MONITOR_SWITCH | 获取耳返开关状态 | 主机→设备 | 读取当前耳返开关状态0=关闭1=开启) |
| 0x8A | SET_EQ_MODE | 切换EQ模式 | 主机→设备 | 切换EQ模式 |
| 0x8B | GET_EQ_MODE | 获取当前EQ模式信息 | 主机→设备 | 读取设备当前EQ模式和名称 |
| 0x8C | SET_MODE_GAIN_AND_NAME | 设置模式整体增益和名称 | 主机→设备 | 设置模式整体增益和名称 |
| 0x8D | SET_EQ_PARAMS | 发送EQ参数 | 主机→设备 | 发送单个滤波器的参数 |
| 0x8E | GET_EQ_PARAMS | 读取EQ参数 | 主机→设备 | 读取单个滤波器的参数 |
| 0x8F | GET_DEVICE_INFO | 获取设备信息 | 主机→设备 | 读取设备PID、VID、产品字符串等信息 |
| 0x90 | RESET_EQ_PARAMS | 复位EQ参数 | 主机→设备 | 删除Flash中的EQ参数并恢复头文件预设参数 |
| 0x91 | GET_EQ_MODE_COUNT | 获取EQ模式总数 | 主机→设备 | 返回预定义加用户模式的总数(不包含禁用模式) |
| 0x92 | SET_AND_SAVE_EQ_MODE | 设置并保存EQ模式 | 主机→设备 | 设置当前EQ模式(0-9)并保存到Flash开机时自动恢复 |
| 0x93 | SET_VOLUME | 设置监听音量级别 | 主机→设备 | 设置设备监听音量级别0=静音, 1-29=-28dB~0dB, 1dB/步) |
| 0x94 | GET_VOLUME | 获取监听音量级别 | 主机→设备 | 读取设备当前监听音量级别0=静音, 1-29=-28dB~0dB, 1dB/步) |
| 0x9D | SET_EQ_ENABLE | 设置EQ使能开关 | 主机→设备 | 设置EQ使能开关ON/OFF禁用时保存当前模式启用时恢复之前模式 |
| 0x9E | GET_EQ_ENABLE | 获取EQ使能开关 | 主机→设备 | 读取EQ使能开关状态ON/OFF |
| 0x9F | GET_SAMPLE_FORMAT | 获取采样率和格式 | 主机→设备 | 读取当前采样率、DSD模式和DAC采样分辨率 |
| 0xA4 | SET_SOUND_EFFECT_MODE | 设置音效模式 | 主机→设备 | 设置音效模式0=无音效1=音乐模式2=游戏模式3=AI7.1模式) |
| 0xA5 | GET_SOUND_EFFECT_MODE | 获取音效模式 | 主机→设备 | 读取当前音效模式0-3 |
| 0xA6 | GET_FIRMWARE_VERSION | 获取固件版本 | 主机→设备 | 读取设备固件版本号BCD格式主版本.次版本.修订版本) |
| 0xA7 | FIRMWARE_UPGRADE_START | 开始固件升级 | 主机→设备 |
| 0xA8 | FIRMWARE_UPGRADE_DATA | 传输固件数据块固定57字节 | 主机→设备 |
| 0xA9 | FIRMWARE_UPGRADE_END | 结束固件升级,验证镜像 | 主机→设备 |
| 0xAA | FIRMWARE_UPGRADE_STATUS | 获取升级状态和进度 | 主机→设备 |
| 0xAB | FIRMWARE_UPGRADE_ABORT | 中止固件升级 | 主机→设备 |
| 0xAC | FIRMWARE_UPGRADE_ERASE | 擦除现有升级镜像 | 主机→设备 |
| 0xAE | DEVICE_REBOOT | 设备重启(通用命令) | 主机→设备 |
| 0xB0 | SET_EX3D_CMD | 发送EX3D命令 | 主机→设备 | 发送EX3D设置命令封装所有EX3D SET命令 |
| 0xB1 | GET_EX3D_CMD | 读取EX3D命令 | 主机→设备 | 读取EX3D参数封装所有EX3D GET命令 |
### 1.3 数据包格式
- **Report ID**: 0x01 (HID报告ID)
- **数据包大小**: 64字节 (1字节Report ID + 63字节数据)
- **同步头**: 0x77 (所有命令的第一个字节)
- **字节序**: 小端序 (Little Endian)
## 2. 详细指令说明
### 2.0 0x82 - SET_MIC_VOLUME (设置麦克风增益级别)
**功能**: 设置麦克风PGA增益级别
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x82 | 命令码
2 | 1 | uint8 | 增益级别 (0=静音, 1-37=0dB~36dB, 1dB/步)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **增益级别范围:** 0-37共38级
- 0静音mute
- 10dB最小有效增益
- 21dB
- ...1dB/步)
- 3736dB最大HID可设置增益
**返回值**:
无直接返回值。设备端增益变化会主动上报0x83格式数据包。
### 2.0b 0x83 - GET_MIC_VOLUME (获取麦克风增益级别)
**功能**: 读取设备当前麦克风PGA增益级别设备端增益变化时也会主动上报
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x83 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**(含主动上报):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x83 | 同步头2
3 | 1 | uint8 | 当前增益级别 (0=静音, 1-37=0dB~36dB)
4-62 | 59 | 0x00 | 保留字节
```
### 2.0c 0x84 - FACTORY_RESET (恢复出厂默认设置)
**功能**: 删除Flash中所有已保存的用户参数设备重启后自动恢复出厂默认值
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x84 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**出厂默认参数**:
| 参数 | 出厂默认值 | 说明 |
|------|-----------|------|
| AI7.1音效模式 | 3 (AI7.1开启) | 音效模式 0=无音效, 1=音乐, 2=游戏, 3=AI7.1 |
| 脚步增强 | 12dB (全亮, 状态2) | LED全亮, 扩展增益12dB |
| 麦克风音量 | 22 (21dB) | PGA寄存器值22 = 21dB |
| 监听音量 | 15 (-14dB) | DAC level 15 = 0dB - 14 = -14dB |
| EQ参数 | 头文件预设 | 删除所有用户EQ参数恢复固件内置预设 |
| AI降噪 | 开启 | 每次上电默认开启不保存到Flash |
| 耳返开关 | 0 (关闭) | ADC→耳机监听通路默认关闭 |
| 麦克风静音 | 0 (未静音) | 麦克风静音状态默认关闭 |
| 监听静音 | 0 (未静音) | 耳机输出静音状态默认关闭 |
**设备端处理**:
1. 删除Flash中保存的以下参数文件
- `game_mode`(音效模式)
- `mic_vol`(麦克风音量)
- `dac_vol`(监听音量)
- `footstep`(脚步增强状态)
- `monitor_sw`(耳返开关)
- `mic_mute`(麦克风静音状态)
- `hp_mute`(耳机静音状态)
- 所有EQ参数文件调用eq_flash_clear_all
2. 设置重启标志约500ms后设备自动重启
3. 重启后自动加载出厂默认参数
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x84 | 同步头2
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
4-62 | 59 | 0x00 | 保留字节
```
**注意**:
- 执行后设备将在约500ms后自动重启USB连接会短暂断开后重连
- 重启后所有参数将恢复为出厂默认值
- 此操作不可撤销
### 2.0d 0x85 - SET_AI_NOISE_STRENGTH (设置AI降噪强度)
**功能**: 设置AI降噪强度级别
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x85 | 命令码
2 | 1 | uint8 | 强度值 (0=关闭, 2/4/.../100=强度级别, 步进2)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **强度值范围**: 0、2、4、6、…、100共51个有效值
- **0**: 关闭AI降噪
- **2-100步进2**: 开启AI降噪强度递增内部dB映射`dB = -(strength × 2)`
- 2 → -4 dB最轻微降噪
- 50 → -100 dB
- 100 → -200 dB最强降噪出厂默认
- **奇数或 >100** 为无效值,固件将拒绝(返回无响应)
**设备端处理**:
- 强度=0关闭AI降噪算法熄灭LED_ANCflag_aidenoise_onoff=0
- 强度=2-100开启AI降噪算法点亮LED_ANCflag_aidenoise_onoff=1更新内部降噪深度
- 设置成功后设备主动上报当前强度0x86格式
- **不保存到Flash**重启后AI降噪恢复为开启强度=100即-200dB最强
**返回值**:
无直接返回设置成功后设备通过0x86格式主动上报当前强度值。
### 2.0e 0x86 - GET_AI_NOISE_STRENGTH (获取AI降噪强度)
**功能**: 读取设备当前AI降噪强度强度变化时设备主动上报
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x86 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**(含主动上报):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x86 | 同步头2
3 | 1 | uint8 | 当前强度值 (0=关闭, 2-100=强度级别)
4-62 | 59 | 0x00 | 保留字节
```
**主动上报说明**:
- **开机时**:设备初始化完成后主动上报当前强度(出厂默认=100
- **按键切换**用户按下AI降噪按键时设备主动上报新强度关闭时上报0开启时上报恢复的强度
- **HID SET_AI_NOISE_STRENGTH0x85命令成功执行后**,设备主动上报新强度
### 2.0f 0x87 - SET_MONITOR_SWITCH (设置耳返开关)
**功能**: 设置耳返ADC→耳机监听开关控制是否将麦克风输入实时路由到耳机输出
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x87 | 命令码
2 | 1 | uint8 | 开关值 (0=关闭, 1=开启)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **0**: 关闭耳返ADC数据不路由到耳机输出NAU88L21 reg 0x0035 = 0x0000
- **1**: 开启耳返ADC数据路由到耳机输出NAU88L21 reg 0x0035 = 0xCFCF0dB监听音量
- **注意**: 耳返路由需要麦克风未静音mic_mute=0且麦克风增益有效level≥2方才生效
**设备端处理**:
- 立即更新 NAU88L21 reg 0x0035耳返音量寄存器
- 若麦克风当前处于静音状态则无论耳返开关为何值reg 0x0035保持0x0000
- 保存到Flash`monitor_sw`路径),断电重启后自动恢复
- 设置成功后用0x88格式响应当前状态
- 出厂默认关闭0
**返回值**:
设置成功后设备回复0x88格式响应。
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x88 | 同步头2
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
4-62 | 59 | 0x00 | 保留字节
```
### 2.0g 0x88 - GET_MONITOR_SWITCH (获取耳返开关状态)
**功能**: 读取当前耳返开关状态
**方向**: 主机→设备(请求),设备→主机(响应)
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x88 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x88 | 同步头2
3 | 1 | uint8 | 当前耳返开关状态 (0=关闭, 1=开启)
4-62 | 59 | 0x00 | 保留字节
```
### 2.1 0x8A - SET_EQ_MODE (切换EQ模式)
**功能**: 切换当前EQ模式
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8A | 命令码
2 | 1 | uint8 | 模式值 (0-9: 预设模式, 10-11: 用户模式)
3-62 | 60 | 0x00 | 保留字节
```
## 2.2 0x8B - GET_EQ_MODE (读取EQ模式信息)
**功能**: 读取EQ模式信息
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8B | 命令码
2 | 1 | uint8 | 模式值 (0-11: 有效模式值, 0xFF: 获取当前模式信息)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理**:
- 如果mode值为0xFF返回当前模式值、整体增益和模式名称
- 如果mode值为有效模式值(0-11),返回指定模式值、整体增益和模式名称
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x8B | 同步头2
3 | 1 | uint8 | 模式值 (当前模式或指定模式)
4-7 | 4 | int32 | 增益值 (范围0到-50dB有符号整数)
8-23 | 16 | char | 模式名称 (UTF-8编码16字节)
24-62 | 39 | 0x00 | 保留字节
```
**使用说明**:
- 发送mode=0xFF时返回当前激活的EQ模式信息
- 发送mode=0-11时返回指定模式的增益和名称信息不切换当前模式
### 2.3 0x8C - SET_MODE_GAIN_AND_NAME (设置模式整体增益和名称)
**功能**: 设置EQ模式整体增益和名称
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8C | 命令码
2 | 1 | uint8 | 模式值 (0-11)
3-6 | 4 | int32 | 增益值 (范围0到-50dB有符号整数)
7-22 | 16 | char | 模式名称 (UTF-8编码16字节)
23-62 | 40 | 0x00 | 保留字节
```
**使用场景**:
- 需要为特定模式设置整体增益补偿和自定义名称
- 自动应用到所有采样率以确保一致性
### 2.4 0x8D - SET_EQ_PARAMS (发送EQ参数)
**功能**: 发送单个滤波器的参数
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8D | 命令码
2 | 1 | uint8 | 模式值 (0-11)
3 | 1 | uint8 | 滤波器Band索引 (0-7)
4 | 1 | uint8 | 滤波器类型
5-8 | 4 | float | 中心频率 (Hz)
9-12 | 4 | float | Q值
13-16 | 4 | float | 带宽 (Hz)
17-20 | 4 | float | 增益 (dB)
21-62 | 42 | 0x00 | 保留字节
```
**滤波器类型码**:
| 类型码 | 滤波器类型 |
|--------|------------|
| 0x00 | bypass滤波器 |
| 0x01 | 全通滤波器 |
| 0x02 | 峰值滤波器 |
| 0x03 | 低通滤波器 |
| 0x04 | 高通滤波器 |
| 0x09 | 低架滤波器 |
| 0x0A | 高架滤波器 |
### 2.5 0x8E - GET_EQ_PARAMS (读取EQ参数)
**功能**: 读取单个滤波器的参数
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8E | 命令码
2 | 1 | uint8 | 模式值 (0-11)
3 | 1 | uint8 | EQ索引 (0-7)
4-62 | 59 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x8E | 同步头2
3 | 1 | uint8 | 模式值 (0-11)
4 | 1 | uint8 | 滤波器Band索引 (0-7)
5 | 1 | uint8 | 滤波器类型
6-9 | 4 | float | 中心频率 (Hz)
10-13 | 4 | float | Q值
14-17 | 4 | float | 带宽 (Hz)
18-21 | 4 | float | 增益 (dB)
22-62 | 41 | 0x00 | 保留字节
```
### 2.6 0x8F - GET_DEVICE_INFO (获取设备信息)
**功能**: 获取设备基本信息
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x8F | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x8F | 同步头2
3-4 | 2 | uint16 | 产品ID (PID)
5-6 | 2 | uint16 | 厂商ID (VID)
7-22 | 16 | char | 产品字符串 (UTF-8编码16字节)
23-38 | 16 | char | 厂商字符串 (UTF-8编码16字节)
39-54 | 16 | char | 序列号字符串 (UTF-8编码16字节)
55-62 | 8 | 0x00 | 保留字节
```
### 2.7 0x90 - RESET_EQ_PARAMS (复位EQ参数)
**功能**: 删除客户定制EQ参数并恢复预设参数
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x90 | 命令码
2 | 1 | uint8 | 模式号 (0-11, 0xFF表示恢复所有包括EQ参数总体增益模式名称 )
3-62 | 60 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x90 | 同步头2
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
4-62 | 59 | 0x00 | 保留字节
```
### 2.8 0x91 - GET_EQ_MODE_COUNT (获取EQ模式总数)
**功能**: 获取预定义加用户模式的总数(不包含禁用模式)
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x91 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x91 | 同步头2
3 | 1 | uint8 | 模式总数 (当前为12包含0-11共12个模式不包含禁用模式)
4 | 1 | uint8 | 预定义模式数量 (当前为10包含0-9共10个预设模式)
5-62 | 58 | 0x00 | 保留字节
```
### 2.9 0x92 - SET_AND_SAVE_EQ_MODE (设置并保存EQ模式)
**功能**: 设置当前EQ模式并保存到Flash开机时自动恢复
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x92 | 命令码
2 | 1 | uint8 | 模式值 (0-11: 0-9预设模式, 10-11用户模式)
3-62 | 60 | 0x00 | 保留字节
```
**设备端处理**:
- 将模式值保存到Flash
- 开机时自动从Flash读取并恢复该模式
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x92 | 同步头2
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
4-62 | 59 | 0x00 | 保留字节
```
### 2.10 0x93 - SET_VOLUME (设置监听音量级别)
**功能**: 设置设备监听(耳机/DAC音量级别
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x93 | 命令码
2 | 1 | uint8 | 音量级别 (0-29: 0=静音, 1=-28dB, ..., 29=0dB)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **音量级别范围:** 0-29共30级
- **说明:** 控制设备监听输出DAC/耳机)音量级别
- 0: 静音muteDAC完全静音
- 1: -28dB最小有效音量
- 2: -27dB
- ...每级1dB步进
- 29: 0dB最大音量
**返回值**:
无直接返回值。如需确认音量是否设置成功请使用GET_VOLUME命令读取当前音量。设备端音量变化含编码器旋转引起的变化会主动通过0x94格式上报。
### 2.11 0x94 - GET_VOLUME (获取监听音量级别)
**功能**: 读取设备当前监听音量级别;设备端音量变化时也会主动上报此格式
**方向**: 主机→设备(请求),设备→主机(响应/主动上报)
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x94 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**(含主动上报):
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x94 | 同步头2
3 | 1 | uint8 | 当前音量级别 (0-29: 0=静音, 1-29=-28dB~0dB, 1dB/步)
4-62 | 59 | 0x00 | 保留字节
```
### 2.20 0x9D - SET_EQ_ENABLE (设置EQ使能开关)
**功能**: 设置EQ使能开关启用/禁用)
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x9D | 命令码
2 | 1 | uint8 | EQ使能开关 (0=OFF禁用, 1=ON启用)
3-62 | 60 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x9D | 同步头2
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
4 | 1 | uint8 | 当前EQ使能状态 (0=OFF, 1=ON)
5-62 | 58 | 0x00 | 保留字节
```
### 2.21 0x9E - GET_EQ_ENABLE (获取EQ使能开关)
**功能**: 读取EQ使能开关状态
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x9E | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x9E | 同步头2
3 | 1 | uint8 | EQ使能开关状态 (0=OFF禁用, 1=ON启用)
4-62 | 59 | 0x00 | 保留字节
```
**设备端处理**:
- 返回当前EQ使能开关状态0=OFF, 1=ON
### 2.22 0x9F - GET_SAMPLE_FORMAT (获取采样率和格式)
**功能**: 读取当前采样率和DSD模式
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0x9F | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x9F | 同步头2
3-6 | 4 | uint32 | 采样率 (samFreq小端序单位Hz)
7 | 1 | uint8 | DSD模式 (dsdMode: 0=PCM, 1=DOP, 2=Native DSD)
8-62 | 55 | 0x00 | 保留字节
```
**设备端处理**:
- 返回当前采样率32位无符号整数小端序单位Hz
- 返回DSD模式0表示PCM格式>0表示DSD格式
- 设备会在采样率或DSD模式发生变化时自动上报此信息通过HID状态报告
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0x9E | 同步头2
3 | 1 | uint8 | EQ使能开关状态 (0=OFF禁用, 1=ON启用)
4 | 1 | uint8 | 保存的模式值 (0-9如果之前有保存0xFF表示未保存)
5-62 | 58 | 0x00 | 保留字节
```
**设备端处理**:
- 返回当前EQ使能开关状态
- 返回之前保存的模式值(如果存在)
### 2.27 0xA4 - SET_SOUND_EFFECT_MODE (设置音效模式)
**功能**: 设置音效模式
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xA4 | 命令码
2 | 1 | uint8 | 音效模式值 (0=无音效, 1=音乐模式, 2=游戏模式, 3=AI7.1模式)
3-62 | 60 | 0x00 | 保留字节
```
**参数说明**:
- **音效模式范围:** 0-3
- **说明:** 选择音效模式,与硬件按键效果相同
- 0: 无音效 — 所有模式按键灯灭EQ算法关闭EX3D算法关闭
- 1: 音乐模式 — 音乐键灯亮EQ算法开启EX3D算法关闭
- 2: 游戏模式 — 游戏键灯亮EQ算法开启EX3D游戏声场(SF=0)开启
- 3: AI7.1模式 — AI7.1键灯亮EQ算法开启EX3D AI7.1声场(SF=1)开启
**返回值**:
无直接返回值。如需确认音效模式是否设置成功请使用GET_SOUND_EFFECT_MODE命令读取当前音效模式。
### 2.28 0xA5 - GET_SOUND_EFFECT_MODE (获取音效模式)
**功能**: 读取设备当前音效模式
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xA5 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xA5 | 同步头2
3 | 1 | uint8 | 当前音效模式 (0=无音效, 1=音乐模式, 2=游戏模式, 3=AI7.1模式)
4-62 | 59 | 0x00 | 保留字节
```
### 2.29 0xA6 - GET_FIRMWARE_VERSION (获取固件版本)
**功能**: 读取设备固件版本号
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xA6 | 命令码
2-62 | 61 | 0x00 | 保留字节
```
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xA6 | 同步头2
3 | 1 | uint8 | 主版本号 (BCD格式如0x01表示1)
4 | 1 | uint8 | 次版本号 (BCD格式如0x00表示0)
5 | 1 | uint8 | 修订版本号 (BCD格式如0x0C表示12)
6-62 | 57 | 0x00 | 保留字节
```
**版本号格式说明**:
- 版本号采用BCDBinary Coded Decimal格式
- 3个字节分别表示主版本号、次版本号、修订版本号
- 例如0x01 0x00 0x0C 表示版本 1.0.12
### 2.30 0xB0 - SET_EX3D_CMD (发送EX3D命令)
**功能**: 发送EX3D设置命令封装所有EX3D SET命令
**方向**: 主机→设备
**数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB0 | 命令码
2-5 | 4 | uint32 | EX3D命令码包含SET标志参考下方两个命令详情
6-9 | 4 | uint32 | 参数1根据EX3D命令不同而不同
10-13 | 4 | uint32 | 参数2根据EX3D命令不同而不同
14-17 | 4 | uint32 | 参数3根据EX3D命令不同而不同
18-62 | 45 | 0x00 | 保留字节或扩展参数
```
**EX3D命令码说明**:
- SET命令格式: `基础命令码 & ~0x0100`清除第9位
- 支持的SET命令
- 0x87: CMD_LMT_THRESHOLD设置枪声阈值
- 0x93: CMD_EXPAND_GAIN设置脚步声增益
**设备端处理**:
- 解析EX3D命令码提取基础命令码和参数
- 根据命令类型执行相应的设置操作
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xB0 | 同步头2
3 | 1 | uint8 | 状态码 (0x00=成功, 0x01=失败)
4-7 | 4 | uint32 | EX3D命令码回显
8-11 | 4 | uint32 | 返回值某些命令返回0xFFFFFFFF表示参数错误
12-62 | 51 | 0x00 | 保留字节
```
### 2.31 0xB1 - GET_EX3D_CMD (读取EX3D命令)
**功能**: 读取EX3D参数封装所有EX3D GET命令
**方向**: 主机→设备
**请求数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x77 | 同步头1
1 | 1 | 0xB1 | 命令码
2-5 | 4 | uint32 | EX3D命令码包含GET标志参考下方两个命令详情
6-9 | 4 | uint32 | 参数1根据EX3D命令不同而不同如通道号、索引等
10-62 | 53 | 0x00 | 保留字节或扩展参数
```
**EX3D命令码说明**:
- GET命令格式: `基础命令码 | 0x0100`设置第9位
- 支持的GET命令
- 0x187: CMD_LMT_THRESHOLD获取枪声阈值
- 0x193: CMD_EXPAND_GAIN获取脚步声增益
**设备端处理**:
- 解析EX3D命令码提取基础命令码和参数
- 调用相应的EX3D处理函数hid_receive_task_in_c
- 返回当前参数值
**响应数据包格式**:
```
字节位置 | 长度 | 内容 | 描述
---------|------|------|------
0 | 1 | 0x01 | Report ID
1 | 1 | 0x77 | 同步头1
2 | 1 | 0xB1 | 同步头2
3-6 | 4 | uint32 | EX3D命令码回显
7-10 | 4 | uint32 | 返回值1根据命令不同而不同
11-14 | 4 | uint32 | 返回值2某些命令需要多个返回值如角度、多通道数据等
15-18 | 4 | uint32 | 返回值3扩展返回值如多通道数据
... | ... | ... | 其他返回值最多可返回14个uint32值总长度不超过63字节
```
**返回值说明**:
- 返回值数量和格式取决于具体的EX3D命令
- 单值命令返回1个uint32值
- 多值命令如角度、多通道数据返回多个uint32值
- 字符串命令(如声场名称):先返回长度(uint32),然后返回字符串数据
- 详细的返回值格式请参考下方两个命令详情
**使用说明**:
- 该命令用于统一封装所有EX3D读取命令
- 参数格式与原始EX3D协议保持一致
- 详细的EX3D命令说明请参考ex3d_protocol.md文档
## 5. 关键特性
### 5.1 设备端系数计算
- 主机只发送参数 (fc, Q, bw, gain)
- 设备端根据参数实时计算滤波器系数
### 5.2 参数格式
- **浮点参数**: fc, Q, bw, gain 使用IEEE 754 float格式传输
- **字节序**: 所有多字节数据使用小端序
### 5.3 错误处理
- 数据包长度检查
- 同步头验证
- 参数范围检查
- 滤波器索引边界检查
### 5.4 模式管理
- 支持12个EQ模式 (0-11: 0-9预设模式, 10,11, 用户模式)
- 模式切换时自动清除滤波器状态
## 7. 注意事项
1. **时序要求**: 发送参数后需要等待设备处理完成再发送下一条命令
2. **数据完整性**: 所有8个滤波器的参数都需要发送即使某些滤波器未使用
3. **模式同步**: 设置模式后需要调用读取模式确保数据同步
4. **错误恢复**: 通信失败时需要重新建立连接并重试
5. **参数验证**: 设备端会验证参数范围,超出范围的值会被限制
---
## 8. 固件升级命令 (0xA70xAE)
本节定义通过HID进行固件升级的命令。最大数据块57字节Flash页256字节字节序小端序。
### 8.1 固件升级命令列表
### 8.2 0xA7 - FIRMWARE_UPGRADE_START
**请求**:
```
字节 0: 0x77 同步头
字节 1: 0xA7 命令码
字节 2-5: uint32 固件大小(字节,小端序)
字节 6-62: 0x00 保留
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA7
字节 2: 状态码 (0x00=成功, 0x01=失败, 0x03=大小无效)
字节 3-6: uint32 页对齐后的实际大小
字节 7-8: uint16 总块数
字节 9-62: 0x00
```
### 8.3 0xA8 - FIRMWARE_UPGRADE_DATA
**请求**数据块固定57字节不足补0:
```
字节 0: 0x77
字节 1: 0xA8
字节 2-3: uint16 块序号从0开始小端序
字节 4: uint8 数据长度固定57
字节 5-61: uint8[57] 固件数据
字节 62: uint8 Checksum字节0-61累加 mod 256
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA8
字节 2: 状态码 (0x00=成功, 0x04=块号错误, 0x05=Checksum错误)
字节 3-4: uint16 已确认块序号
字节 5-62: 0x00
```
### 8.4 0xA9 - FIRMWARE_UPGRADE_END
**请求**:
```
字节 0: 0x77
字节 1: 0xA9
字节 2-5: uint32 固件总大小(用于验证)
字节 6-62: 0x00
```
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xA9
字节 2: 状态码 (0x00=成功, 0x01=失败)
字节 3-62: 0x00
```
### 8.5 0xAA - FIRMWARE_UPGRADE_STATUS
**请求**: 字节0=0x77, 字节1=0xAA, 其余0x00
**响应**(主动上报):
```
字节 0: 0x77
字节 1: 0xAA
字节 2: 升级状态 (0=空闲, 1=准备中, 2=传输中, 3=完成中, 4=已完成, 5=错误, 6=已中止)
字节 3-4: uint16 已接收块数
字节 5-6: uint16 总块数
字节 7-8: uint16 已写页数
字节 9-10: uint16 总页数
字节 11-14: uint32 已传输字节数
字节 15-18: uint32 总字节数
字节 19: 错误码
字节 20-62: 0x00
```
### 8.6 0xAB - FIRMWARE_UPGRADE_ABORT
**请求**:
```
字节 0: 0x77
字节 1: 0xAB
字节 2: 清理标志 (0x00=保留数据, 0x01=擦除数据)
字节 3-62: 0x00
```
**响应**(主动上报): 字节0=0x77, 字节1=0xAB, 字节2=状态码(0x00=成功)
### 8.7 0xAC - FIRMWARE_UPGRADE_ERASE
**请求**: 字节0=0x77, 字节1=0xAC, 其余0x00
**响应**(主动上报): 字节0=0x77, 字节1=0xAC, 字节2=状态码(0x00=成功)
### 8.8 0xAE - DEVICE_REBOOT
**请求**: 字节0=0x77, 字节1=0xAE, 其余0x00
**响应**: 无响应,设备立即重启。
### 8.9 标准升级流程
```
1. (可选) ERASE — 擦除现有upgrade image
2. START — 设置固件大小,等待响应(SUCCESS)
3. 循环 DATA — 逐块发送,每块等待响应确认
4. END — 完成写入,等待响应(SUCCESS)
5. REBOOT — 重启加载新固件
```