Compare commits

...

182 Commits

Author SHA1 Message Date
yuquanjun d330e17bf1 chore(release): bump firmware to 0.2.61 and tone resources to 1019
The updated 1.bin is smaller and still fits; 2.bin and 3.bin stay at the same flash addresses.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-19 19:00:45 +08:00
yuquanjun b02072c950 chore(release): bump firmware to 0.2.60 and tone resources to 1016
The new 1.bin is smaller and keeps the same flash addresses for 2.bin and 3.bin.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 20:37:36 +08:00
yuquanjun 756639f5f6 fix(accomp): limit the eight-note sequence to the first rhythm
Other rhythms send several notes at once, so walking that arpeggio list turned their chords into the wrong pitches.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 20:37:36 +08:00
yuquanjun 1dfa0991a5 chore(release): bump firmware to 0.2.59
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 15:35:01 +08:00
yuquanjun 5b9ab3c098 fix(accomp): keep the sixth arpeggio note on the next eighth
The extra note stacked on the fifth eighth was consuming the next sequence step, so later bars drifted. Drop that trigger instead of delaying the rest of the cycle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 15:35:01 +08:00
yuquanjun b9fcddd9b3 chore(release): bump firmware to 0.2.58
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 12:22:55 +08:00
yuquanjun 927509ceb5 fix(accomp): delay a same-tick arpeggio note by one eighth
The circled Em notes were stacked on the previous eighth. Hold only that extra note, and time it from the millisecond clock that actually runs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 12:08:29 +08:00
yuquanjun 3c81607daf fix(chord): play sheet accompaniment sequences and chord tones
III-VII shapes use the C-major sequence column with the same fixed-key offset as the strings. Chord tones follow the decimal column. Bump firmware to 0.2.57.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 19:22:17 +08:00
yuquanjun 99c2d84465 chore(release): bump firmware to 0.2.56
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 14:59:12 +08:00
yuquanjun 9089c9994a test(chord): retry dropped RTT reads in the fixed-key voicing check
STRING_OK lines are sometimes lost under load. Resend the string command until the note comes back.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 14:58:28 +08:00
yuquanjun 605af8f045 fix(chord): apply fixed-key voicings from the new chord sheet
Stop adding transpose to every string and AutoBand tone. Each degree now uses the C-major source fret from the sheet, with +1 only where the sheet marks it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 14:38:23 +08:00
yuquanjun e49f5a06fc chore(release): bump firmware to 0.2.55
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 09:34:38 +08:00
yuquanjun d16c3320fd fix(led): reverse neck lamp colors so degree 1 is white and 7 is red
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 09:34:02 +08:00
yuquanjun b9bf460232 chore(release): bump firmware to 0.2.54
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 06:48:50 +08:00
yuquanjun 57e2789659 fix(ui): keep playback and mode keys while the settings pages are open
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 06:47:59 +08:00
yuquanjun 6166bb8346 chore(release): bump firmware to 0.2.53
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 11:31:15 +08:00
yuquanjun a68b978c08 fix(univ): finish the universal outro so the pick can start again
Keep the last 1/2/3 fill on screen, and leave neck lights all green in normal and expert unless the app is guiding them.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 11:20:51 +08:00
yuquanjun ccad4570d8 fix(led): keep app chord lights when strumming during sing-along
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 16:11:28 +08:00
yuquanjun 5b2c8137eb fix(ui): draw mixer volume badges from the rounded art swatch
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 16:00:17 +08:00
yuquanjun ac01d0f6b7 fix(ui): ignore fill keys 1-4 on the system settings page
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 15:41:12 +08:00
yuquanjun 9b9aaeaadf fix(ui): keep the boot logo until the light show finishes
Mode select was covering the logo before the side lights played. Firmware is 0.2.52.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 18:37:42 +08:00
yuquanjun a8bf9a3a91 fix(power): skip boot lights and sound-board init below 6.8V
A protected pack only trickle-charges, so Dream, the 12V rail, and the amp stay off until the pack is above 6.8V. Firmware is 0.2.51.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 17:58:02 +08:00
yuquanjun 6ce5d7a453 fix(audio): hold mode entry until the sound board finishes init
Dream power-up now overlaps the boot light show. Mode keys, the pick, and side keys stay ignored until MIDI config has been sent, so a fast tap cannot play before the board is ready.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 17:24:16 +08:00
yuquanjun cb6c2da5ce fix(bpm): play each track at its default tempo and keep only the remembered settings
Boot and song changes use the universal and rhythm BPM tables, with style 20 at 91. Factory restore and power-on now follow the persistence sheet, and the firmware version is 0.2.49.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 17:11:49 +08:00
yuquanjun bd40b076b7 chore(release): bump firmware to 0.2.48
Pick is start-only in universal mode, and the key-board LEDs recover after the board is reinserted.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 17:33:28 +08:00
yuquanjun 71f14f69f9 fix(led): relight the key board after hot-plug or late insert
TM1629 drops display-on when the board loses power, while key reads still work. Re-enable the display and rewrite the current pattern when the board is seen again.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 17:28:15 +08:00
yuquanjun 3fab5024a9 fix(pick): ignore universal-mode strums while playback is running
The pick only starts the piece. A later strum must not restart the preamble or change the chord.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 17:28:15 +08:00
yuquanjun 8c8c728752 chore(release): bump firmware to 0.2.47
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 16:57:17 +08:00
yuquanjun d07b14c29d fix(midi): raise Em, F, G, and Am plucked string voicings
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 16:55:36 +08:00
yuquanjun 53c21eee50 chore(release): pack tone resources 1008 and bump to 0.2.46
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 20:45:20 +08:00
yuquanjun e0860dd375 chore(release): bump firmware to 0.2.45
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 16:29:30 +08:00
yuquanjun 75ee80722c fix(midi): map concert steel to Bank1 program 24
Bump firmware to 0.2.44 so slot 1 stays Bank1 program 24 and slot 2 stays program 25. Rhythm presets no longer replace the string voice on channel 0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 16:22:42 +08:00
yuquanjun 11ddab46f5 fix(ui): boot string tone as concert steel guitar
Show item 1 (Bank1 program 24, catalog tone 25) after power-on, and bump firmware to 0.2.43.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 12:15:08 +08:00
yuquanjun 3f1c1c74ba fix(ui): boot string tone to Bank1 program 25
Keep the last rhythm across soft power cycles, and bump firmware to 0.2.42.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 10:59:59 +08:00
yuquanjun be84c22479 fix(nvm): reset rhythm and string tone on power-up
Do not restore the last rhythm type or string timbre after a reboot or soft power cycle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-08 10:46:53 +08:00
yuquanjun 233dd0de69 chore(release): bump firmware to 0.2.41
Ship the new AutoBand Stop timeline-jump library as MCU 0.2.41.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 22:24:51 +08:00
yuquanjun 744eea534a fix(autoband): replace lib with Stop timeline jump fix
Drop in the 2026-10-06 AutoBand module_ab patch so Stop advances the
timeline and settles to_stop before the next Start, enabling immediate pick.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 22:18:07 +08:00
yuquanjun c007b4e40d feat(tone): ship the 1002 rhythm pack as firmware 0.2.40
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-02 13:06:35 +08:00
yuquanjun 459f73d8fe fix(ui): align transpose note letters on one baseline
Redraw the 16px ASCII glyphs so note names and the flat share one baseline.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 17:39:10 +08:00
yuquanjun 296a1b5420 feat(tone): ship the 0928 rhythm pack with Hall2 reverb and PEQ
Load the updated 1.bin and apply the sound-designer Hall2 and four-band EQ at startup. Version 0.2.39.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 17:53:06 +08:00
yuquanjun cd4f1cd902 chore(release): bump firmware to 0.2.38
Ship the restored flat amplifier EQ together with the 6.8V-to-10% battery gauge.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 17:16:58 +08:00
yuquanjun 49e30681cb fix(amp): drop the prototype EQ and restore the flat coefficients
The captured sample curves made the tone uneven. Rewrite the datasheet bypass values at boot because a software reset leaves the old coefficients in RAM.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 17:16:34 +08:00
yuquanjun 4983a424e5 fix(bat): map 6.8V to 10% and 8.4V to 100%
Stretch the 1.6V working range across the gauge so the low-battery shutdown no longer appears at 35%.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 17:15:41 +08:00
yuquanjun e0b91d17b4 chore(release): bump firmware to 0.2.37
Mark the boot mute change so the release package matches the speaker pop fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 10:11:48 +08:00
yuquanjun d7cd10eb08 fix(amp): mute the speaker before the 12V rail finishes rising
Hold master mute from shortly after the boost turns on through EQ setup, then let the chip fade in so boot does not pop.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 10:11:11 +08:00
yuquanjun 29507014f5 chore(release): bump firmware to 0.2.36
Tag the single amplifier init so the shipped version matches the string-tone fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 09:53:20 +08:00
yuquanjun df0fd0f6d0 fix(amp): init the amplifier once after the string clock is up
Bring up 12V and Dream together after the boot lights, then configure the amp a single time so the string tone stays intact and the unmute write is not lost.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 09:47:47 +08:00
yuquanjun 0e106e4da1 feat(amp): load prototype EQ when the amplifier starts
Write the captured AD85050 channel EQ into coefficient RAM before unmute so boot matches the prototype instead of the chip bypass defaults.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 08:13:45 +08:00
yuquanjun 58e8b3dbc7 fix(ui): step the battery percentage by 5 so it cannot cliff
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-27 18:15:03 +08:00
yuquanjun 3220602f89 fix(pwr): show the charge page, then blank it after 10s below 6.8V
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-27 18:15:03 +08:00
yuquanjun 8bf68e256d fix(pwr): shut down at 6.8V and light the charge page only above it
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 15:06:36 +08:00
yuquanjun cde5a80a3d feat(ui): match system-settings cards and type size to the hub
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 15:06:35 +08:00
yuquanjun 03062543e4 fix(ui): fill the charging battery to the live percentage
The charging glyph kept a fixed yellow bar. Clear that bar from the icon and paint the cavity from the current percent, in the same yellow as the bolt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 14:19:36 +08:00
yuquanjun 6f19486b16 fix(boot): show the burn-mode title in white
The source picture painted the glyphs in the page background color, so the screen stayed black. Draw those strokes in white when the external image has no light pixels.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 13:11:17 +08:00
yuquanjun fa5aa85bee fix(usb): enter the bootloader after USB update confirm without key 4
Keep the NVM sector out of the application image and arm a backup register that survives reset, so confirm stays in flash mode even when round key 4 is not held.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 12:42:29 +08:00
yuquanjun 968f8ae1ec feat(ui): draw system settings with MiSans bitmaps
Match the requirement screen using the settings-hub method, and keep the glyphs 1-bit so the image still fits in application flash.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 12:42:11 +08:00
yuquanjun e6de959366 fix(pwr): keep the pack above 6.8V and unmute the amp after 12V is up
Show the real battery percent, shut down at 6.8V even while Type-C is connected, and leave the charge screen dark so it does not drain the pack. Initialize the amplifier only after the 12V rail has settled.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-26 07:35:09 +08:00
yuquanjun 89a3e5f95f fix(pwr): reach mode select before boot LED show while charging
Bump firmware to 0.2.31. Skip the color LED sequence on USB power-on so a depleted pack can leave the logo screen and charge normally.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 21:04:51 +08:00
yuquanjun 1cc4d400ef fix(usb): show USB update and enter the loader after confirm
Bump firmware to 0.2.30. The 11px font now has the update glyphs, and the flashed boot image stays in USB programming when that mode is saved.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 20:33:26 +08:00
yuquanjun 4063bab4b5 fix(ui): align transpose and tempo controls with the 0924 mockup
Match the card box to the reference, put the value on the same center line as the arrow and plus-minus chips, and use MiSans for the 16px digits.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 11:16:20 +08:00
yuquanjun ea60c1fb62 feat(ui): apply 0924 layout with language and USB mode
Remove divider lines, add language and USB-update confirm pages, and store both in NVM so boot can enter IAP.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 07:39:32 +08:00
yuquanjun ad11f1128b chore: refresh git_user_fw_ver after auto-off activity fix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 21:33:08 +08:00
yuquanjun 80faaa4f9f fix(pwr): treat all play/UI inputs as auto-off activity
Centralize idle-timer reset on touch/volume/tap/transpose in UI task, and on pick, fretboard, side keys, round keys, and string NoteOn. Pause auto power-off countdown while accompaniment is playing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 20:48:18 +08:00
yuquanjun 91b33a4515 fix(boot): end startup LED on green; reset idle timer on mixer touch
Boot color sequence last frame was cyan; use mode-select green instead.
Mixer fader drag returned before ResetAutoPowerCount, so sliding volume could still hit auto power-off.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 20:43:11 +08:00
yuquanjun a3898dc9ae chore: refresh git_user_fw_ver for 0.2.29 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 20:13:46 +08:00
yuquanjun 84b6e4f15a chore: bump firmware to 0.2.29 and refresh release pack metadata
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 20:12:56 +08:00
yuquanjun 67a5fe5d60 fix(band): revert soft-stop; ignore round/side keys on mode select
Restore hard AutoBandTop1_Stop and drop eaten-start/followup tick-gate.
Keep API stubs for callers. Block TM1617 round keys and reinforce side-key/BLE gates while InModeFlag is false.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 20:08:27 +08:00
yuquanjun 18394d0b9b fix(pick): block accompaniment until a play mode is entered
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 18:42:32 +08:00
yuquanjun 3eba48ece1 fix(auto): stop stacking xpose -12 on III/IV chords
G-major III was collapsing B3 onto B2 after register -12 plus transpose -12.
Keep single register drop for III/IV; stack xpose only from V upward.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 16:32:18 +08:00
yuquanjun f6d9a557c8 chore: refresh git_user_fw_ver for 0.2.28 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 08:12:41 +08:00
yuquanjun f116e17529 chore: bump firmware to 0.2.28 and refresh release pack metadata
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 08:12:26 +08:00
yuquanjun 4bfe3ca008 fix(free): preserve expert chord/transpose across mode switch
NavBar no longer forces I after stop; remember context before leave and prefer saved fret chord on no-fret pick.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 08:05:50 +08:00
yuquanjun 3c01dc8c28 fix(free): remember last fret chord in expert and free modes
Shared last-chord memory; no-fret pick in free mode plays that chord.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 07:59:56 +08:00
yuquanjun 9ae3f5ec5e fix(free): keep expert fret chord (e.g. VI) for no-fret pick
Do not force I on free pick; reuse last expert KEY_ID / remembered chord after mode switch.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 07:53:57 +08:00
yuquanjun a322ed369c fix(ram): pack Global.c statics to fit SRAM (was 8 bytes short)
Shrink even-beat stop tick to 32-bit and fold univ/expert/free flags into single bytes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 07:47:15 +08:00
yuquanjun e7c9cd91f1 feat(free): allow pick start without fretboard using expert-stop key
Normal-mode pick with no fret held applies the last expert stop transpose, starts on I, and arms even-beat stop if idle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 07:43:46 +08:00
yuquanjun 5c30baef89 feat(universal): pick starts with preamble then loops section 1
Exit piece for AutoBand Preamble, then enter piece RunVar0 with loop so the intro is not repeated.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 06:57:01 +08:00
yuquanjun 3a09db55ee fix(led): start boot light show with LCD logo
Init TM1629 before POWER_ON and run the color sequence during the logo dwell instead of after mode select.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 06:46:43 +08:00
yuquanjun 15a647d8b4 feat(led): match prototype boot light show Blue-Cyan-Red-Cyan
On POWER_ON, fret-side LEDs follow the sample-unit '开机彩灯' sequence instead of jumping straight to solid green.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 06:39:00 +08:00
yuquanjun 3c102a918f feat(ui): use 0923 status-bar Bluetooth on/off icons
Replace the old 11x17 glyph and gray slash with dedicated on 13x20 and off 19x20 assets from the 0923 pack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 06:15:10 +08:00
yuquanjun 3b0f5479ba feat(amp): BLE SysEx R/W for AD85050 CH2 EQ RAM and I2C scan
Expose 0xA0-0xAE via 07 00/01 nibble-coded frames, add RAM helpers, and host scan/test scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 06:14:56 +08:00
yuquanjun c480e96a3f chore: refresh git_user_fw_ver for 0.2.22 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 08:39:49 +08:00
yuquanjun 96fd815ca9 fix(band): cut intro and endings in immediately
Normal and expert modes no longer wait for the next bar before preamble, interlude, outro, and ending. Universal mode ignores those keys. Bump firmware to 0.2.22.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 08:39:39 +08:00
yuquanjun 93e633472a fix(xpose): allow neck transpose in universal after pick hold-up
Universal TM1629 path dropped keys 0-21 before BP_Transpose. Route pick-hold neck keys to transpose, add RTT pick hold inject and a HIL script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 07:43:46 +08:00
yuquanjun 6d01d2cbb1 fix(mixer): ignore section keys and lock the grabbed fader
TM1617 keys injected fake touches at y=255 which slammed mixer sliders to 1. Lock the pressed fader until release and shrink overlapping hit boxes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 07:23:08 +08:00
yuquanjun cb4443f0e4 fix(led): use identity colors on universal progression lights
Loop_Light_Handle was hardcoding red for every measure; map L1-L7 to the same R/G/B/yellow/purple/cyan/white table as App guide LEDs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 07:08:48 +08:00
yuquanjun 04abc2e1be feat(ui): tap status-bar Bluetooth icon to toggle power
Hit area on mode/home/settings hub; off state uses gray icon + slash until a disabled asset is ready. Syncs system setting and NVM.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 17:42:04 +08:00
yuquanjun d00f570e2f fix(band): soft-stop on stop key so immediate pick can start
Stop key no longer calls AutoBandTop1_Stop (library eats the next Start). Soft mute + tick gate runs on MainTask; cold start skips redundant Stop when already clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 17:42:03 +08:00
yuquanjun 4b8e676033 chore: refresh git_user_fw_ver for 0.2.21 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 11:41:49 +08:00
yuquanjun 4716c87b5c release: bump firmware to 0.2.21
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 11:41:05 +08:00
yuquanjun ef41eb30fa fix(chord): song-mode LED no longer overwrites chord map (6m/Am -> AM7)
Problem2: in song mode UI shows 6m(Am) but MIDI played AM7
(E2 A2 E3 G#3 C#4 E4). Root cause: BL_Set_led wrote the LED frame's
chord code into chord_type_index_map of the group middle key
(LED_L6 -> key17), so a guidance frame carrying 0x02 (M7) turned the
Am key into AM7. Remapping on the chord page only helped until the
next LED frame.

- BL_Set_led: light LED only, drop all chord_type_index_map writes;
  chord quality is owned by map page 02 03/02 04 (BT_Chord_offset_map)
- handleReadRhythmMap / Return_Light_buff: fix type->protocol read-back
  encoding (m7->0x0A, M7->0x02, ad9->0x04, m7-5->0x0B, sus2->0x1F,
  sus4->0x1E), re-landing the 0917 verified fix
- BT_Chord_offset_map: accept dominant-7 doc code 0x0D (legacy 0x13 kept)
- tests: test_chord_map_fix.py (16/16 PASS on device),
  test_fret_positions.py, test_problem2_song_am.py (7/7 PASS:
  post-LED strum stays E2 A2 E3 A3 C4 E4)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 11:40:51 +08:00
yuquanjun 6d064cb53e chore: refresh git_user_fw_ver for 0.2.20 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:53:30 +08:00
yuquanjun cd32b4120b release: bump firmware to 0.2.20
Low-battery shutdown below 6.2V with tip screen and 10s soft power-off; UI0902 includes LOWBAT_TIP fullscreen asset.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:53:30 +08:00
yuquanjun 1b1b9b196d feat(power): low-battery tip screen and auto power-off below 6.2V
Stop all sound, show UI0902 LOWBAT_TIP fullscreen, then soft-off after 10s. Skip while charging; speed up ADC sampling near empty. Pack new tip bitmap into ExtFlash UI0902 map.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:53:13 +08:00
yuquanjun f740b6fba0 chore: refresh git_user_fw_ver for 0.2.19 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:23:26 +08:00
yuquanjun 878f3b41f1 release: bump firmware to 0.2.19
I/II+#F overall -12 transpose mapping; free-mode keeps all fret LEDs green (no LOOP_LIGHT). Carries 0.2.18 free even-beat stop, KEY_ID wind-down, universal outro, and expert local-song continue.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:23:09 +08:00
yuquanjun 0a2b4a1c92 chore: refresh git_user_fw_ver after xpose/LED fixes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:18:31 +08:00
yuquanjun a80c2216ea fix(free): keep all fret LEDs green during normal-mode playback
Disable LOOP_LIGHT rhythm chasing in free mode so LEDs stay solid green instead of moving with the beat.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:18:30 +08:00
yuquanjun feb084699c fix(reg): apply overall -12 for transpose >= #F on I/II too
Match 转调说明 table: C~F keep normal register; #F~B lower bass/chord by one octave for all fret degrees. III+ register fix unchanged. RTT pitch test covers I/II+#F.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 17:18:30 +08:00
yuquanjun ada2031e38 chore: refresh git_user_fw_ver for 0.2.18 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 15:53:50 +08:00
yuquanjun f135027647 release: bump firmware to 0.2.18
Free-mode even-beat release stop; keep fret KEY_ID during wind-down so register octave does not jump up before stop. Also includes universal outro all-green LED and expert local-song continue after section+fret.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 15:52:58 +08:00
yuquanjun 158c02d27b fix(free): stop accompaniment on next even beat after fret release
In normal mode, releasing the fretboard now finishes the current beat-pair (beat 1→end of 2, beat 3→end of 4) instead of cutting immediately.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 15:23:10 +08:00
yuquanjun 8fa5220b82 fix: universal outro all-green LED; expert local song keeps playing after section+fret
Keep fretboard LEDs all green during outro, and for expert local songs treat section-key + fret changes as continuous chord updates like rhythm mode (no mid-session Stop).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 15:13:53 +08:00
yuquanjun 7ebb7cf265 chore: refresh git_user_fw_ver for 0.2.17 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 07:20:31 +08:00
yuquanjun 56a5a253ca release: bump firmware version to 0.2.17
Include Type-C charging battery icon and BLE timbre/style UI sync fix already on develop; add RTT midi/string inject helpers for mic pitch calibration. Tone pack remains 0916_bank.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 07:18:44 +08:00
yuquanjun 6a1395a112 chore: refresh git_user_fw_ver after BLE sync fix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 19:07:23 +08:00
yuquanjun 287c3f6799 fix(ble): sync timbre/style UI via UI task to avoid hardfault
App writes for timbre/BPM/transpose/style were refreshing LCD and
reloading tone packs on the 768B BLE recv stack, causing overflow and
crashes. Route heavy work through MSG_ID_BLE_* into the UI task, and
notify App when the device changes rhythm style.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 19:07:23 +08:00
yuquanjun fd58637e9d feat(ui): show charging battery icon when Type-C is plugged
Replace the status-bar outline+fill with the 0918 lightning battery bitmap while charging, and fix Pre-Build git version script UTF-8 decoding on Chinese Windows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 17:58:33 +08:00
yuquanjun fb64ada557 chore: refresh git_user_fw_ver for 0.2.16 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:20:01 +08:00
yuquanjun e721c8e67c release: bump firmware version to 0.2.16
Stop accompaniment on mode/song switch; restore all-green LEDs when leaving universal; default pick/preamble to current-key I chord after soft boot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:18:52 +08:00
yuquanjun 3274c7d4fb fix(play): default pick/preamble to current-key I chord after boot
Apply Accomp_ApplyDefaultIChord before SyncStart on preamble, on soft power-on/mode enter/nav switch, and on pick fallback. Reset TM1629 key edge state so soft-off residual key_last cannot stick a prior fret.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:18:14 +08:00
yuquanjun 6c8a3a3d3b fix(play): stop accompaniment fully on mode and song switch
Use Stop_AutoBand (engine stop + all-channel AllNotesOff) when changing nav mode, reloading tone presets, switching songs/progressions, or returning to mode select. Also fix AllNotesOff to address all 16 MIDI channels.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:05:13 +08:00
yuquanjun bf1a539e44 fix(led): restore all-green fret lights when leaving universal mode
Nav-bar mode switches bypassed the legacy TAB path that called all-on green, so LOOP_LIGHT red LEDs stuck until reboot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 16:00:17 +08:00
yuquanjun 4f83ed52ec chore: refresh git_user_fw_ver for 0.2.15 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:03:16 +08:00
yuquanjun ca0244d0d5 release: bump firmware version to 0.2.15
Dual MIDI bank (accomp bank0 / string bank1) + toneRes 0916_bank; keeps local-song mid-play and power-on KEY_ID fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 14:00:01 +08:00
yuquanjun 30af9c75ed merge: feature_bank dual MIDI bank + toneRes 0916_bank into develop
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:59:17 +08:00
yuquanjun 7909a4f882 chore: refresh git_user_fw_ver for 0.2.14 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:12:49 +08:00
yuquanjun 8a8c7ec377 release: bump firmware version to 0.2.14
Local-song mid-play fret/pick no longer Stop+Start (avoids AutoBand silent fail); soft-off power-on resets KEY_ID/PressFlag/StartFlag so pick starts at degree I.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:11:09 +08:00
yuquanjun 064fabf249 fix(power): reset performance state (KEY_ID_1629/PressFlag/StartFlag) on power-on after soft-off
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:06:20 +08:00
yuquanjun dc5b7f4391 fix(expert): local song no Stop+Start while playing (fret change / re-pick)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:05:04 +08:00
yuquanjun 1201d9f9d0 fix(ui): further darken top/bottom separator lines
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 20:06:47 +08:00
yuquanjun dd55181937 fix(ui): darken top/bottom separator lines
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 19:43:03 +08:00
yuquanjun fe034e3ffe chore: sync git_user_fw_ver after 0.2.14 bank rebuild
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 18:39:27 +08:00
yuquanjun d4c35b8b90 chore: refresh git_user_fw_ver for 0.2.14 bank build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 18:38:00 +08:00
yuquanjun ba00940135 fix(midi): bank1 bass program is 33 not 34
Align Timbre_index with the Dream bank1 table.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 18:37:45 +08:00
yuquanjun d11d217b02 release: bump to 0.2.14 with toneRes 0916_bank
Repack ExtFlash from Doc/音色文件/0916_bank; BIN3 stays at 0xA7437 (2.bin length unchanged).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 18:32:13 +08:00
yuquanjun 11efccc19e feat(midi): select Dream bank0 for accomp, bank1 for string timbre
Match dual-bank tone ROM so accompaniment volume scaling no longer shares patches with the main string voice; bass program updated to 34.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 18:29:48 +08:00
yuquanjun 125eb00aa3 fix(power): prevent charge-boot long-press from auto power-off
Consume the same power-key hold used for soft-off charge boot before setting powon, and ignore stale POWOFF_CHARG after power-on so mode select stays on screen.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 15:10:34 +08:00
yuquanjun 65b0a84c4a chore: clean git_user_fw_ver id for 0.2.13
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 21:02:20 +08:00
yuquanjun 35d4cc28af chore: refresh git_user_fw_ver for 0.2.13 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 21:01:56 +08:00
yuquanjun 6fbeaa4881 release: bump firmware version to 0.2.13
Ship expert fretboard continue for local songs and tone resource pack 0915.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 21:01:30 +08:00
yuquanjun 5f41af27e7 fix(expert): 专业模式仅按指板即可续奏下一和弦,无需再拨片
App 连机专业模式下,起奏后按亮灯指板即可继续播放:
- 本地曲目(App 和弦曲目)/段落停止时:指板键投递 MSG_ID_BP_KEY 给主任务,
  走与「指板+拨片」完全相同的 Pick_Handle 起奏路径(扫描线程内直接
  Stop+Start 会无声,主任务上下文正常),Pick_Handle 内 Return_Light_buff
  通知 App 亮下一节
- 节奏库播放中:保持说明书行为,仅 Note_On 换和弦音 + Return_Light_buff
- 去掉 Last_Tm1926D_Key 去重:相邻两节可能是同一和弦键,松手再按必须能续奏
- 新增 Band_TrackPlayTick/Band_IsPlaying:8ms 周期跟踪 AutoBand PlayTick
  判定伴奏是否进行中
- 抽出 Expert_StartWithChord 公共起奏函数,拨片/指板共用
- tools/_test_expert_fret_restart.py: 指板续奏 RTT 回归测试

HIL 验证: pitch reg OK=41 FAIL=0; packs 9/9 PASS

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 19:13:10 +08:00
yuquanjun 2d9f234a7d chore: refresh git_user_fw_ver for 0.2.12 build
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 22:10:36 +08:00
yuquanjun 61caeb7407 release: bump firmware version to 0.2.12
Include autoclose 关闭 glyph fix and recent normal-pick / HIL / flash-tool work in the release tag.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 22:09:09 +08:00
yuquanjun eed22d4b8c fix(ui): add missing 闭 glyph for autoclose 关闭 label
Settings showed only 关 because GBK 闭 was absent from CHS font tables; append WenQuanYi bitmaps for all sizes and keep the patch helper.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 22:07:57 +08:00
yuquanjun c6be9fe88b chore: refresh git_user_fw_ver build id
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 21:49:37 +08:00
yuquanjun 8ac13ce6e9 tools: add MCU + ExtFlash ALL.res flash helper
Script flashes APP via J-Link then streams ALL.res over RTT flash all; include a minimal loadbin command file for APP-only updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 21:49:37 +08:00
yuquanjun cae4eb84a1 test: clearer BLE scan FAIL; RTT reset; longer UI ACK timeouts
Report missing Smart Guitar MIDI as an explicit FAIL instead of parse noise, reset target when opening RTT sessions, and give ui boot/charge more ACK time for LCD draws.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 21:49:37 +08:00
yuquanjun 4c6e2122ed fix: normal rhythm pick via piece; ACK UI before LCD; flash-busy power guard
Require fretboard in normal mode per manual; use SetPiecePlayMode for 1.bin. ACK ui boot/charge before full-screen draw, add RTT flash all and tone pick free, and skip soft-off while ExtFlash transfer is busy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 21:49:16 +08:00
yuquanjun d06e44bcb3 fix: keep power key alive on hang; refuse play when tone pack missing
TMR7 high-prio watchdog and fault-loop emergency cut/reset so soft-off still works if the main loop or AutoBand ISR dies; skip start when preset load fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 20:19:45 +08:00
yuquanjun f8aeb4fb7c release: 0.2.10 — tone pack 0914 (BIN3 after 2.bin), autoclose label 关闭
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 19:37:57 +08:00
yuquanjun 7fa2f5f1c4 release: bump firmware version to 0.2.9
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 16:27:04 +08:00
yuquanjun 6da7d4d627 test: stabilize HIL suites — inter-suite reset, async tm1617 inject, ACK-first
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 16:16:11 +08:00
yuquanjun eb1e5cbe84 fix: map Finger bass timbre to MIDI PC 33 per tone table
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:59:01 +08:00
yuquanjun 28970fddf0 chore: drop committed __pycache__ and ignore Python bytecode
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:05:49 +08:00
yuquanjun a495717883 test: unified K1 HIL harness + RTT inject hooks (tm1617/adc/bin2/sticky)
tools/k1_harness: one CLI over existing COM/BLE/RTT scripts covering
App SysEx 01-06, BLE smoke, TM1629/TM1617 key inject, 1/2/3.bin pack
checks with pick/outro regression, and UI nav (log status/TAP/DUMP).
Unified PASS/FAIL/SKIP/SENT markdown report to Doc/reports.

firmware hooks in app_log.c: 'tm1617 key N', 'adc key N on|off',
'tone bin2 [idx]', 'chord key N hold' (sticky inject survives physical
idle scan so normal-mode pick tests can hold a chord).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:05:17 +08:00
yuquanjun daee47a457 tools: add BLE/RTT/pick test and flash helper scripts
- ble_log_pull.py: pull field logs over BLE (midi/uart transport)
- rtt_flash_log_dump.py / log_decode.py: dump and decode RAM/flash logs via J-Link RTT
- _test_normal_pick.py: semi-automated normal-mode pick regression (RTT + physical pad)
- _ble_channel_matrix.py / _probe_ble_rtt.py / _usb_midi_sysex_probe.py: GATT/BLE/USB-MIDI diagnostics
- build_artist_kit.py: package artist tone kit
- flash_boot_app_v024.py: flash boot+app images

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 14:58:11 +08:00
yuquanjun f841d9e7b1 Normal mode: pick sounds held chord; release stops accompaniment.
Require left-hand pad held (PressFlag) before pick starts; skip the default I-chord fallback in normal mode. Release (key 0) stops AutoBand immediately instead of looping.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 12:55:22 +08:00
yuquanjun 713a768733 Disable fretboard chord/stop side-effects in universal mode.
Ignore TM1629 keys 0-21 in universal so pad no longer changes KEY_ID or arms OutTime_Stop; keep tap-tempo and stop. Clear stale KEY_ID/PressFlag when entering universal tab.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 12:36:39 +08:00
yuquanjun 24261942d8 Map universal section-4 to Postamble outro and share AutoBand_StartOutro with ADC.
Exit piece mode before Postamble so universal chord loops can switch into the style outro stage once 3.bin has PostambleMIDI.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 12:24:35 +08:00
yuquanjun 1cf6562236 Add bass/chord register mapping with RTT inject and bin1/3 probes.
Intercept AutoBand MIDI by channel (bass ch8, drum ch9), add chord-key RTT cmds, and ship scripts to verify 1.bin/3.bin pitch rules on device.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 21:21:11 +08:00
yuquanjun 91b270d856 Revert "Lower accompaniment by one octave for #IV and V-VII chords."
This reverts commit 439ccf439d.
2026-09-11 14:59:23 +08:00
yuquanjun 439ccf439d Lower accompaniment by one octave for #IV and V-VII chords.
AutoBand ignores input octave, so shift engine MIDI output by -12 for those chords (except drums) to keep the range from low #IV up to natural IV.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 22:08:09 +08:00
yuquanjun 2d62e1e41a Stop drawing status volume bar on mixer page to avoid erasing the back button.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 19:29:47 +08:00
yuquanjun 4aad989263 Reapply master volume at boot/mode-entry/play-start and sync volume bar on settings hub.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 18:58:24 +08:00
yuquanjun 295a2a6fa3 Fix song-name trailing ghost by clearing the full text row before redraw.
When switching from a longer title to a shorter one, the old gradient-only clear left uncovered glyph fragments outside the pill bounds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 10:46:11 +08:00
yuquanjun b65b762d92 Refresh git_user_fw_ver.h after 0.2.8 release rebuild.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 07:03:20 +08:00
yuquanjun 30c4ea9c0d Refresh git_user_fw_ver.h for 0.2.8 release commit.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 07:02:22 +08:00
yuquanjun 05ccf28a4b Release 0.2.8: harden BLE SysEx receive path for app stability.
Bump firmware version after BT recv stack/log fixes and pitch/chord bounds so Phoenix Atelier map/LED traffic no longer stack-smashes the MCU.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 07:02:22 +08:00
yuquanjun 59c11f3f93 Fix BT recv stack smash and harden pitch/chord SysEx paths.
Enlarge BT recv stack, move large handlers/log buffers off the stack, clamp key indexes, and yield in W25Q busy-wait so BLE protocol tests stay stable.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 06:51:32 +08:00
yuquanjun 24ffe87527 Refresh bottom nav with 0909 enlarged icons and aligned label art.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 20:24:39 +08:00
yuquanjun 5bb403cd11 Add artist self-serve tone pack tool for USB IAP updates of 1/2/3.bin.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 16:37:29 +08:00
yuquanjun a818065c2e Fix mixer knob outline at max volume by seating the knob on the track capsule ends.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 16:33:03 +08:00
yuquanjun c1b32c0351 Refresh git_user_fw_ver.h for 0.2.7 release commit.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 12:18:00 +08:00
yuquanjun bb6d9ae7f9 Release 0.2.7: refresh rhythm 1.bin pack with fixed BIN3 layout checks.
Update pack/publish to enforce 41KB song limit, verify 1/2/3.bin at fixed addresses, and emit .res aliases for the tone and ALL extflash images.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 12:17:42 +08:00
yuquanjun 99f7ed3e5a Pin BIN3 to fixed 0xA71AC and reject packs where 2.bin drift shifts it.
Variable 2.bin length previously moved 3.bin; firmware still read 0xA71AC and saw zeros. Pack now pads to the fixed slot and publish verifies DAB headers before shipping ALL.res.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 11:47:15 +08:00
yuquanjun cd21e4e45e Always enable loop on universal-mode pick so accompaniment can play.
Without SetLoopMode the piece path often produced no audible output when the chord pad was not held.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 11:35:14 +08:00
yuquanjun 92e5e32de3 Diagnose BIN3 LoadPreset failures and add flash bin3 tooling.
Log Flash magic on load failure, expose RTT flash bin3, and document the 0903 pack offset for the universal bank.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 11:32:40 +08:00
yuquanjun 015417dc3d Enlarge bottom nav touch zones to full-width 60x55 cells under the section buttons.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 11:01:40 +08:00
yuquanjun 6f2f7b6b75 Remove mode-select top stripe cover that left an extra line.
The ROW_BG full-width fill over the universal row top corners showed as a second separator under the status bar; source art no longer needs it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 08:00:06 +08:00
yuquanjun ba110565f1 Use chevron asset for factory-reset row instead of solid triangle.
Matches 0902-07: restore is a drill-in row with thin > (ICON_CHEVRON), not the prev/next filled triangle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 07:50:08 +08:00
yuquanjun ad0d990c55 Center indexed param/timbre labels as one block and nudge section digits.
Fixes the left-biased index+name layout, unifies index-name gap across rows, and shifts play-section numbers +2px per UI markup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 07:34:48 +08:00
yuquanjun f1f9520637 Fix settings BT/restore icons and soft-off BLE protocol plumbing.
Point system-settings rows at the correct Flash icons, keep Main/UI alive across soft-off, and expose git build id for 01 0C with matching BLE tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 07:03:52 +08:00
yuquanjun 57448b3da8 Harden BLE protocol test for Windows pairing and flaky notifies.
Default --unpair on Windows, probe/reconnect on first timeout, resync FrameParser on duplicate F0, and retry query once.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 22:14:18 +08:00
yuquanjun 0aedb45e6e Make BLE SysEx UID and fw-code MIDI-safe for BLE-MIDI.
Encode 01 07 UID as hex ASCII and use 01 0F (keep 01 FF alias) so high-bit bytes are not dropped as timestamps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 22:02:06 +08:00
yuquanjun 7b08f5e098 Start BLE UART4 App protocol receive on power-on.
TaskBTRecvThread previously started only after mode select, so GATT SysEx never reached the parser until then; verified BLE-MIDI 01 01 now replies with GATT notify.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 21:46:14 +08:00
yuquanjun f762348883 Merge branch 'main' into develop 2026-09-08 18:15:45 +08:00
yuquanjun 8febbd7742 Align BLE SysEx style/transpose replies with Doc protocol and add BLE test harness.
Drop ineffective Dream BT rename SysEx; fix 03 04 boot/list/total and 03 07 read length.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 18:05:04 +08:00
yuquanjun bd22246942 Use AT32 UID for unique PHON_ name and push it to Dream over SysEx.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 12:37:29 +08:00
yuquanjun 725ac495ba Merge main: bring Release 0.2.5 (2ss.bin tone pack) into develop.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 10:18:06 +08:00
yuquanjun 01bc2a592c Implement full BLE SysEx protocol handlers and app-sim test.
Wire missing 01/02/03/05 commands, fix chord-map reply and section/End dispatch, and add UART4 protocol regression script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 10:00:55 +08:00
yuquanjun a6259b5fca Release 0.2.4: package Boot with UI0902 flash-mode screen.
EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 05:51:58 +08:00
198 changed files with 19725 additions and 3656 deletions

4
.gitignore vendored
View File

@ -40,3 +40,7 @@ Desktop.ini
*.key
*.pem
credentials.json
# Python
__pycache__/
*.pyc

View File

@ -65,6 +65,18 @@ uint8_t percentage = 0;
//static uint32_t charge_step_tick = 0;
#define VBAT_MIN_RAW 2520
#define VBAT_MAX_RAW 3528
/* 包电压标定:ADC 6.0V→2520、8.4V→3528。显示电量只把 6.8V~8.4V 映到 10%~100%。关机阈值仍是 6.8V */
#define VBAT_PACK_V_MIN_MV 6000
#define VBAT_PACK_V_MAX_MV 8400
#define VBAT_SHUTDOWN_MV 6800
#define VBAT_SHUTDOWN_RAW \
(VBAT_MIN_RAW + (uint32_t)(VBAT_SHUTDOWN_MV - VBAT_PACK_V_MIN_MV) * \
(VBAT_MAX_RAW - VBAT_MIN_RAW) / (VBAT_PACK_V_MAX_MV - VBAT_PACK_V_MIN_MV))
/* 7.2V 以下加快采样,避免从 6.8V 掉到保护电压时还要等 30s */
#define VBAT_FAST_SAMPLE_RAW \
(VBAT_MIN_RAW + (uint32_t)(1200) * (VBAT_MAX_RAW - VBAT_MIN_RAW) / \
(VBAT_PACK_V_MAX_MV - VBAT_PACK_V_MIN_MV))
#define BAT_SAMPLE_INTERVAL_LOW_MS 2000
@ -72,10 +84,14 @@ uint8_t percentage = 0;
static void app_adc_string_process(uint8_t channel)
{
uint16_t adc_val = ADC_ReadChannel(ADC_CHANNEL_0) >> 5;
uint16_t adc_val;
uint8_t vel_out = 80;
if (System_LowBat_IsActive())
return;
adc_val = ADC_ReadChannel(ADC_CHANNEL_0) >> 5;
if (adc_val >= 127) {
/* δ<><CEB4><EFBFBD><EFBFBD> <20><> Note Off */
if (string_state[channel]) {
@ -92,6 +108,7 @@ static void app_adc_string_process(uint8_t channel)
}
if (!string_state[channel]) {
string_state[channel] = 1;
ResetAutoPowerCount(); /* 硅胶弦触发视为用户操作 */
SendNoteOnMidiEvent(get_note_by_channel(channel), vel_out);
}
}
@ -114,10 +131,16 @@ pick_state_t app_adc_get_pick_input(void)
static void app_adc_pick_process(void)
{
pick_state_t curstate = app_adc_get_pick_input();
uint32_t now = rt_tick_get();
pick_state_t curstate;
uint32_t now;
uint32_t hold_tick;
if (System_LowBat_IsActive())
return;
curstate = app_adc_get_pick_input();
now = rt_tick_get();
switch(pick_fsm)
{
case PICK_FSM_STATE_IDLE:
@ -263,7 +286,9 @@ static void app_adc_charge_process(void)
{
/* 通知 UI 熄灭充电页并关主电 */
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, 0, 0);
BSP_MainPowerEnable(0);
/* 发消息可能让出 CPU:关电前再确认仍未开机,避免切断开机主电 */
if (!powon)
BSP_MainPowerEnable(0);
}
}
}
@ -288,13 +313,18 @@ static void app_adc_hp_process(void)
static void app_adc_volume_map_level(uint16_t val)
{
/* 5 格状态栏音量条:0=静音,5=最大 */
if (val <= 5) level = 0;
else if (val <= 35) level = 1;
else if (val <= 65) level = 2;
else if (val <= 95) level = 3;
else if (val <= 115) level = 4;
else level = 5;
/* 8 格状态栏音量条:0=静音,8=最大(K1_UI_0923-05) */
if (val <= 5)
level = 0;
else
{
uint16_t lv = (uint16_t)((val * 8u + 64u) / 128u);
if (lv < 1u)
lv = 1u;
if (lv > 8u)
lv = 8u;
level = (uint8_t)lv;
}
}
void app_adc_sync_volume(uint16_t val)
@ -303,6 +333,14 @@ void app_adc_sync_volume(uint16_t val)
app_adc_volume_map_level(val);
}
/* 取当前主音量(复用扫描任务维护的最近一次有效值)。
* 模拟开关同一时刻只选中一路,离开扫描上下文直接重读 ADC 会串到
* 其它通道,故统一走 vol_last;未初始化(0xFFFF)时按静音兜底 */
uint8_t app_adc_get_volume(void)
{
return (vol_last > 127) ? 0 : (uint8_t)vol_last;
}
static void app_adc_volume_process(void)
{
uint16_t val = ADC_ReadChannel(ADC_CHANNEL_1)>>5;
@ -317,6 +355,18 @@ static void app_adc_volume_process(void)
static uint16_t s_vbat_raw = 0;
static uint8_t s_vbat_valid = 0;
static uint8_t s_charge_ui_allowed = 0;
static uint8_t s_pct_shown_valid = 0;
static uint8_t s_heavy_boot_msg = 0;
/* 高于 6.8V 才允许点亮关机充电页;未采样视为不允许 */
uint8_t app_adc_charge_ui_allowed(void)
{
return (s_vbat_valid && s_vbat_raw > (uint16_t)VBAT_SHUTDOWN_RAW) ? 1u : 0u;
}
static bat_state_t bat_state = BAT_IDLE;
static uint32_t bat_last_sample_tick = 0; /* 上次采样时刻 */
static uint32_t bat_state_tick = 0; /* 进当前状态的时刻 */
@ -345,6 +395,10 @@ void app_adc_init(void)
bat_poweron_done = 0;
bat_sample_cnt = 0;
bat_sample_tick = 0;
s_vbat_raw = 0;
s_vbat_valid = 0;
s_charge_ui_allowed = 0;
s_pct_shown_valid = 0;
}
/* 采样:读 ADC + 滑动平均 */
@ -358,31 +412,94 @@ static void app_adc_battery_do_sample(void)
bat_index = (bat_index + 1) % BAT_SAMPLE_COUNT;
}
/* 上报:映射成百分比,变化才发消息 */
/* 6.8V→10%,8.4V→100%。6.8~8.4V 的 1.6V 线性对应 90 个百分点。低于等于 6.8V 仍显示 10%。 */
static uint8_t bat_voltage_percent(uint16_t filtered)
{
uint32_t span;
uint32_t pct;
if (filtered <= (uint16_t)VBAT_SHUTDOWN_RAW)
return 10u;
if (filtered >= VBAT_MAX_RAW)
return 100u;
span = (uint32_t)VBAT_MAX_RAW - (uint32_t)VBAT_SHUTDOWN_RAW;
pct = 10u + (90u * ((uint32_t)filtered - (uint32_t)VBAT_SHUTDOWN_RAW)) / span;
if (pct > 100u)
pct = 100u;
return (uint8_t)pct;
}
/* 显示电量:四舍五入到 5%,之后每次最多升/降 5,避免一下掉一截。关机仍看原始电压。 */
static uint8_t bat_display_percent(uint8_t raw_pct)
{
uint8_t q = (uint8_t)((((uint16_t)raw_pct + 2u) / 5u) * 5u);
if (q > 100u)
q = 100u;
if (!s_pct_shown_valid)
{
s_pct_shown_valid = 1u;
return q;
}
if ((uint16_t)q + 5u < percentage)
return (uint8_t)(percentage - 5u);
if (q > (uint8_t)(percentage + 5u))
return (uint8_t)(percentage + 5u);
return q;
}
/* 上报:映射成百分比,变化才发消息;低于等于 6.8V 触发低电量关机(插着 Type-C 也执行) */
static void app_adc_battery_report(void)
{
uint16_t filtered = bat_sum / BAT_SAMPLE_COUNT;
uint8_t pct;
uint8_t allow;
uint8_t pct_changed;
uint8_t allow_changed;
if (filtered < VBAT_MIN_RAW)
pct = 0;
else if (filtered > VBAT_MAX_RAW)
pct = 100;
else
pct = 100 * (filtered - VBAT_MIN_RAW) / (VBAT_MAX_RAW - VBAT_MIN_RAW);
pct = (pct / 10) * 10;
pct = bat_voltage_percent(filtered);
if (pct != percentage) { /* 变化才上报 */
allow = (filtered > (uint16_t)VBAT_SHUTDOWN_RAW) ? 1u : 0u;
s_vbat_raw = filtered;
s_vbat_valid = 1u;
/* 高于 6.8V 才允许开机灯和音源板。电压未知或仍低时不发,避免保护态涓流被 Dream/12V 吃掉 */
if (!powon || allow == 0u)
{
s_heavy_boot_msg = 0;
if (powon && allow == 0u)
Audio_AbortIfNotReady();
}
else if (!Audio_IsReady() && !Audio_BringupStarted() && !s_heavy_boot_msg)
{
s_heavy_boot_msg = 1;
MainTask_Sendmsg(MSG_ID_HEAVY_BOOT, 0, 0, 0);
}
/* 开机使用中包电压低于等于 6.8V:提示页停留 10s 后关机。插着 Type-C 同样停负载 */
if (powon && !System_LowBat_IsActive() && allow == 0u)
{
LOG_W("BAT", "lowbat raw=%u thr=%u → tip+shutdown",
(unsigned)filtered, (unsigned)VBAT_SHUTDOWN_RAW);
MainTask_Sendmsg(MSG_ID_LOW_BAT_TIP, pct, filtered, 0);
}
pct = bat_display_percent(pct);
pct_changed = (pct != percentage) ? 1u : 0u;
allow_changed = (allow != s_charge_ui_allowed) ? 1u : 0u;
s_charge_ui_allowed = allow;
if (pct_changed)
percentage = pct;
if(usb_charging_state && !powon)
{
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, usb_charging_state, 0);
}
else
{
MainTask_Sendmsg(MSG_ID_BATTERY_VALUE, percentage, usb_charging_state, 0);
}
if (usb_charging_state && !powon)
{
/* 跨过 6.8V 时通知界面:高于则一直亮,否则 10s 后关屏 */
if (pct_changed || allow_changed)
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, usb_charging_state, 0);
}
else if (pct_changed)
{
MainTask_Sendmsg(MSG_ID_BATTERY_VALUE, percentage, usb_charging_state, 0);
}
}
@ -394,20 +511,31 @@ static void app_adc_battery_process(void)
switch (bat_state)
{
case BAT_IDLE:
/* 触发:开机后首采,或距上次 ≥30s */
/* 触发:开机后首采,或距上次 ≥30s(接近低电时改为 2s) */
if (/*powon && */!bat_poweron_done)
{
bat_poweron_done = 1;
bat_state = BAT_START;
}
else if (now - bat_last_sample_tick >= BAT_SAMPLE_INTERVAL_MS)
else
{
bat_state = BAT_START;
uint32_t interval = BAT_SAMPLE_INTERVAL_MS;
uint16_t last_avg = bat_sum / BAT_SAMPLE_COUNT;
/* 开机接近低电时加快采样。关机充电且尚未高于 6.8V 也加快,
* 但不停充电芯片,便于电压回升后尽快点亮充电页。 */
if (powon && last_avg != 0 && last_avg < (uint16_t)VBAT_FAST_SAMPLE_RAW)
interval = BAT_SAMPLE_INTERVAL_LOW_MS;
else if (!powon && usb_charging_state && s_vbat_valid &&
s_vbat_raw <= (uint16_t)VBAT_SHUTDOWN_RAW)
interval = BAT_SAMPLE_INTERVAL_LOW_MS;
if (now - bat_last_sample_tick >= interval)
bat_state = BAT_START;
}
break;
case BAT_START:
if (usb_charging_state) /* 充电中:先停充电,采真实电压 */
/* 关机充电不中断充电芯片。开机中才短暂停充,读负载下的真实电压 */
if (powon && usb_charging_state)
{
BSP_ChargerEnable(0);
bat_charge_paused = 1;

View File

@ -22,9 +22,13 @@ extern bool pick_hold_up;
extern bool usb_charging_state;
extern bool usb_charging_laststate;
extern uint8_t percentage;
/* 1 = 包电压已高于 6.8V,充电页保持亮。0 = 未采样或低于等于 6.8V,充电页亮 10s 后关屏。 */
uint8_t app_adc_charge_ui_allowed(void);
void app_adc_scan_all(void);
void app_adc_in1_scan_part(uint8_t channel);
bool app_adc_usb_is_plugged(void);
/* 开机/主动采样后同步 vol_last 与 level,避免扫描任务误触发或跳变 */
void app_adc_sync_volume(uint16_t val);
/* 取当前主音量(0~127),供 MasterVolume_Reapply 等重发场景使用 */
uint8_t app_adc_get_volume(void);
#endif

View File

@ -11,7 +11,7 @@ static uint32_t s_overflow;
static uint32_t s_boot_count;
static char s_ui_page[16] = "boot";
static char s_debug_level = 'D';
static char s_cmd_buf[48];
static char s_cmd_buf[64];
static uint8_t s_cmd_len;
/* RTT 二进制烧录:写到 W25Q128(ui0902 或本地曲目) */
@ -56,6 +56,8 @@ static void app_log_flash_flush_page(void)
/* 每页 ACK,避免主机打爆 RTT 下行缓冲 */
snprintf(ack, sizeof(ack), "FLASH_ACK %lu\n", (unsigned long)s_flash_addr);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, ack);
/* 整包 UI 超过自动关机窗口,刷写时保持开机 */
ResetAutoPowerCount();
}
static void app_log_flash_feed(const uint8_t *data, unsigned len)
@ -136,17 +138,36 @@ void app_log_set_ui_page(const char *name)
void app_log_write(char level, const char *cat, const char *fmt, ...)
{
char line[APP_LOG_SLOT_SIZE];
/* 静态行缓冲:TaskBTRecv 等小栈线程禁止再开 128B 局部数组 */
static char line[APP_LOG_SLOT_SIZE];
static rt_mutex_t s_log_mtx = RT_NULL;
va_list ap;
int n;
/* TMR6 1ms ISR 会经 AutoBand NoteOn 回调进来:禁止在中断里 take mutex / 打 RTT */
if (rt_interrupt_get_nest() != 0) {
return;
}
if (level == 'D' && s_debug_level != 'D') {
return;
}
if (s_log_mtx == RT_NULL) {
s_log_mtx = rt_mutex_create("applog", RT_IPC_FLAG_PRIO);
}
if (s_log_mtx != RT_NULL) {
if (rt_mutex_take(s_log_mtx, rt_tick_from_millisecond(20)) != RT_EOK) {
return;
}
}
n = snprintf(line, sizeof(line), "[%05u][%c][%-4s] ",
(unsigned)app_log_ms(), level, cat);
if (n < 0) {
if (s_log_mtx != RT_NULL) {
rt_mutex_release(s_log_mtx);
}
return;
}
if ((size_t)n >= sizeof(line)) {
@ -160,6 +181,10 @@ void app_log_write(char level, const char *cat, const char *fmt, ...)
app_log_slot_store(line);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "\n");
if (s_log_mtx != RT_NULL) {
rt_mutex_release(s_log_mtx);
}
}
static void app_log_dump_ram(void)
@ -274,14 +299,60 @@ uint8_t app_log_try_command(const char *cmd)
app_log_flash_start(size);
return 1U;
}
/* flash all <size> → W25Q128 @ 0x0(tone+UI 合成 ALL.res) */
if (strncmp(cmd, "flash all ", 10) == 0) {
uint32_t size = (uint32_t)strtoul(cmd + 10, NULL, 10);
app_log_flash_start_at(0U, size, "FLASH_ALL_GO", "FLASH_ALL_OK\n");
return 1U;
}
if (strncmp(cmd, "flash haitian ", 14) == 0) {
uint32_t size = (uint32_t)strtoul(cmd + 14, NULL, 10);
app_log_flash_start_at(FLASH_ADDR_SONG_HAITIAN, size,
"FLASH_HAITIAN_GO", "FLASH_HAITIAN_OK\n");
return 1U;
}
if (strncmp(cmd, "tone status", 11) == 0) {
uint8_t hdr[16];
if (strncmp(cmd, "flash bin3 ", 11) == 0) {
uint32_t size = (uint32_t)strtoul(cmd + 11, NULL, 10);
app_log_flash_start_at(EXTFLASH_BIN3_UNIVERSAL_ADDR, size,
"FLASH_BIN3_GO", "FLASH_BIN3_OK\n");
return 1U;
}
/* bp pick:经 MainTask 队列模拟真实拨片(与停止键串行,复现停后立即拨) */
if (strncmp(cmd, "bp pick", 7) == 0) {
MainTask_Sendmsg(MSG_ID_BP_KEY, 1 /*PICK_STATE_DOWN*/, 0, 0);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "BP_PICK_OK\n");
return 1U;
}
/* 拨片上推快移调门闩:1=进入 / 0=退出(琴颈键经 BP_Transpose) */
if (strncmp(cmd, "pick hold ", 10) == 0 && cmd[10] != '\0') {
uint8_t on = (cmd[10] == '1');
pick_hold_up = on ? 1 : 0;
{
char line[40];
snprintf(line, sizeof(line), "PICK_HOLD_OK on=%u\n", (unsigned)on);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
}
return 1U;
}
/* band dirty:强制下次冷启动先 Stop(验证 Stop→Start 紧挨是否必被吞) */
if (strncmp(cmd, "band dirty", 10) == 0) {
Band_ForceStopBeforeStart();
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "BAND_DIRTY_OK\n");
return 1U;
}
/* band state:停/起时序诊断 — StartFlag/PlayTick/是否在播 */
if (strncmp(cmd, "band state", 10) == 0) {
char line[96];
snprintf(line, sizeof(line),
"BAND_STATE start=%u playing=%u playtick=%lu ms=%lu\n",
(unsigned)StartFlag,
(unsigned)Band_IsPlaying(),
(unsigned long)AutoBandTop1_GetCurrentPlayTick(),
(unsigned long)app_log_ms());
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
if (strncmp(cmd, "tone status", 11) == 0) {uint8_t hdr[16];
uint8_t name[40];
uint8_t cur_hdr[16];
char *pname;
@ -320,6 +391,16 @@ uint8_t app_log_try_command(const char *cmd)
(unsigned long)(cur_hdr[12] | (cur_hdr[13] << 8) |
(cur_hdr[14] << 16) | (cur_hdr[15] << 24)));
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
{
uint8_t b3[16];
W25Q128_Read(b3, EXTFLASH_BIN3_UNIVERSAL_ADDR, 16);
snprintf(line, sizeof(line),
"TONE @BIN3 magic=%02X%02X%02X%02X cnt=%lu\n",
b3[0], b3[1], b3[2], b3[3],
(unsigned long)(b3[12] | (b3[13] << 8) |
(b3[14] << 16) | (b3[15] << 24)));
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
}
snprintf(line, sizeof(line),
"TONE @BIN2 magic=%02X%02X%02X%02X max=%lu cnt=%lu name=%.16s\n",
hdr[0], hdr[1], hdr[2], hdr[3],
@ -353,7 +434,7 @@ uint8_t app_log_try_command(const char *cmd)
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
ret = AutoBandTop1_LoadPresetItemFromFlash(0);
ret = App_Auto_LoadPresetFromFlash(0);
snprintf(line, sizeof(line),
"TONE_LOCAL ret=%d addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n",
ret, (unsigned long)ADDRESS,
@ -364,16 +445,326 @@ uint8_t app_log_try_command(const char *cmd)
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* tone bin1 [idx] → 1.bin 节奏(专业+节奏类型) */
if (strncmp(cmd, "tone bin1", 9) == 0) {
char line[160];
int ret;
unsigned idx = 0;
int count;
if (cmd[9] == ' ' && cmd[10] != '\0')
idx = (unsigned)strtoul(cmd + 10, NULL, 10);
mGuiData[GUI_TAB_INDEX].Current = 1; /* 专业 */
mGuiData[GUI_AUTOBAND_SW].Current = 0; /* 节奏类型→1.bin */
ParamGuiData[SONG_MODE_PARAM].Current = (uint8_t)idx;
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
count = AutoBandTop1_GetPresetItemCount();
if (count > 0 && (int)idx >= count)
idx = (unsigned)(count - 1);
ParamGuiData[SONG_MODE_PARAM].Current = (uint8_t)idx;
ret = App_Auto_LoadPresetFromFlash((int)idx);
snprintf(line, sizeof(line),
"TONE_BIN1 ret=%d idx=%u addr=0x%08lX map=BIN1@0x%08lX name=%s count=%d %s\n",
ret, idx, (unsigned long)ADDRESS,
(unsigned long)EXTFLASH_BIN1_RHYTHM_ADDR,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)",
AutoBandTop1_GetPresetItemCount(),
(ADDRESS == EXTFLASH_BIN1_RHYTHM_ADDR) ? "OK" : "MISMATCH");
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* tone bin2 [idx] → 2.bin 本地曲目(专业+本地曲目,带索引扫描) */
if (strncmp(cmd, "tone bin2", 9) == 0) {
char line[160];
int ret;
unsigned idx = 0;
int count;
if (cmd[9] == ' ' && cmd[10] != '\0')
idx = (unsigned)strtoul(cmd + 10, NULL, 10);
mGuiData[GUI_TAB_INDEX].Current = 1; /* 专业 */
mGuiData[GUI_AUTOBAND_SW].Current = 1; /* 本地曲目→2.bin */
ParamGuiData[EXPRESS_MODE_PARAM].Current = (uint8_t)idx;
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
count = AutoBandTop1_GetPresetItemCount();
if (count > 0 && (int)idx >= count)
idx = (unsigned)(count - 1);
ParamGuiData[EXPRESS_MODE_PARAM].Current = (uint8_t)idx;
ret = App_Auto_LoadPresetFromFlash((int)idx);
snprintf(line, sizeof(line),
"TONE_BIN2 ret=%d idx=%u addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n",
ret, idx, (unsigned long)ADDRESS,
(unsigned long)EXTFLASH_BIN2_SONG_HAITIAN_ADDR,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)",
AutoBandTop1_GetPresetItemCount(),
(ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR) ? "OK" : "MISMATCH");
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* tone bin3 [idx] → 3.bin 万能和弦走向 */
if (strncmp(cmd, "tone bin3", 9) == 0) {
char line[160];
int ret;
unsigned idx = 0;
int count;
if (cmd[9] == ' ' && cmd[10] != '\0')
idx = (unsigned)strtoul(cmd + 10, NULL, 10);
mGuiData[GUI_TAB_INDEX].Current = 0; /* 万能 */
mGuiData[GUI_AUTOBAND_SW].Current = 0;
ParamGuiData[ALL_MODE_PARAM].Current = (uint8_t)idx;
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
count = AutoBandTop1_GetPresetItemCount();
if (count > 0 && (int)idx >= count)
idx = (unsigned)(count - 1);
ParamGuiData[ALL_MODE_PARAM].Current = (uint8_t)idx;
ret = App_Auto_LoadPresetFromFlash((int)idx);
snprintf(line, sizeof(line),
"TONE_BIN3 ret=%d idx=%u addr=0x%08lX map=BIN3@0x%08lX name=%s count=%d %s\n",
ret, idx, (unsigned long)ADDRESS,
(unsigned long)EXTFLASH_BIN3_UNIVERSAL_ADDR,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)",
AutoBandTop1_GetPresetItemCount(),
(ADDRESS == EXTFLASH_BIN3_UNIVERSAL_ADDR) ? "OK" : "MISMATCH");
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* mode N:进入模式选择页的第 N 项(0 万能 / 1 专业 / 2 普通),供 RTT 起奏 */
if (strncmp(cmd, "mode ", 5) == 0 && cmd[5] != '\0') {
unsigned id = (unsigned)strtoul(cmd + 5, NULL, 10);
extern void Touch_Mode_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex);
if (id > 2u) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "MODE_BAD\n");
return 1U;
}
Touch_Mode_Select_Action(0, (uint8_t)id, 0);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "MODE_OK\n");
return 1U;
}
/* tone start:在当前已加载音色上拨片起奏(不改 TAB/库) */
if (strncmp(cmd, "tone start", 10) == 0) {
StartFlag = 0;
if (!(cmd[10] == ' ' && (cmd[11] == 'k' || cmd[11] == 'K')))
KEY_ID_1629 = 0;
Pick_Handle();
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TONE_START_DONE\n");
return 1U;
}
if (strncmp(cmd, "tone pick", 9) == 0) {
/* 模拟专业+本地曲目拨片(无和弦板) */
/* tone pick uni → 万能;tone pick free → 普通+节奏;默认专业+本地曲目 */
if (cmd[9] == ' ' && (cmd[10] == 'u' || cmd[10] == 'U')) {
mGuiData[GUI_TAB_INDEX].Current = 0;
mGuiData[GUI_AUTOBAND_SW].Current = 0;
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
(void)App_Auto_LoadPresetFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
KEY_ID_1629 = 0;
PressFlag = 0;
Pick_Handle();
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TONE_PICK_UNI_DONE\n");
return 1U;
}
if (cmd[9] == ' ' && (cmd[10] == 'f' || cmd[10] == 'F' || cmd[10] == 'n' || cmd[10] == 'N')) {
/* 普通模式 + 节奏类型(1.bin);模拟已按指板 */
unsigned idx = ParamGuiData[SONG_MODE_PARAM].Current;
mGuiData[GUI_TAB_INDEX].Current = 2;
mGuiData[GUI_AUTOBAND_SW].Current = 0;
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
(void)App_Auto_LoadPresetFromFlash((int)idx);
if (!(cmd[11] == ' ' && (cmd[12] == 'k' || cmd[12] == 'K')))
KEY_ID_1629 = 1;
PressFlag = 1;
Pick_Handle();
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TONE_PICK_FREE_DONE\n");
return 1U;
}
/* 模拟专业+本地曲目拨片;chord pick keep → 保留已注入的 KEY_ID */
mGuiData[GUI_TAB_INDEX].Current = 1;
mGuiData[GUI_AUTOBAND_SW].Current = 1;
KEY_ID_1629 = 0; /* 走默认和弦兜底 */
if (!(cmd[9] == ' ' && (cmd[10] == 'k' || cmd[10] == 'K'))) {
KEY_ID_1629 = 0; /* 默认走一级和弦兜底 */
}
StartFlag = 0;
Pick_Handle();
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TONE_PICK_DONE\n");
return 1U;
}
/* chord notes KEY [TYPE]:当前移调下 GetChordNotesByType 的和弦音 */
if (strncmp(cmd, "chord notes ", 12) == 0 && cmd[12] != '\0') {
char *endp = NULL;
unsigned key = (unsigned)strtoul(cmd + 12, &endp, 10);
unsigned type = 0;
int has_type = 0;
uint8_t buff[4] = {0, 0, 0, 0};
uint8_t n, i;
char line[64];
int pos;
if (endp != NULL && *endp == ' ') {
type = (unsigned)strtoul(endp + 1, NULL, 10);
has_type = 1;
}
if (key < 1U || key > 21U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "CHORD_NOTES_BAD\n");
return 1U;
}
if (!has_type)
type = chord_type_index_map[key].type;
n = GetChordNotesByType((uint8_t)key, (uint8_t)type, buff);
pos = snprintf(line, sizeof(line), "CHORD_NOTES_OK key=%u type=%u n=%u",
key, type, (unsigned)n);
for (i = 0; i < n && pos > 0 && pos < (int)sizeof(line) - 5; i++)
pos += snprintf(line + pos, sizeof(line) - (size_t)pos, " %u", (unsigned)buff[i]);
if (pos > 0 && pos < (int)sizeof(line) - 2) {
line[pos++] = '\n';
line[pos] = '\0';
}
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* 测试注入:chord key N(0释放 / 1~21和弦 / 22拍速 / 23停止) */
if (strncmp(cmd, "chord key ", 10) == 0 && cmd[10] != '\0') {
unsigned key = (unsigned)strtoul(cmd + 10, NULL, 10);
char line[48];
int hold = (strstr(cmd + 10, "hold") != NULL);
if (key > 23U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "CHORD_KEY_BAD\n");
return 1U;
}
if (hold)
app_tm1629_inject_hold((uint8_t)key);
else
app_tm1629_inject_key((uint8_t)key);
snprintf(line, sizeof(line), "CHORD_KEY_OK key=%u%s\n", key, hold ? " hold" : "");
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* 测试注入:tm1617 key N(0~3=MAIN_D/C/B/A 段落或导航键,4=释放)
* ACK 先于 Handle:0~3 会投递触摸消息,可能挤占 RTT 下行导致 ACK 丢失 */
if (strncmp(cmd, "tm1617 key ", 11) == 0 && cmd[11] != '\0') {
unsigned key = (unsigned)strtoul(cmd + 11, NULL, 10);
char line[48];
if (key > 4U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TM1617_KEY_BAD\n");
return 1U;
}
snprintf(line, sizeof(line), "TM1617_KEY_OK key=%u\n", key);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
app_tm1617_inject_key((uint8_t)key);
return 1U;
}
/* 测试注入:midi on <note> [vel] / midi off <note>
* 直通 Dream(与硅胶弦同一 SendNoteOn/Off 路径),供麦测音高校准 */
if (strncmp(cmd, "midi on ", 8) == 0 && cmd[8] != '\0') {
char *endp = NULL;
unsigned note = (unsigned)strtoul(cmd + 8, &endp, 10);
unsigned vel = 100;
char line[48];
if (endp == cmd + 8 || note > 127U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "MIDI_ON_BAD\n");
return 1U;
}
while (*endp == ' ')
endp++;
if (*endp != '\0') {
vel = (unsigned)strtoul(endp, NULL, 10);
if (vel > 127U)
vel = 127U;
}
SendNoteOnMidiEvent((uint8_t)note, (uint8_t)vel);
snprintf(line, sizeof(line), "MIDI_ON_OK note=%u vel=%u\n", note, vel);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
if (strncmp(cmd, "midi off ", 9) == 0 && cmd[9] != '\0') {
unsigned note = (unsigned)strtoul(cmd + 9, NULL, 10);
char line[40];
if (note > 127U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "MIDI_OFF_BAD\n");
return 1U;
}
SendNoteOffMidiEvent((uint8_t)note, 0);
snprintf(line, sizeof(line), "MIDI_OFF_OK note=%u\n", note);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* 测试注入:拨弦 string <1..6> [vel|off]
* 按当前 USE_MIDI 发与硅胶 N 弦相同的 NoteOn/Off(须先 chord key 装载) */
if (strncmp(cmd, "string ", 7) == 0 && cmd[7] != '\0') {
char *endp = NULL;
unsigned s = (unsigned)strtoul(cmd + 7, &endp, 10);
unsigned vel = 100;
uint8_t note = 0;
char line[56];
int do_off = 0;
if (endp == cmd + 7 || s < 1U || s > 6U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "STRING_BAD\n");
return 1U;
}
while (*endp == ' ')
endp++;
if (*endp != '\0') {
if (endp[0] == 'o' || endp[0] == 'O')
do_off = 1;
else {
vel = (unsigned)strtoul(endp, NULL, 10);
if (vel > 127U)
vel = 127U;
}
}
switch (s) {
case 1: note = USE_MIDI.Midi_1; break;
case 2: note = USE_MIDI.Midi_2; break;
case 3: note = USE_MIDI.Midi_3; break;
case 4: note = USE_MIDI.Midi_4; break;
case 5: note = USE_MIDI.Midi_5; break;
default: note = USE_MIDI.Midi_6; break;
}
if (do_off) {
SendNoteOffMidiEvent(note, 0);
snprintf(line, sizeof(line), "STRING_OFF_OK s=%u note=%u\n", s, (unsigned)note);
} else {
SendNoteOnMidiEvent(note, (uint8_t)vel);
snprintf(line, sizeof(line),
"STRING_OK s=%u note=%u vel=%u\n", s, (unsigned)note, vel);
}
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
/* 测试注入:adc key N on|off(0~3;1=独立尾奏键,与万能第4键同路径) */
if (strncmp(cmd, "adc key ", 8) == 0 && cmd[8] != '\0') {
unsigned idx = (unsigned)strtoul(cmd + 8, NULL, 10);
char line[48];
int on = (strstr(cmd + 8, "on") != NULL);
if (idx > 3U || (!on && strstr(cmd + 8, "off") == NULL)) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "ADC_KEY_BAD\n");
return 1U;
}
snprintf(line, sizeof(line), "ADC_KEY_OK idx=%u on=%d\n", idx, on);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
ADC_IN1_KEY_Handle((uint8_t)idx, on ? true : false);
return 1U;
}
/* 测试注入:chord xpose N(0~11,C=0) */
if (strncmp(cmd, "chord xpose ", 12) == 0 && cmd[12] != '\0') {
unsigned xp = (unsigned)strtoul(cmd + 12, NULL, 10);
char line[48];
if (xp > 11U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "CHORD_XPOSE_BAD\n");
return 1U;
}
mGuiData[GUI_TRANSPOSE].Current = (uint8_t)xp;
snprintf(line, sizeof(line), "CHORD_XPOSE_OK xp=%u\n", xp);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
LOG_I("REG", "xpose set %u", xp);
return 1U;
}
if (strncmp(cmd, "flash erase chip", 16) == 0) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_BEGIN\n");
LOG_I("FLASH", "W25Q128 chip erase start");
@ -382,25 +773,50 @@ uint8_t app_log_try_command(const char *cmd)
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_OK\n");
return 1U;
}
if (strncmp(cmd, "i2c scan", 8) == 0) {
uint8_t found[16];
uint8_t n;
uint8_t i;
char line[48];
n = wk_i2c1_scan(found, (uint8_t)sizeof(found));
for (i = 0U; i < n && i < (uint8_t)sizeof(found); i++) {
if (found[i] == 0x30U) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "I2C ACK 0x30 AD85050\n");
} else if (found[i] == 0x5AU) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "I2C ACK 0x5A AW816\n");
} else {
snprintf(line, sizeof(line), "I2C ACK 0x%02X\n", (unsigned)found[i]);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
}
}
snprintf(line, sizeof(line), "I2C_SCAN_END n=%u\n", (unsigned)n);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
if (strncmp(cmd, "ui boot", 7) == 0) {
/* 先 ACK:全屏 Logo 绘制很慢,避免 HIL/主机超时误判 */
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_BOOT_OK\n");
LCD_BLK_Set();
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
UI0902_BOOT_LOGO_ADDR);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_BOOT_OK\n");
return 1U;
}
if (strncmp(cmd, "ui charge", 9) == 0) {
uint8_t peek[4];
W25Q128_Read(peek, UI0902_CHARGE_SCREEN_ADDR, 4);
/* 先 ACK(peek 很快);再铺色/画图,避免卡在 LCD SPI 时主机无响应 */
if (peek[0] != 0xFF || peek[1] != 0xFF)
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_CHARGE_OK\n");
else
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_CHARGE_EMPTY\n");
LCD_BLK_Set();
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
W25Q128_Read(peek, UI0902_CHARGE_SCREEN_ADDR, 4);
if (peek[0] != 0xFF || peek[1] != 0xFF) {
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_CHARGE_SCREEN_W, UI0902_CHARGE_SCREEN_H,
UI0902_CHARGE_SCREEN_ADDR);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_CHARGE_OK\n");
} else {
Draw_Charging_Icon(120, 150, 2, 0x3D7F);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_CHARGE_EMPTY\n");
}
{
const char *s = "50";

View File

@ -12,7 +12,7 @@
#endif
#ifndef APP_LOG_RAM_SIZE
#define APP_LOG_RAM_SIZE (4U * 1024U)
#define APP_LOG_RAM_SIZE ((4U * 1024U) - 128U)
#endif
#ifndef APP_LOG_SLOT_SIZE

View File

@ -75,12 +75,24 @@ uint8_t app_tm1617_scan_key(void)
key = (uint8_t)TM1617_ScanFkey();
rt_mutex_release(TM1617_Mutex);
if (key != key_last)
if (key != key_last)
{
key_last = key;
LOG_I("KEY", "tm1617 key=%u", (unsigned)key);
TM1617_Handle(key);
/* ????????????????/?????? */
if (InModeFlag)
TM1617_Handle(key);
return key;
}
return KEY_NULL;
}
void app_tm1617_inject_key(uint8_t key)
{
if (key >= KEY_NULL)
key = KEY_NULL;
key_last = key;
LOG_I("KEY", "tm1617 inject key=%u", (unsigned)key);
/* ???????? RTT poll ?????? UI/?????????? */
MainTask_Sendmsg(MSG_ID_KEY_1617, key, 0, 0);
}

View File

@ -11,4 +11,8 @@ void app_tm1617_auto_loop(void);
uint8_t app_tm1617_scan_key(void);
/* RTT/test: bypass physical scan and inject a key event directly.
* key: 0=KEY_MAIN_D 1=KEY_MAIN_C 2=KEY_MAIN_B 3=KEY_MAIN_A 4+=release(KEY_NULL) */
void app_tm1617_inject_key(uint8_t key);
#endif /* APP_TM1617_H */

View File

@ -1,9 +1,10 @@
#include "includes.h"
static uint8_t key_last = KEY_NONE;
static uint8_t key_hold_sticky = 0; /* 1 = ????????????????(KEY_NONE)????? */
/* LED 期望颜色缓存:索引 = LedNum_TypeDef(0~7),COLOR_OTHER 表示灭 */
/* LED ???????????????? = LedNum_TypeDef??0~7????COLOR_OTHER ????? */
//static LedColor_TypeDef led_cache[8] = {
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER,
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER
@ -18,6 +19,12 @@ void app_tm1629_init(void)
rt_mutex_release(TM1629_Mutex);
}
void app_tm1629_reset_key_state(void)
{
key_last = KEY_NONE;
key_hold_sticky = 0;
}
uint8_t app_tm1629_Scan_Key(void)
{
uint8_t key = 0;
@ -27,7 +34,10 @@ uint8_t app_tm1629_Scan_Key(void)
rt_mutex_take(TM1629_Mutex, RT_WAITING_FOREVER);
key = TM1629D_GetKey();
rt_mutex_release(TM1629_Mutex);
if(key_hold_sticky && key == KEY_NONE)
return KEY_NONE; /* ??????§ľ??????????????????????? */
if(key != key_last)
{
key_last = key;
@ -38,6 +48,27 @@ uint8_t app_tm1629_Scan_Key(void)
return KEY_NONE;
}
void app_tm1629_inject_key(uint8_t key)
{
key_hold_sticky = 0;
key_last = key;
LOG_I("KEY", "inject key=%u", (unsigned)key);
TM1629_Handle(key);
}
void app_tm1629_inject_hold(uint8_t key)
{
if(key == KEY_NONE)
{
app_tm1629_inject_key(KEY_NONE);
return;
}
key_hold_sticky = 1;
key_last = key;
LOG_I("KEY", "inject hold key=%u", (unsigned)key);
TM1629_Handle(key);
}
static void app_tm1629_led_set(LedNum_TypeDef led, LedColor_TypeDef color, uint8_t on)
{

View File

@ -3,7 +3,10 @@
void app_tm1629_init(void);
void app_tm1629_reset_key_state(void); /* 软开机清扫描边沿,避免残留 key_last */
uint8_t app_tm1629_Scan_Key(void);
void app_tm1629_inject_key(uint8_t key); /* RTT/测试:绕过扫描直接注入 */
void app_tm1629_inject_hold(uint8_t key); /* RTT/测试:注入并保持(物理空扫不释放,chord key 0 解除) */
void app_tm1629_set_chord_led(uint8_t key_idx, LedColor_TypeDef color);
void app_tm1629_set_led(LedNum_TypeDef led, LedColor_TypeDef color);
void app_tm1629_all_off(void);

View File

@ -68,19 +68,25 @@ app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
}
if (!pressed) {
if (!long_press_fired && !click_sent &&
if (CurrUIProcress == UI_Mixer_Process &&
(touch_state == TOUCH_PRESS_WAIT_STABLE ||
touch_state == TOUCH_PRESS_STABLE ||
touch_state == TOUCH_SLIDING))
{
/* 调音台:抬起只解锁推子(按下已报过,不能再当点击) */
MainTask_Sendmsg(MSG_ID_TOUCH, 0, x, y);
}
else if (!long_press_fired && !click_sent &&
(touch_state == TOUCH_PRESS_WAIT_STABLE ||
touch_state == TOUCH_PRESS_STABLE ||
touch_state == TOUCH_SLIDING))
{
/* 导航页:抬起时发一次点击(坐标更稳,避免按下瞬间误触底栏) */
if (CurrUIProcress != UI_Mixer_Process) {
r.gesture = GESTURE_RELEASE;
r.x = down_x;
r.y = down_y;
LOG_TPI("release x=%u y=%u -> MSG", (unsigned)down_x, (unsigned)down_y);
MainTask_Sendmsg(MSG_ID_TOUCH, 1, down_x, down_y);
}
r.gesture = GESTURE_RELEASE;
r.x = down_x;
r.y = down_y;
LOG_TPI("release x=%u y=%u -> MSG", (unsigned)down_x, (unsigned)down_y);
MainTask_Sendmsg(MSG_ID_TOUCH, 1, down_x, down_y);
}
touch_state = TOUCH_IDLE;
down_x = down_y = 0;

View File

@ -321,6 +321,7 @@
<state>$PROJ_DIR$\..\..\device\LCD_ILI9341</state>
<state>$PROJ_DIR$\..\..\device\TM1617</state>
<state>$PROJ_DIR$\..\..\..\project\inc</state>
<state>$PROJ_DIR$\..\..\..\driver</state>
</option>
<option>
<name>CCStdIncCheck</name>

View File

@ -0,0 +1,27 @@
#ifndef BOOT_FLASH_MODE_INK_H
#define BOOT_FLASH_MODE_INK_H
#include <stdint.h>
/* 烧录模式.png 的白字笔画。原图把字画成页面底色,铺到黑底上就是黑屏。 */
#define BOOT_FLASH_INK_X 78
#define BOOT_FLASH_INK_Y 149
#define BOOT_FLASH_INK_W 86
#define BOOT_FLASH_INK_H 21
static const uint8_t boot_flash_ink[231] = {
0x1C,0x30,0x00,0x00,0x00,0x01,0x83,0x18,0x00,0x0E,0x40,0x1C,0x30,0x00,0xFF,0xFE,
0x01,0x83,0x18,0x00,0x0E,0xE0,0x1C,0x3F,0xF0,0xFF,0xFE,0x01,0xBF,0xFF,0x00,0x0E,
0x70,0x1D,0xFF,0xE0,0x00,0x06,0x01,0xBF,0xFF,0x00,0x0E,0x30,0xDF,0xFC,0x60,0x00,
0x06,0x0F,0xE3,0x18,0x3F,0xFF,0xF8,0x7E,0x1C,0xE0,0x7F,0xFE,0x0F,0xE0,0x00,0x3F,
0xFF,0xF8,0x7C,0x0F,0xC0,0x7F,0xFE,0x03,0x9F,0xFE,0x00,0x06,0x00,0x7C,0x0F,0x10,
0x00,0x06,0x03,0x9C,0x0E,0x00,0x06,0x00,0x7C,0xFF,0x31,0xFF,0xFF,0xC3,0x9F,0xFE,
0x00,0x06,0x00,0x7C,0xF3,0xF3,0xFF,0xFF,0xC7,0xDF,0xFE,0x3F,0xF6,0x00,0x1C,0x81,
0xE0,0x41,0xC1,0x07,0xF8,0x06,0x3F,0xF6,0x00,0x1C,0x00,0x40,0xE1,0xC3,0x0F,0xFF,
0xFE,0x03,0x86,0x00,0x1D,0xFF,0xF0,0x71,0xE7,0x8F,0x9F,0xFE,0x03,0x07,0x00,0x1F,
0xFF,0xF0,0x3B,0xFE,0x0D,0x80,0xC0,0x03,0x07,0x00,0x1E,0x33,0x00,0x1F,0xFC,0x09,
0xBF,0xFF,0x03,0x03,0x18,0x3F,0x33,0x10,0x7F,0xFC,0x01,0xBF,0xFF,0x03,0x03,0x18,
0x32,0x73,0x11,0xF9,0xCF,0x01,0x81,0xE0,0x07,0xFB,0x98,0x70,0x73,0x13,0xE1,0xC7,
0xC1,0x87,0xF8,0x3F,0xF9,0xD8,0x61,0xE3,0xF1,0x8F,0xC1,0xC1,0x9F,0x3F,0x3F,0x01,
0xF8,0x61,0xC1,0xF0,0x0F,0x80,0x01,0xBC,0x0F,0x00,0x00,0xF0,0x00,0x00,0x00,0x0F,
0x00,0x01,0xB0,0x02,0x00,0x00,0x20,
};
#endif

View File

@ -33,9 +33,12 @@
#include "usb_app.h"
#include "wk_system.h"
#include "includes.h"
#include <string.h>
#include "W25Q128.h"
#include "Drv_TM1617_RGB.h"
#include "UI0902_Res_Addr.h"
#include "drv_nvm.h"
#include "boot_flash_mode_ink.h"
/* private includes ----------------------------------------------------------*/
/* add user code begin private includes */
@ -88,6 +91,87 @@ static uint32_t PowerKeyCount = 0;
static uint8_t long_press_locked = 0; // ???????????????????
/* add user code end 0 */
static uint16_t Boot_NvmSum(const uint8_t *p, uint16_t len)
{
uint16_t sum = 0;
while (len > 0) {
sum = (uint16_t)(sum + *p++);
len--;
}
return sum;
}
static uint8_t Boot_NvmUsbUpdateRequested(void)
{
const NvmData_Type *nvm = (const NvmData_Type *)INNER_FLASH_SAVE_ADDRESS;
uint16_t s0 = Boot_NvmSum((const uint8_t *)&nvm->data, sizeof(NvmParam_Type));
if (s0 != nvm->sum[0] || (uint16_t)(~s0) != nvm->sum[1])
return 0;
if (nvm->data.nvm_version != NVM_VERSION)
return 0;
return (nvm->data.param.UsbMode == NVM_USB_UPDATE) ? 1 : 0;
}
/* 外部图把字画成了页面底色,铺出来是黑屏。字行中间有接近白色的像素才采用它。 */
static uint8_t Boot_FlashModeHasLight(void)
{
uint8_t row[172];
uint16_t i;
W25Q128_Read(row,
UI0902_FLASH_MODE_ADDR + (158ul * 240ul + 78ul) * 2ul,
(uint16_t)sizeof(row));
for (i = 0; i + 1u < sizeof(row); i += 2)
{
uint16_t c = (uint16_t)(((uint16_t)row[i] << 8) | row[i + 1]);
if (c >= 0xC618)
return 1;
}
return 0;
}
static void Boot_DrawFlashModeInk(void)
{
uint16_t row, col, stride;
LCD_FillByColor(0, 0, 240, 320, 0x0042);
stride = (uint16_t)((BOOT_FLASH_INK_W + 7u) >> 3);
for (row = 0; row < BOOT_FLASH_INK_H; row++)
{
const uint8_t *p = boot_flash_ink + (uint32_t)row * stride;
for (col = 0; col < BOOT_FLASH_INK_W; col++)
{
if (p[col >> 3] & (uint8_t)(0x80u >> (col & 7)))
LCD_DrawPoint((uint16_t)(BOOT_FLASH_INK_X + col),
(uint16_t)(BOOT_FLASH_INK_Y + row), WHITE);
}
}
}
static void Boot_NvmClearUsbUpdate(void)
{
NvmData_Type tmp;
uint16_t s0;
uint32_t i;
uint32_t words;
uint32_t buf[(sizeof(NvmData_Type) + 3) / 4];
memcpy(&tmp, (const void *)INNER_FLASH_SAVE_ADDRESS, sizeof(tmp));
if (tmp.data.param.UsbMode != NVM_USB_UPDATE)
return;
tmp.data.param.UsbMode = NVM_USB_MIDI;
s0 = Boot_NvmSum((const uint8_t *)&tmp.data, sizeof(NvmParam_Type));
tmp.sum[0] = s0;
tmp.sum[1] = (uint16_t)(~s0);
memset(buf, 0xFF, sizeof(buf));
memcpy(buf, &tmp, sizeof(tmp));
words = (sizeof(tmp) + 3) / 4;
flash_unlock();
flash_sector_erase(INNER_FLASH_SECTOR_ADDRESS);
for (i = 0; i < words; i++)
flash_word_program(INNER_FLASH_SAVE_ADDRESS + i * 4, buf[i]);
flash_lock();
}
flag_status BSP_GetPowerKey (void)
{
return gpio_input_data_bit_read(POWER_BUTTON_PORT, POWER_BUTTON_PIN);
@ -131,15 +215,16 @@ int main(void)
TM1617_GPIO_Init();
/* ????????????????????? App??
* ???????????? KEY_MAIN_A ????? USB ????????
* ??????????? KEY_NULL ???? App????λ??????????????? Boot ?????? */
/* 按住圆键 4(KEY_MAIN_A),或 App 确认了 USB 更新,都停在烧录。
* USB 更新有两处标志:Flash 里的 UsbMode,以及复位后仍在的备份寄存器。
* 没按键且两处都没有标志才跳进 App。 */
wk_delay_ms(50);
TM1617KeyValue = TM1617_ScanFkey();
if (TM1617KeyValue != KEY_MAIN_A)
if (TM1617KeyValue != KEY_MAIN_A &&
!Boot_NvmUsbUpdateRequested() &&
!drv_nvm_usb_boot_armed())
{
JumpToApplication();
/* ?? App ??????Ч????????????? */
}
/* init spi1 function. */
@ -150,12 +235,6 @@ int main(void)
/* init acc function. */
wk_acc_init();
/* init usbfs function. */
wk_usbfs_init();
/* init usb app function. */
wk_usb_app_init();
/* add user code begin 2 */
W25Q128_Init();
@ -163,23 +242,34 @@ int main(void)
wk_delay_ms(10);
/* USER CODE BEGIN 2 */
LCD_BLK_Set();
/* 烧录模式全屏图:UI0902_FLASH_MODE @ 外置 Flash;未烧资源时黑底兜底 */
/* <EFBFBD><EFBFBD><EFBFBD>???<3F><>?<3F><>UI0902_FLASH_MODE @ <20><><EFBFBD><EFBFBD> Flash<73><68>?<3F><><EFBFBD><EFBFBD>??<3F>??<3F><><EFBFBD> */
{
uint8_t peek[4];
W25Q128_Read(peek, UI0902_FLASH_MODE_ADDR, 4);
if (!(peek[0] == 0xFF && peek[1] == 0xFF && peek[2] == 0xFF && peek[3] == 0xFF))
if (!(peek[0] == 0xFF && peek[1] == 0xFF && peek[2] == 0xFF && peek[3] == 0xFF) &&
Boot_FlashModeHasLight())
{
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_FLASH_MODE_W, UI0902_FLASH_MODE_H,
UI0902_FLASH_MODE_ADDR);
}
else
{
LCD_FillByColor(0, 0, 240, 320, BLACK);
LCD_ShowChinese_AutoAlign(0, 240, 150,
(uint8_t *)"\xC9\xD5\xC2\xBC\xC4\xA3\xCA\xBD\x00",
LCD_ALIGN_CENTER, WHITE, BLACK, 0, 24);
Boot_DrawFlashModeInk();
}
}
/* 画面出来后再清标志,避免还没进烧录就被下一次复位跳回 App。
* 擦写与 Boot 同在 Flash Bank1,期间关掉中断。 */
if (Boot_NvmUsbUpdateRequested() || drv_nvm_usb_boot_armed())
{
__disable_irq();
if (Boot_NvmUsbUpdateRequested())
Boot_NvmClearUsbUpdate();
drv_nvm_clear_usb_boot_arm();
__enable_irq();
}
wk_usbfs_init();
wk_usb_app_init();
/* add user code end 2 */
@ -267,7 +357,7 @@ void JumpToApplication(void)
/* ???????????????? */
JumpAddress = *(__IO uint32_t*) (FIRMWARE_START_ADDR + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* ??????????ó????????? */
/* ??????????<EFBFBD><EFBFBD>????????? */
__set_MSP(*(__IO uint32_t*) FIRMWARE_START_ADDR);
SCB->VTOR = FIRMWARE_START_ADDR;
Jump_To_Application();

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,12 @@
#define MSG_ID_TAP_SPEED 25
#define MSG_ID_LOOP_LIGHT 26
#define MSG_ID_CHARG 27
#define MSG_ID_BLE_UI_REFRESH 28
#define MSG_ID_BLE_STYLE_SET 29
#define MSG_ID_LOW_BAT_TIP 30
#define MSG_ID_STOP_BAND 31 /* 停止键/收束:MainTask 串行硬停 */
#define MSG_ID_START_FOLLOWUP 32 /* 保留:软停补发已撤销,不再使用 */
#define MSG_ID_HEAVY_BOOT 33 /* 包电压高于 6.8V 后才点开机灯并初始化音源 */
#define GPIO_PIN_RESET false
#define GPIO_PIN_SET true
@ -136,11 +142,13 @@ typedef enum {
typedef enum {
GUI_VERSION = 0,
GUI_BLUETOOTH_SW = 1,
GUI_USB_MODE = 1,
GUI_AUTOCLOSE = 2,
GUI_RESTORE = 3,
GUI_BLUETOOTH_SW = 4, /* 不在设置列表绘制;状态栏 / NVM 同步 */
GUI_CANCEL,
GUI_CONFIRM,
GUI_LANGUAGE_PICK,
}GUI_SYSTEMSETTING_ID;
@ -166,8 +174,32 @@ extern uint8_t KEY_ID_1629;
extern bool powon;
void Power_Key_Scan(void);
void Power_Key_IsrTick(void);
void Power_Key_FaultLoop(void);
void Power_Key_WatchdogInit(void);
void Power_Key_ConsumePress(void);
void PowerOff_CutRails(void);
void AutoPowerOff_Scan(void);
void System_PowerOn(void);
/* 彩灯一开始就请求上电;主循环执行,不堵 UI。未就绪前禁止进模式起奏 */
void System_RequestAudioBringUp(void);
void System_AudioBringUp_Poll(void);
uint8_t Audio_IsReady(void);
uint8_t Audio_BringupStarted(void);
void Audio_AbortIfNotReady(void);
void Power_ChargeIdle_LogPoll(void);
/* 高于 6.8V:充电页背光保持;低于等于 6.8V:亮 10s 后关屏。拔电时复位倒计时。 */
void Power_ChargeBacklightSteady(void);
void Power_ChargeBacklightLowHold(void);
void Power_ChargeBacklightSessionReset(void);
/* 读回各路电源输出电平:main/dream/v12/bt 为 1=开;chg 为 1=充电使能(低有效) */
void Power_LogRails(const char *where);
void System_RequestPowerOff(void);
void System_PowerOff_Poll(void);
/* 低电量:停声+提示后 10s 关机(主循环 Poll) */
void System_LowBat_Arm(void);
void System_LowBat_Poll(void);
uint8_t System_LowBat_IsActive(void);
extern uint8_t Led;
extern bool PressFlag;
@ -176,6 +208,7 @@ extern volatile uint32_t ADDRESS;
extern uint8_t key_toggle[4];
extern bool StartFlag;
extern bool InModeFlag; /* 已进入演奏模式;模式选择页必须为 false */
extern int16_t MIC_VOL_MAP[11];
extern const uint8_t Version[3];
@ -196,7 +229,10 @@ extern GUI_SWITCH ParamGuiData[];
extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent);
void Stop_AutoBand();
/* 普通模式:松手后偶拍收束轮询(由 Read_Cur_Measure 调用) */
void FreeMode_PollEvenBeatStop(void);
/* 当前调一级大和弦(把位1 + maj);开机/进模式/前奏/拨片兜底共用 */
void Accomp_ApplyDefaultIChord(void);
static void ShowPowerOn();
@ -211,19 +247,44 @@ uint8_t GUI_Item_AjustValue(GUI_SWITCH * Group, int8_t Dir);
void GUI_Item_AjustLoopValue(GUI_SWITCH * Group, int8_t Dir);
void Send_volume(uint8_t vol);
void MasterVolume_Reapply(void);
/* 尾奏起奏:ADC 尾奏键与万能第4段落键共用 */
void AutoBand_StartOutro(void);
void ADC_IN1_KEY_Handle(uint8_t key,bool on);
void TM1617_Handle(uint8_t key);
void TM1629_Handle(uint8_t key);
void Pick_Handle();
void Loop_Light_Handle(uint8_t measure);
void Stop_AutoBand(void);
void Stop_AutoBand_Soft(void); /* 兼容:等同 Stop_AutoBand */
extern uint8_t Band_TickGate;
void Stop_AutoBand_Request(void); /* 投递 MSG_ID_STOP_BAND → 硬停 */
uint8_t Band_IsPlaying(void);
void Band_ForceStopBeforeStart(void); /* 兼容空操作 */
void Band_AbsorbEatenStart(void); /* 兼容空操作 */
void Band_MarkRealStop(void); /* 兼容空操作 */
uint8_t Band_TakeStartFollowup(void); /* 兼容:恒返回 0 */
void Band_BeginStartFollowup(void); /* 兼容空操作 */
void Band_EndStartFollowup(void); /* 兼容空操作 */
void BL_Set_led(uint8_t Led, uint8_t chord_type);
/* App 曲目引导灯有效时,拨片不要把琴颈打成全绿 */
void AppNeckLed_NoteGuide(void);
void AppNeckLed_ClearGuide(void);
uint8_t AppNeckLed_IsGuide(void);
uint8_t GetChordNotesByType(uint8_t MIDI_Index,uint8_t type,uint8_t *buff);
void FretChord_FillUseMidi(uint8_t key);
/* 源品位 III~VII:按 C 大调「和弦伴奏发音顺序」填 8 音(已含固定调半音)。I/II 返回 0 */
uint8_t AccompPattern_Fill(uint8_t key, uint8_t out[8]);
/* 伴奏已在播时仅更新和弦音,不 Restart(快转调) */
void Accomp_UpdatePlayingChord(void);
/* 切模式/停键前记住专业移调与最后指板和弦 */
void Accomp_RememberPlayContext(void);
/* 段落键等主动刷新伴奏活动,避免 PlayTick 短暂停滞被判为已停 */
void Band_NotifyPlayActivity(void);
void BT_Chord_offset_map(uint8_t pos_offset,uint8_t chord_offset);
void BT_Pitch_offset_map(uint8_t pos_offset,uint8_t pitch_offset);
void Read_Cur_Measure();

View File

@ -19,35 +19,696 @@ static uint8_t pStoreBuffer[PRESET_BUFFER_SIZE];
//static uint8_t* pStoreBuffer;
#define DEFAULT_TEMPO 100
/* ======== Bass/和弦分通道八度(无 AutoBand 源码时的输出侧映射) ========
* 代码通道(0 起,与 MIDI status 低 4 位一致):8=bass,9=鼓;其余=和弦。
* 日志打印同号(ch8=bass)。
* ① 指板 I/II(键1~6):原样;移调≥#F(6) 时表格「整体-12」(bass、和弦)。
* ② 指板 III/IV(键7~12):bass -12 地板 E1;和弦通道改走发音顺序(见下)。
* ③ 指板 V~VII(键13~21):bass 同②,移调≥#F 时 bass 再 -12。
* 和弦通道:源品位是 III~VII 时,不再做 -12,按 C 大调「和弦伴奏发音顺序」
* 逐音循环(固定调半音与六弦同一套映射)。I/II 形状仍走上面的八度规则。
* 对照 自动伴奏新更改和弦规则.xlsx「C大调 / 和弦伴奏发音顺序」 */
#define CHORD_REG_FIX_EN 1
#define BASS_CH 8 /* 日志 ch8 */
#define DRUM_CH 9 /* 日志 ch9 */
#define MIDI_E1 28
#define MIDI_E2 40
#define MIDI_GSHARP4 68
#define XPOSE_FS 6 /* C=0 时 #F=6 */
/* 映射策略指纹:变化时 CC123 清旧音,防挂音(不建大音符表) */
static uint8_t s_reg_fp = 0xFFu;
/* 每个指纹周期内 NoteOn 映射日志限额(和弦与 bass 分开,避免和弦占满看不到 bass) */
static uint8_t s_pitch_log_left = 0;
static uint8_t s_bass_log_left = 0;
static uint16_t s_ch_ever_mask = 0; /* 会话内各通道是否出现过 NoteOn */
#define PITCH_LOG_PER_FP 24
#define BASS_LOG_PER_FP 16
static void App_Auto_QueueAllNotesOffMelodic(void);
/* 和弦通道发音顺序:每通道自己的拍点,NoteOff 按进入音配对 */
static uint8_t s_seq[8];
static uint8_t s_seq_on;
static uint8_t s_seq_ready;
static uint8_t s_seq_key;
static uint8_t s_seq_type;
static uint8_t s_seq_xp;
static uint8_t s_seq_po;
#define SEQ_SLOTS 12
#define ARP_CH 12 /* 逐音琶音;垫音通道同一拍会叠多个音,不参与网格 */
static uint8_t s_seq_step[16];
static struct { uint8_t ch, in, out, used; } s_seq_slot[SEQ_SLOTS];
/* 第 5 拍会叠来一个多余触发。丢掉它,不占发音顺序,第 6 个音就落在下一拍。 */
static uint32_t s_grid_t0;
static uint16_t s_grid_unit;
static uint8_t s_grid_on;
static uint8_t s_seq_drop;
static uint16_t s_pending_hold_ms;
static uint8_t s_slot_hold4[SEQ_SLOTS];
static volatile uint16_t s_hold_report;
static volatile uint8_t s_hold_report_ready;
static volatile uint8_t s_hold_count;
/* tmr6_ticks 没有在中断里累加,用已经在走的 1ms 时基。 */
extern uint32_t wk_timebase_get(void);
static void App_Auto_GridReset(void)
{
s_grid_on = 0;
s_pending_hold_ms = 0;
}
static void App_Auto_QueueAllNotesOffMelodic(void);
/* 离开八音顺序时清掉步数和未配对的音,避免下一首接着上一首的相位。 */
static void App_Auto_SeqClear(void)
{
uint8_t i;
uint8_t was = s_seq_on;
s_seq_on = 0;
s_seq_ready = 0;
App_Auto_GridReset();
for (i = 0u; i < 16u; i++)
s_seq_step[i] = 0;
for (i = 0u; i < SEQ_SLOTS; i++)
{
s_seq_slot[i].used = 0;
s_slot_hold4[i] = 0;
}
if (was)
App_Auto_QueueAllNotesOffMelodic();
}
/* 八音表只对应第 1 首分解(1.bin 序号 0)。其他节奏保持曲库音高。 */
static int App_Auto_UseArpSeq(void)
{
if ((uint32_t)ADDRESS != EXTFLASH_BIN1_RHYTHM_ADDR)
return 0;
if (ParamGuiData[SONG_MODE_PARAM].Current != 0)
return 0;
return 1;
}
/* 当前速度的八分音符,单位 ms。速度范围 40..260。 */
static uint16_t App_Auto_EighthMs(void)
{
uint16_t bpm = (uint16_t)mGuiData[GUI_SPEED].Current;
if (bpm < 40u)
bpm = 40u;
return (uint16_t)(30000u / bpm);
}
static void App_Auto_QueueMidi(MidiFifoItem_t *m, uint16_t hold_ms)
{
if (hold_ms == 0u)
m->delayCounter = 0;
else
{
uint16_t due = (uint16_t)((uint16_t)wk_timebase_get() + hold_ms);
if (due == 0u)
due = 1u;
m->delayCounter = due;
s_hold_report = hold_ms;
if (s_hold_count < 255u)
s_hold_count++;
s_hold_report_ready = 1u;
}
mymidififo_InQueue(&m_MidiSendFifo, m);
}
void App_Auto_LogHeldNotes(void)
{
uint16_t ms;
uint8_t n;
if (!s_hold_report_ready)
return;
ms = s_hold_report;
n = s_hold_count;
s_hold_report_ready = 0;
LOG_I("SEQHOLD", "dly=%u n=%u unit=%u",
(unsigned)ms, (unsigned)n, (unsigned)s_grid_unit);
}
static void App_Auto_SeqRefresh(void)
{
uint8_t key = KEY_ID_1629;
uint8_t type = 0, po = 0;
uint8_t xp = (uint8_t)mGuiData[GUI_TRANSPOSE].Current;
uint8_t seq[8];
uint8_t on;
uint8_t i;
if (key >= 1u && key <= 21u)
{
type = chord_type_index_map[key].type;
po = chord_type_index_map[key].PitchOffset;
}
if (s_seq_ready && key == s_seq_key && type == s_seq_type && xp == s_seq_xp && po == s_seq_po)
return;
on = AccompPattern_Fill(key, seq);
s_seq_key = key;
s_seq_type = type;
s_seq_xp = xp;
s_seq_po = po;
s_seq_ready = 1u;
if (!on)
{
if (s_seq_on)
App_Auto_QueueAllNotesOffMelodic();
s_seq_on = 0;
App_Auto_GridReset();
for (i = 0u; i < SEQ_SLOTS; i++)
s_seq_slot[i].used = 0;
return;
}
if (s_seq_on)
{
uint8_t same = 1u;
for (i = 0u; i < 8u; i++)
{
if (s_seq[i] != seq[i])
same = 0u;
}
if (!same)
App_Auto_QueueAllNotesOffMelodic();
}
for (i = 0u; i < 8u; i++)
s_seq[i] = seq[i];
for (i = 0u; i < 16u; i++)
s_seq_step[i] = 0;
for (i = 0u; i < SEQ_SLOTS; i++)
{
s_seq_slot[i].used = 0;
s_slot_hold4[i] = 0;
}
App_Auto_GridReset();
s_seq_on = 1u;
}
/* 1 = 已用发音顺序处理(out 为最终音高) */
static int App_Auto_MapSeq(int channel, int key, int is_on, int *out)
{
int ch;
int i;
s_pending_hold_ms = 0;
s_seq_drop = 0;
if (!App_Auto_UseArpSeq())
{
if (s_seq_on)
App_Auto_SeqClear();
return 0;
}
App_Auto_SeqRefresh();
if (!s_seq_on || channel == BASS_CH || channel == DRUM_CH)
return 0;
ch = channel & 15;
if (!is_on)
{
for (i = SEQ_SLOTS - 1; i >= 0; i--)
{
if (s_seq_slot[i].used && s_seq_slot[i].ch == (uint8_t)ch
&& s_seq_slot[i].in == (uint8_t)key)
{
if (s_seq_slot[i].used == 2u)
s_seq_drop = 1u;
else
{
*out = s_seq_slot[i].out;
s_pending_hold_ms = (uint16_t)s_slot_hold4[i] * 4u;
}
s_seq_slot[i].used = 0;
s_slot_hold4[i] = 0;
return 1;
}
}
*out = key;
return 1;
}
{
uint8_t step;
uint32_t now;
uint8_t piled = 0;
if (ch == ARP_CH)
{
now = wk_timebase_get();
if (!s_grid_on || s_grid_unit == 0u
|| (now - s_grid_t0) >= (uint32_t)(s_grid_unit / 4u))
s_grid_unit = App_Auto_EighthMs();
piled = (s_grid_on
&& (now - s_grid_t0) < (uint32_t)(s_grid_unit / 4u)) ? 1u : 0u;
s_grid_t0 = now;
s_grid_on = 1u;
}
if (piled)
{
/* 同一拍的后一个触发不发声,也不占用下一个顺序音 */
s_seq_drop = 1u;
for (i = 0; i < SEQ_SLOTS; i++)
{
if (!s_seq_slot[i].used)
{
s_seq_slot[i].used = 2u;
s_seq_slot[i].ch = (uint8_t)ch;
s_seq_slot[i].in = (uint8_t)key;
s_seq_slot[i].out = 0;
return 1;
}
}
s_seq_slot[0].used = 2u;
s_seq_slot[0].ch = (uint8_t)ch;
s_seq_slot[0].in = (uint8_t)key;
s_seq_slot[0].out = 0;
return 1;
}
step = (uint8_t)(s_seq_step[ch] & 7u);
*out = s_seq[step];
s_seq_step[ch] = (uint8_t)((step + 1u) & 7u);
}
for (i = 0; i < SEQ_SLOTS; i++)
{
if (!s_seq_slot[i].used)
{
s_seq_slot[i].used = 1;
s_seq_slot[i].ch = (uint8_t)ch;
s_seq_slot[i].in = (uint8_t)key;
s_seq_slot[i].out = (uint8_t)(*out);
s_slot_hold4[i] = (uint8_t)(s_pending_hold_ms / 4u);
return 1;
}
}
s_seq_slot[0].used = 1;
s_seq_slot[0].ch = (uint8_t)ch;
s_seq_slot[0].in = (uint8_t)key;
s_seq_slot[0].out = (uint8_t)(*out);
s_slot_hold4[0] = (uint8_t)(s_pending_hold_ms / 4u);
return 1;
}
static int App_Auto_ClampMidi(int n)
{
if (n < 0) return 0;
if (n > 127) return 127;
return n;
}
static int App_Auto_ChordDegree(void)
{
if (KEY_ID_1629 < 1 || KEY_ID_1629 > 21)
return 0;
return (int)((KEY_ID_1629 - 1) / 3) + 1; /* 1=I .. 7=VII */
}
static int App_Auto_NeedRegisterFix(void)
{
/* 键 1~6 = I/II:不动;7~21 = III~VII */
return (KEY_ID_1629 >= 7 && KEY_ID_1629 <= 21) ? 1 : 0;
}
static int App_Auto_XposeExtra(void)
{
return (mGuiData[GUI_TRANSPOSE].Current >= XPOSE_FS) ? 1 : 0;
}
static uint8_t App_Auto_RegFingerprint(void)
{
/* bit0=need_fix, bit1=xpose_extra, bit2.. = 粗粒度级数 (key/3) */
uint8_t fp = 0;
if (App_Auto_NeedRegisterFix()) fp |= 0x01u;
if (App_Auto_XposeExtra()) fp |= 0x02u;
if (KEY_ID_1629 >= 1 && KEY_ID_1629 <= 21)
fp |= (uint8_t)(((KEY_ID_1629 - 1) / 3) << 2);
return fp;
}
static void App_Auto_QueueAllNotesOffMelodic(void)
{
MidiFifoItem_t m = {0};
int ch;
for (ch = 0; ch < 16; ch++)
{
if (ch == DRUM_CH) continue;
m.msg[0] = (uint8_t)(0xB0 | ch);
m.msg[1] = 123; /* All Notes Off */
m.msg[2] = 0;
m.msglen = 3;
App_Auto_QueueMidi(&m, 0);
}
}
/* 超出 #G4:在当前和弦内音(GetChordNotesByType,对照和弦表「和弦伴奏」列)中就近 */
static int App_Auto_NearestChordTone(int target)
{
uint8_t buff[4] = {0, 0, 0, 0};
uint8_t n;
uint8_t pcs[4];
int i, oct, best = -1, best_dist = 9999;
uint8_t type;
if (KEY_ID_1629 < 1 || KEY_ID_1629 > 21)
return App_Auto_ClampMidi(target);
type = chord_type_index_map[KEY_ID_1629].type;
n = GetChordNotesByType(KEY_ID_1629, type, buff);
if (n == 0)
return App_Auto_ClampMidi(target > MIDI_GSHARP4 ? MIDI_GSHARP4 : target);
for (i = 0; i < (int)n; i++)
pcs[i] = (uint8_t)(buff[i] % 12);
for (i = 0; i < (int)n; i++)
{
for (oct = 0; oct < 11; oct++)
{
int cand = (int)pcs[i] + oct * 12;
int dist;
if (cand < MIDI_E2 || cand > MIDI_GSHARP4)
continue;
dist = cand - target;
if (dist < 0) dist = -dist;
/* 并列:优先较低者(不超过上限) */
if (dist < best_dist || (dist == best_dist && (best < 0 || cand < best)))
{
best_dist = dist;
best = cand;
}
}
}
if (best < 0)
return MIDI_GSHARP4;
return best;
}
static int App_Auto_MapBassNote(int key, uint8_t *flags)
{
int out = key - 12;
uint8_t f = 0x01u; /* bit0: -12 applied */
while (out < MIDI_E1)
{
out += 12;
f |= 0x02u; /* bit1: floored up to E1 */
}
if (App_Auto_XposeExtra() && App_Auto_ChordDegree() >= 5)
{
out -= 12;
f |= 0x04u; /* bit2: xpose extra -12 */
while (out < MIDI_E1)
{
out += 12;
f |= 0x02u;
}
}
if (flags) *flags = f;
return App_Auto_ClampMidi(out);
}
static int App_Auto_MapChordNote(int key, uint8_t *flags)
{
int out = key - 12;
uint8_t f = 0x01u; /* bit0: -12 */
while (out < MIDI_E2)
{
out += 12;
f |= 0x08u; /* bit3: raised to E2 */
}
if (out > MIDI_GSHARP4)
{
out = App_Auto_NearestChordTone(out);
f |= 0x10u; /* bit4: nearest chord tone */
}
if (App_Auto_XposeExtra() && App_Auto_ChordDegree() >= 5)
{
out -= 12;
f |= 0x04u;
while (out < MIDI_E2)
{
out += 12;
f |= 0x08u;
}
if (out > MIDI_GSHARP4)
{
out = App_Auto_NearestChordTone(out);
f |= 0x10u;
}
}
if (flags) *flags = f;
return App_Auto_ClampMidi(out);
}
/* 转调说明:移调≥#F 时 I/II 也「整体-12」(bass、和弦);不含 III+ 把位音区修正 */
static int App_Auto_MapXposeOverall(int channel, int key, uint8_t *flags)
{
int out = key - 12;
uint8_t f = 0x04u; /* bit2: xpose overall -12 */
if (channel == BASS_CH)
{
while (out < MIDI_E1)
{
out += 12;
f |= 0x02u;
}
}
else
{
while (out < MIDI_E2)
{
out += 12;
f |= 0x08u;
}
if (out > MIDI_GSHARP4)
{
out = App_Auto_NearestChordTone(out);
f |= 0x10u;
}
}
if (flags) *flags = f;
return App_Auto_ClampMidi(out);
}
static int App_Auto_MapNote(int channel, int key, uint8_t *flags, int is_on)
{
int out = key;
if (flags) *flags = 0;
#if CHORD_REG_FIX_EN
if (channel == DRUM_CH || key < 0 || key > 127)
return key;
if (App_Auto_MapSeq(channel, key, is_on, &out))
{
if (flags) *flags = 0x20u; /* 发音顺序 */
return out;
}
if (App_Auto_NeedRegisterFix())
{
/* III+:把位音区修正;V~VII 且 ≥#F 时 Map* 内再叠转调 -12 */
if (channel == BASS_CH)
out = App_Auto_MapBassNote(key, flags);
else
out = App_Auto_MapChordNote(key, flags);
}
else if (App_Auto_XposeExtra())
{
/* I/II + 移调≥#F:表格「整体-12 (bass、和弦)」 */
out = App_Auto_MapXposeOverall(channel, key, flags);
}
else
{
/* I/II + 移调 C~F:正常和弦逻辑,不改八度 */
return key;
}
#else
(void)channel;
(void)is_on;
#endif
return out;
}
static const char *App_Auto_RoleName(int channel)
{
if (channel == DRUM_CH) return "drum";
if (channel == BASS_CH) return "bass";
return "chord";
}
static void App_Auto_LogPitch(int channel, int key, int out, uint8_t flags, int is_on)
{
const char *role;
int deg;
int fix;
int xf;
int pass;
if (channel == DRUM_CH)
return;
if (channel == BASS_CH)
{
if (s_bass_log_left == 0)
return;
}
else if (s_pitch_log_left == 0)
{
return;
}
role = App_Auto_RoleName(channel);
deg = App_Auto_ChordDegree();
fix = App_Auto_NeedRegisterFix();
xf = App_Auto_XposeExtra();
/* PASS = 未做任何八度映射(I/II 且移调 C~F) */
pass = ((!fix && !xf) || channel == DRUM_CH) ? 1 : 0;
LOG_I("PITCH", "%s ch%u(%s) %d->%d d=%d deg=%d chord=%u xp=%u xf=%d fl=0x%02X %s%s%s%s",
is_on ? "on" : "off",
(unsigned)channel, role, /* 0 基,与 BASS_CH=8 一致 */
key, out, out - key,
deg, (unsigned)KEY_ID_1629,
(unsigned)mGuiData[GUI_TRANSPOSE].Current, xf,
(unsigned)flags,
pass ? "PASS " : "",
(flags & 0x10u) ? "NEAR " : "",
(flags & 0x02u) ? "E1UP " : "",
(flags & 0x08u) ? "E2UP " : "");
if (channel == BASS_CH)
{
if (s_bass_log_left > 0)
s_bass_log_left--;
}
else if (s_pitch_log_left > 0)
{
s_pitch_log_left--;
}
}
/* NoteOn 路径:策略变化时清旧音;返回映射后音高 */
static int App_Auto_MapNoteOn(int channel, int key)
{
#if CHORD_REG_FIX_EN
uint8_t fp = App_Auto_RegFingerprint();
uint8_t flags = 0;
int out;
if (fp != s_reg_fp)
{
if (s_reg_fp != 0xFFu)
{
LOG_I("REG", "fp %u->%u chord=%u deg=%d xp=%u xf=%d",
(unsigned)s_reg_fp, (unsigned)fp,
(unsigned)KEY_ID_1629,
App_Auto_ChordDegree(),
(unsigned)mGuiData[GUI_TRANSPOSE].Current,
App_Auto_XposeExtra());
App_Auto_QueueAllNotesOffMelodic();
}
else
{
LOG_I("REG", "fp init %u chord=%u deg=%d xp=%u",
(unsigned)fp, (unsigned)KEY_ID_1629,
App_Auto_ChordDegree(),
(unsigned)mGuiData[GUI_TRANSPOSE].Current);
}
s_reg_fp = fp;
s_pitch_log_left = PITCH_LOG_PER_FP;
s_bass_log_left = BASS_LOG_PER_FP;
s_ch_ever_mask = 0; /* 新策略周期重新报到通道 */
}
out = App_Auto_MapNote(channel, key, &flags, 1);
if (s_seq_drop)
return out;
if (channel >= 0 && channel < 16)
{
uint16_t bit = (uint16_t)(1u << channel);
if ((s_ch_ever_mask & bit) == 0u)
{
s_ch_ever_mask |= bit;
LOG_I("REG", "ch-seen ch%u role=%s key=%d",
(unsigned)channel, App_Auto_RoleName(channel), key);
}
}
App_Auto_LogPitch(channel, key, out, flags, 1);
return out;
#else
(void)channel;
return key;
#endif
}
static void Func_CallBack_ProgramChange(int channel, int program)
{
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0xc0 | channel;
midimsg.msg[1] = program;
MidiFifoItem_t midimsg = {0};
uint8_t ch = (uint8_t)(channel & 0x0F);
uint8_t bank = MIDI_BANK_ACCOMP;
/* 通道 0 是硅胶弦。节奏预设常在这里放钢琴(Program 0),会盖掉弦音色。 */
if (ch == 0)
{
uint8_t slot = mGuiData[GUI_TIMBRE_SELECT].Current;
if (slot > 4u)
slot = 0;
bank = MIDI_BANK_STRING;
program = Timbre_index[slot];
}
LOG_I("REG", "pc ch%u prog=%d", (unsigned)channel, program);
/* 伴奏走 Bank0;弦音色走 Bank1。先 Bank Select 再 PC */
midimsg.msg[0] = 0xb0 | ch;
midimsg.msg[1] = 0x00; /* CC0 Bank MSB */
midimsg.msg[2] = bank;
midimsg.msglen = 3;
App_Auto_QueueMidi(&midimsg, 0);
midimsg.msg[1] = 0x20; /* CC32 Bank LSB */
midimsg.msg[2] = 0;
App_Auto_QueueMidi(&midimsg, 0);
midimsg.msg[0] = 0xc0 | ch;
midimsg.msg[1] = (uint8_t)program;
midimsg.msg[2] = 0;
midimsg.msglen = 2;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
App_Auto_QueueMidi(&midimsg, 0);
}
static void Func_CallBack_NoteOff(int channel,int key)
{
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0x80 | channel;
midimsg.msg[1] = key;
MidiFifoItem_t midimsg = {0};
uint8_t flags = 0;
int out_key = App_Auto_MapNote(channel, key, &flags, 0);
if (s_seq_drop)
return;
midimsg.msg[0] = 0x80 | (channel & 0x0F);
midimsg.msg[1] = (uint8_t)out_key;
midimsg.msg[2] = 0;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
App_Auto_QueueMidi(&midimsg, s_pending_hold_ms);
}
static void Func_CallBack_NoteOn(int channel,int key,int vel)
{
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0x90 | channel;
midimsg.msg[1] = key;
midimsg.msg[2] = vel;
MidiFifoItem_t midimsg = {0};
int out_key;
if (vel == 0)
{
uint8_t flags = 0;
out_key = App_Auto_MapNote(channel, key, &flags, 0); /* 视同 NoteOff */
}
else
out_key = App_Auto_MapNoteOn(channel, key);
if (s_seq_drop)
return;
midimsg.msg[0] = 0x90 | (channel & 0x0F);
midimsg.msg[1] = (uint8_t)out_key;
midimsg.msg[2] = (uint8_t)vel;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
App_Auto_QueueMidi(&midimsg, s_pending_hold_ms);
}
@ -57,23 +718,23 @@ static void Func_CallBack_CC(int channel,int cc,int value)
{
return;
}
MidiFifoItem_t midimsg;
MidiFifoItem_t midimsg = {0};
midimsg.msg[0] = 0xb0 | channel;
midimsg.msg[1] = cc;
midimsg.msg[2] = value;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
App_Auto_QueueMidi(&midimsg, 0);
}
static void Func_CallBack_PitchWheel(int channel,int cc,int value)
{
MidiFifoItem_t midimsg;
MidiFifoItem_t midimsg = {0};
midimsg.msg[0] = 0xe0 | channel;
midimsg.msg[1] = cc;
midimsg.msg[2] = value;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
App_Auto_QueueMidi(&midimsg, 0);
}
/* Flash Map 0903:对照 ExtFlash_Tone_Addr.h / Doc/.../FLASH_MAP.txt */
@ -96,6 +757,32 @@ static const char *ToneFlashMapBank(uint32_t abs)
static uint32_t s_flash_rd_last_base = 0xFFFFFFFFu;
static uint16_t s_flash_rd_log_cnt = 0;
/* 最近一次 LoadPreset 是否成功;失败时禁止拨片起奏(防空库 + TMR6 ISR 崩) */
static volatile uint8_t s_preset_ready = 0;
int App_Auto_LoadPresetFromFlash(int presetIndex)
{
App_Auto_SeqClear();
int ret = AutoBandTop1_LoadPresetItemFromFlash(presetIndex);
if (ret == 0)
{
const char *name = AutoBandTop1_GetPresetName();
int count = AutoBandTop1_GetPresetItemCount();
s_preset_ready = (count > 0 && name != NULL && name[0] != '\0') ? 1u : 0u;
}
else
{
s_preset_ready = 0u;
AutoBandTop1_Stop();
StartFlag = 0;
}
return ret;
}
uint8_t App_Auto_IsPresetReady(void)
{
return s_preset_ready;
}
static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput)
{
@ -135,6 +822,9 @@ static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput)
//
void App_Auto_Init(void)
{
LOG_I("REG", "ch map bass=%d drum=%d fix=%d E1=%d E2=%d Gs4=%d",
BASS_CH, DRUM_CH, CHORD_REG_FIX_EN, MIDI_E1, MIDI_E2, MIDI_GSHARP4);
LOG_I("REG", "PITCH log: chN(role) in->out d=delta deg=I..VII xp=xpose xf=#Fextra fl=flags");
AutoBandTop1_SetPresetStoreBuffer(pStoreBuffer,PRESET_BUFFER_SIZE);
AutoBandTop1_Init();
AutoBandTop1_RegisterCallBack_NoteOn(Func_CallBack_NoteOn);
@ -145,11 +835,15 @@ void App_Auto_Init(void)
AutoBandTop1_RegisterReadFlashCallback(Func_CallBack_ReadFlash);
m_presetCount = AutoBandTop1_GetPresetItemCount();
int ret = AutoBandTop1_LoadPresetItemFromFlash(0);
int ret = App_Auto_LoadPresetFromFlash(0);
if (ret != 0)
{
LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X map=%s",
ret, (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS));
uint8_t hdr[16];
W25Q128_Read(hdr, (uint32_t)ADDRESS, 16);
LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X map=%s magic=%02X%02X%02X%02X cnt=%lu",
ret, (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS),
hdr[0], hdr[1], hdr[2], hdr[3],
(unsigned long)(hdr[12] | (hdr[13] << 8) | (hdr[14] << 16) | (hdr[15] << 24)));
}
else
{

View File

@ -8,9 +8,14 @@
#ifndef APP_AUTO_H_
#define APP_AUTO_H_
#include "mymidififo1.h"
#include <stdint.h>
extern void App_Auto_Init(void);
/* 统一加载入口:记录成功/失败,失败时 Stop,避免空库起奏进 ISR 崩溃 */
int App_Auto_LoadPresetFromFlash(int presetIndex);
uint8_t App_Auto_IsPresetReady(void);
extern MidiFifoSeq_t m_MidiSendFifo;
#endif /* APP_AUTO_H_ */

Binary file not shown.

View File

@ -2,10 +2,16 @@
void UI_ExpertMode_Init(void)
{
uint8_t keep = (UI_IsSettingsPage() && mGuiData[GUI_TAB_INDEX].Current == 1) ? 1u : 0u;
mGuiData[GUI_TAB_INDEX].Current = 1;
mGuiData[GUI_TAB_LAST_INDEX].Current = mGuiData[GUI_TAB_INDEX].Current;
//mGuiData[GUI_AUTOBAND_SW].Current = 1;
UI_ReloadTonePreset(); /* 必须在 TAB=专业 之后换库,否则仍是万能 3.bin */
if (!keep)
UI_ReloadTonePreset(); /* 必须在 TAB=专业 之后换库,否则仍是万能 3.bin */
/* 未连 App 弹唱:专业把位灯一直全绿。从设置返回同一模式不改灯。 */
if (!keep && !AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
if (CurrUIProcress == UI_SongMode_Process)
Show_home_UI_Diff();
else
@ -33,6 +39,10 @@ void UI_ExpertMode_Process(DisplayTaskMessage_Type msg)
case MSG_ID_BATTERY_VALUE:
Draw_Status_Battery_Icon(percentage);
break;
case MSG_ID_CHARG:
Show_Battery_Icon(msg.ID);
break;
case MSG_ID_TAP_SPEED:
// uint8_t last_value = mGuiData[GUI_SPEED].Current;

View File

@ -2,11 +2,17 @@
void UI_FreeMode_Init(void)
{
uint8_t keep = (UI_IsSettingsPage() && mGuiData[GUI_TAB_INDEX].Current == 2) ? 1u : 0u;
// CurrentMode = 2;
mGuiData[GUI_TAB_INDEX].Current = 2;
mGuiData[GUI_TAB_LAST_INDEX].Current = mGuiData[GUI_TAB_INDEX].Current;
//mGuiData[GUI_AUTOBAND_SW].Current = 1;
UI_ReloadTonePreset(); /* TAB=普通 后再加载 1.bin */
if (!keep)
UI_ReloadTonePreset(); /* TAB=普通 后再加载 1.bin */
/* 未连 App:普通一直全绿。从设置返回同一模式不改灯。 */
if (!keep && !AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
if (CurrUIProcress == UI_SongMode_Process)
Show_home_UI_Diff();
else
@ -34,6 +40,10 @@ void UI_FreeMode_Process(DisplayTaskMessage_Type msg)
case MSG_ID_BATTERY_VALUE:
Draw_Status_Battery_Icon(percentage);
break;
case MSG_ID_CHARG:
Show_Battery_Icon(msg.ID);
break;
case MSG_ID_TAP_SPEED:
{
@ -98,11 +108,6 @@ void UI_FreeMode_Process(DisplayTaskMessage_Type msg)
{
Refresh_Transpose(&UI_Label[GUI_SPEED], &mGuiData[GUI_SPEED]);
if(nvm->param.BPM != mGuiData[GUI_SPEED].Current)
{
nvm->param.BPM = mGuiData[GUI_SPEED].Current;
}
uint8_t Speed[6] = {0xF0, 0x51, 0x03, 0x00, 0x00, 0xF7};
Speed[3] = mGuiData[GUI_SPEED].Current / 128;
Speed[4] = mGuiData[GUI_SPEED].Current % 128;

View File

@ -2,18 +2,24 @@
uint8_t CurrentMode = 0;
void RGB_Y_TO_R()
/* 样机「开机彩灯」:侧灯全亮色序 蓝→青→红→绿(末态与模式切换同色绿) */
void UI_BootLedShow(void)
{
app_tm1629_all_on(LED_COLOR_YELL);
rt_thread_delay(1000);
app_tm1629_all_on(LED_COLOR_R);
}
static const LedColor_TypeDef seq[] = {
LED_COLOR_B,
LED_COLOR_CYA,
LED_COLOR_R,
LED_COLOR_G,
};
static const uint16_t hold_ms[] = { 400, 300, 400, 0 };
uint8_t i;
void RGB_Y_TO_G()
{
app_tm1629_all_on(LED_COLOR_YELL);
rt_thread_delay(1000);
app_tm1629_all_on(LED_COLOR_G);
for (i = 0; i < (uint8_t)(sizeof(seq) / sizeof(seq[0])); i++)
{
app_tm1629_all_on(seq[i]);
if (hold_ms[i] != 0U)
rt_thread_mdelay(hold_ms[i]);
}
}
#define UI_MODE_SCREEN_WIDTH 240
@ -21,11 +27,11 @@ void RGB_Y_TO_G()
extern bool InModeFlag;
/* 0902-01:行高88、行距92;顶边与模式主页移调/速度(CARD_Y=48)对齐,分割线居中 */
/* 模式选择三行与演奏页移调卡不再共用 Y:演奏页按 0923-04 上移后仍保持本页 48/140/232 */
#define UI0902_MODE_ROW_X 9
#define UI0902_MODE_ROW_W 222
#define UI0902_MODE_ROW_H 88
#define UI0902_MODE_ROW_Y0 UI0902_CARD_Y /* 48,与移调/速度顶对齐 */
#define UI0902_MODE_ROW_Y0 48
#define UI0902_MODE_ROW_DY 92 /* 48 / 140 / 232 */
/* 模式页不显示焦点:三行均用未选中资源;单击直接进入 */
@ -43,26 +49,22 @@ static void UI_ModeSelect_DrawButtons(void)
LCD_WR_PIC_FROM_FLASH(UI0902_MODE_ROW_X, y,
UI0902_MODE_ROW_W, UI0902_MODE_ROW_H,
s_mode_row_addr[i]);
/* 万能模式素材顶部有残留近白横线(相对行内 y=7/8),盖成行底色 */
if (i == 0) {
LCD_FillByColor(UI0902_MODE_ROW_X, (uint16_t)(y + 7),
(uint16_t)(UI0902_MODE_ROW_X + UI0902_MODE_ROW_W),
(uint16_t)(y + 9), UI0902_ROW_BG);
}
}
}
void UI_ReturnToModeSelect(void)
{
StartFlag = 0;
InModeFlag = false;
AutoBandTop1_Stop();
Stop_AutoBand();
/* 长按回模式选择时,清掉万能 LOOP_LIGHT 残留红灯 */
app_tm1629_all_on(LED_COLOR_G);
CallUI_Idle();
UI_DrawModeSelectScreen();
}
void UI_DrawModeSelectScreen(void)
{
InModeFlag = false; /* 模式选择页:未进入演奏模式,禁止伴奏起奏 */
UI_ClearFocus();
pCurrentTouch_Area = Touch_ModeSelect_Areas;
@ -73,6 +75,9 @@ void UI_DrawModeSelectScreen(void)
}
const Touch_AreaTypeDef Touch_ModeSelect_Areas[] = {
/* 状态栏蓝牙:点击开关(须在模式行之前,避免被误判) */
{ UI0902_BT_HIT_X0, UI0902_BT_HIT_X1, UI0902_BT_HIT_Y0, UI0902_BT_HIT_Y1,
0, 0, GUI_BL_SW, NULL },
/* Flag=按钮序号(0万能/1普通/2专业);ID=进入 TAB。全宽便于命中;Y 与 MODE_ROW_* 一致 */
{ 0, 239, 48, 135, 0, 0, 0, NULL },
{ 0, 239, 140, 227, 1, 0, 2, NULL },
@ -91,7 +96,14 @@ extern int8_t delta;
extern STRING_MIDI USE_MIDI;
void LoadConfig(void)
{
SendProgramChangeMidiEvent(0,Timbre_index[mGuiData[GUI_TIMBRE_SELECT].Current]);
uint8_t ch;
/* 双音色库:主弦走 Bank1,先选 bank 再 PC */
SendProgramWithBankMidiEvent(0, MIDI_BANK_STRING, Timbre_index[mGuiData[GUI_TIMBRE_SELECT].Current]);
/* 伴奏通道预置 Bank0,避免上电后首个 PC 前误用残留 bank */
for (ch = 1; ch <= 15; ch++)
SendBankChangeMidiEvent(ch, MIDI_BANK_ACCOMP);
uint8_t val_127 = (faders[0].val * 127) / 10;
SendVolumeChangeMidiEvent(1,val_127);
@ -112,6 +124,8 @@ void LoadConfig(void)
SendVolumeChangeMidiEvent(0,(faders[1].val * 127) / 10);
Dream_ApplyEditorParams();
AW816_Set_Volume(MIC_VOL_MAP[faders[2].val]);
AW816_Set_Reverb(faders[3].val * 10);
@ -121,10 +135,24 @@ void Touch_Mode_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex)
{
(void)areaIndex;
(void)FLAG;
if (ID == GUI_BL_SW)
{
UI_StatusBar_ToggleBluetooth();
return;
}
/* 音源板初始化要到秒级。没就绪就进模式,LoadConfig/拨片会打出不对的声音 */
if (!Audio_IsReady())
{
LOG_I("UI", "mode enter deferred: audio not ready");
return;
}
StartTask();
/* ID 为 TAB 索引:0=万能(Song) 1=专业(Expert) 2=普通(Free) */
mGuiData[GUI_TAB_INDEX].Current = ID;
InModeFlag = true;
/* 进模式:默认当前调一级,避免软关机残留把位影响拨片/前奏 */
StartFlag = 0;
Accomp_ApplyDefaultIChord();
/* 进入子页后抑制残留按下,否则易误触底栏 GUI_TAB_INDEX(id=5)→设置 */
app_touch_suppress(500);
/* DSP 已就绪:再下发音色 + 调音台音量(与关机前 NVM/faders 一致) */
@ -147,40 +175,53 @@ void Touch_Mode_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex)
}
extern uint8_t bat_init_done;
/* 关机充电页已绘制标志:POWER_ON 需清除,以便再次软关机充电时重绘 */
static bool s_charge_ui_drawn = false;
static uint8_t s_boot_led_done = 0;
/* Logo 保持到彩灯结束再进模式选择。电压未知或仍低于 6.8V 时留在 Logo,不点灯。 */
static void UI_BeginPerformancePower(void)
{
if (!powon || !app_adc_charge_ui_allowed() || s_boot_led_done)
{
if (powon && app_adc_charge_ui_allowed())
System_RequestAudioBringUp();
return;
}
s_boot_led_done = 1;
UI_BootLedShow();
System_RequestAudioBringUp();
UI_DrawModeSelectScreen();
StartTouchTask();
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
}
void IdleProcess(DisplayTaskMessage_Type msg)
{
uint8_t vol;
switch (msg.MessageType)
{
case MSG_ID_POWER_ON :
case MSG_ID_POWER_ON :
/* 充电软关机开机:滞后的拔电消息可能已切主电/关显示,强制恢复 */
BSP_MainPowerEnable(1);
LCD_WR_REG(0x29); /* Display ON */
s_charge_ui_drawn = false;
LCD_BLK_Set();
s_boot_led_done = 0;
/* 先留 Logo。彩灯(蓝→青→红→绿,约 1.1s)播完才进模式选择 */
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H,
UI0902_BOOT_LOGO_ADDR);
BSP_SelectAdcChannel(6);
/* 让出 CPU,避免忙等卡住触摸/主循环线程 */
rt_thread_mdelay(1000);
LoadConfig();
vol = ADC_ReadChannel(ADC_CHANNEL_1)>>5;
app_adc_sync_volume(vol);
Send_volume(vol);
UI_DrawModeSelectScreen();
TM1629D_AllLedOn(LED_COLOR_G);
TM1629D_UpdateDisplay(0);
StartTouchTask();
/* 扫描先跑,才能采到包电压。电压已高于 6.8V 时这里就播彩灯并切模式页 */
StartScanTask();
/* Dream 上电稍后可能忽略首包 SysEx:再发主音量 + 调音台(保持关机前设置) */
rt_thread_mdelay(400);
vol = ADC_ReadChannel(ADC_CHANNEL_1)>>5;
app_adc_sync_volume(vol);
Send_volume(vol);
LoadConfig();
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
UI_BeginPerformancePower();
break;
case MSG_ID_HEAVY_BOOT:
UI_BeginPerformancePower();
break;
case MSG_ID_POWER_OFF:
/* 关机:熄屏 + 关背光 */
/* 无 Type-C:整机关机熄屏;有 Type-C 时随后 POWOFF_CHARG 会再亮充电图 */
LCD_BLK_Clr();
LCD_WR_REG(0x28); /* Display OFF */
LCD_FillByColor(0, 0, 240, 320, BLACK);
break;
@ -190,6 +231,8 @@ void IdleProcess(DisplayTaskMessage_Type msg)
case MSG_ID_TOUCH:
{
if (!powon)
break; /* 软关机已停触摸;兜底勿进模式选择 */
static uint32_t s_last_enter_ms;
uint32_t now = rt_tick_get() * 1000U / RT_TICK_PER_SECOND;
uint8_t hit = 0U;
@ -204,6 +247,13 @@ void IdleProcess(DisplayTaskMessage_Type msg)
(unsigned)k,
(unsigned)Touch_ModeSelect_Areas[k].Flag,
(unsigned)msg.HiByte, (unsigned)msg.LoByte);
/* 蓝牙开关不受进模式防抖限制 */
if (Touch_ModeSelect_Areas[k].ID == GUI_BL_SW)
{
Touch_Mode_Select_Action(Touch_ModeSelect_Areas[k].Flag,
Touch_ModeSelect_Areas[k].ID, k);
break;
}
/* 单击直接进入对应模式主页 */
if (now - s_last_enter_ms < 300U)
break;
@ -225,12 +275,16 @@ void IdleProcess(DisplayTaskMessage_Type msg)
break;
case MSG_ID_BATTERY_VALUE:
if (!s_boot_led_done)
break;
Draw_Status_Battery_Icon(msg.ID);
break;
case MSG_ID_POWOFF_CHARG:
{
static bool s_charge_ui_drawn = false;
/* 已开机:忽略滞后的关机充电消息,勿覆盖模式选择页或切断主电 */
if (powon)
break;
if(!s_charge_ui_drawn)
{
uint8_t peek[4];
@ -254,8 +308,8 @@ void IdleProcess(DisplayTaskMessage_Type msg)
LOG_W("UI", "charge flash empty @0x%08lX — flash ui0902",
(unsigned long)UI0902_CHARGE_SCREEN_ADDR);
}
LCD_BLK_Set();
s_charge_ui_drawn = true;
Power_LogRails("charge-ui");
}
if(usb_charging_state)
{
@ -280,22 +334,31 @@ void IdleProcess(DisplayTaskMessage_Type msg)
}
LCD_WR_PIC_Trans(x, y, g_ChargePctPercent.w, g_ChargePctPercent.h,
g_ChargePctPercent.data, BLACK);
/* 插入后先显示充电画面。高于 6.8V 一直亮;否则 10s 后关屏,充电继续 */
if (app_adc_charge_ui_allowed())
Power_ChargeBacklightSteady();
else
Power_ChargeBacklightLowHold();
}
else
{
/* 关机充电中拔掉:熄屏,允许下次再进充电页 */
Power_ChargeBacklightSessionReset();
LCD_BLK_Clr();
LCD_FillByColor(0, 0, 240, 320, BLACK);
BSP_MainPowerEnable(0);
s_charge_ui_drawn = false;
Power_LogRails("charge-unplug");
}
}
break;
case MSG_ID_EC_VOL:
{
/* 主音量已在 MainTask 下发;此处只刷新条 */
/* 主音量已在 MainTask 下发;Logo 期间不画音量条 */
level = msg.HiByte;
if (!s_boot_led_done)
break;
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
ResetAutoPowerCount();
}

81
UI/UI_Language.c Normal file
View File

@ -0,0 +1,81 @@
#include "includes.h"
extern const Touch_AreaTypeDef *pCurrentTouch_Area;
const Touch_AreaTypeDef Touch_Language_Areas[] =
{
{ 0, 44, 0, 40, 0, 0, GUI_CANCEL, NULL },
{ UI0902_LANG_BTN_X, (uint16_t)(UI0902_LANG_BTN_X + UI0902_LANG_BTN_W - 1),
UI0902_LANG_BTN_Y0, (uint16_t)(UI0902_LANG_BTN_Y0 + UI0902_LANG_BTN_H - 1),
0, NVM_LANG_CN, GUI_LANGUAGE_PICK, NULL },
{ UI0902_LANG_BTN_X, (uint16_t)(UI0902_LANG_BTN_X + UI0902_LANG_BTN_W - 1),
UI0902_LANG_BTN_Y1, (uint16_t)(UI0902_LANG_BTN_Y1 + UI0902_LANG_BTN_H - 1),
0, NVM_LANG_EN, GUI_LANGUAGE_PICK, NULL },
};
#define TOUCH_AREA_LANGUAGE_NUM (sizeof(Touch_Language_Areas)/sizeof(Touch_AreaTypeDef))
static void UI_Language_DrawButtons(void)
{
NvmParam_Type *nvm = drv_nvm_param_ptr();
uint8_t lang = nvm->param.Language;
uint32_t cn_addr;
uint32_t en_addr;
if (lang > 1)
lang = NVM_LANG_CN;
cn_addr = (lang == NVM_LANG_CN) ? UI0902_BTN_LANG_CN2_ADDR : UI0902_BTN_LANG_CN1_ADDR;
en_addr = (lang == NVM_LANG_EN) ? UI0902_BTN_LANG_EN_ON_ADDR : UI0902_BTN_LANG_EN_ADDR;
LCD_WR_PIC_FROM_FLASH(UI0902_LANG_BTN_X, UI0902_LANG_BTN_Y0,
UI0902_BTN_LANG_CN1_W, UI0902_BTN_LANG_CN1_H, cn_addr);
LCD_WR_PIC_FROM_FLASH(UI0902_LANG_BTN_X, UI0902_LANG_BTN_Y1,
UI0902_BTN_LANG_EN_W, UI0902_BTN_LANG_EN_H, en_addr);
}
void UI_Language_Init(void)
{
UI_ClearFocus();
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
UI_DrawSubPageHeader((const uint8_t *)"\xCF\xB5\xCD\xB3\xD3\xEF\xD1\xD4"); /* 系统语言 */
UI_Language_DrawButtons();
pCurrentTouch_Area = Touch_Language_Areas;
}
void UI_Language_Process(DisplayTaskMessage_Type msg)
{
uint8_t k;
NvmParam_Type *nvm;
switch (msg.MessageType)
{
case MSG_ID_TOUCH:
for (k = 0; k < TOUCH_AREA_LANGUAGE_NUM; k++)
{
if (msg.HiByte >= pCurrentTouch_Area[k].x_min &&
msg.HiByte <= pCurrentTouch_Area[k].x_max &&
msg.LoByte >= pCurrentTouch_Area[k].y_min &&
msg.LoByte <= pCurrentTouch_Area[k].y_max)
{
switch (pCurrentTouch_Area[k].ID)
{
case GUI_CANCEL:
MenuPage_SystemSetting_Proc();
break;
case GUI_LANGUAGE_PICK:
nvm = drv_nvm_param_ptr();
nvm->param.Language = pCurrentTouch_Area[k].Value ? NVM_LANG_EN : NVM_LANG_CN;
drv_nvm_save_to_flash();
UI_Language_DrawButtons();
break;
default:
break;
}
ResetAutoPowerCount();
break;
}
}
break;
default:
break;
}
}

7
UI/UI_Language.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UI_LANGUAGE_H_
#define UI_LANGUAGE_H_
void UI_Language_Init(void);
void UI_Language_Process(DisplayTaskMessage_Type msg);
#endif

View File

@ -1,6 +1,8 @@
#include "includes.h"
#include "mixer_knob_0902.h"
extern const Touch_AreaTypeDef *pCurrentTouch_Area;
static int8_t s_mixer_focus = -1;
static int8_t s_mixer_grab = -1; /* 按下锁定的推子,松手前不换轨 */
/* 0902-06 调音台:返回 + 标题;无底栏 */
const Touch_AreaTypeDef Touch_Mixer_Areas[] = {
@ -53,18 +55,26 @@ void DrawAllFaders(void)
drv_nvm_save_to_flash();
}
/* 0902-06:实心蓝色圆钮(勿用同心空心圆,会透出色条) */
#define MIXER_KNOB_R 14
/* 美工 0902-31 方圆色块 24x23;透明角贴在色条上,数字另画 */
#define MIXER_KNOB_W MIXER_KNOB_ART_W
#define MIXER_KNOB_H MIXER_KNOB_ART_H
static void DrawMixerKnob(uint16_t cx, uint16_t cy)
{
uint16_t x = (uint16_t)(cx - MIXER_KNOB_W / 2);
uint16_t y = (uint16_t)(cy - MIXER_KNOB_H / 2);
LCD_WR_PIC_Trans(x, y, MIXER_KNOB_W, MIXER_KNOB_H, gImage_MixerKnob_24x23, BLACK);
}
static void DrawFaderSlider(Fader_t *f, uint16_t slider_y)
{
uint16_t cx = f->x + f->w / 2;
uint16_t ly = f->y + f->h + 8;
uint16_t cy = (uint16_t)(slider_y + MIXER_KNOB_R);
uint16_t cy = (uint16_t)(slider_y + MIXER_KNOB_H / 2);
char buf[8];
LCD_FillCircle(cx, cy, MIXER_KNOB_R, COLOR_GRAD_MID);
DrawMixerKnob(cx, cy);
sprintf(buf, "%d", f->val);
LCD_ShowString_AutoAlign((uint16_t)(cx - 8), (uint16_t)(cx + 8),
LCD_ShowString_AutoAlign((uint16_t)(cx - 10), (uint16_t)(cx + 10),
(uint16_t)(cy - 5),
(uint8_t*)buf, LCD_ALIGN_CENTER, WHITE, COLOR_GRAD_MID, 0, 11);
LCD_FillByColor(cx - 15, ly + 17, cx + 15, ly + 19, UI0902_BG_COLOR);
@ -149,24 +159,23 @@ void UpdateFaderByTouch(int idx, uint16_t y)
}
// ============================================================
// ??????Y????????val? 0~10??
// 滑块顶边 Y:0/10 档方圆贴色条底/顶,不超出柱身
// ============================================================
static uint16_t CalcSliderY(Fader_t *f)
{
uint16_t slider_h = (uint16_t)(MIXER_KNOB_R * 2);
uint16_t fill_h = (f->val * f->h) / 10;
if (fill_h > f->h) fill_h = f->h;
uint16_t slider_y = f->y + f->h - fill_h - (slider_h / 2);
if (slider_y < f->y) slider_y = f->y;
if (slider_y > f->y + f->h - slider_h) slider_y = f->y + f->h - slider_h;
return slider_y;
uint16_t half = (uint16_t)(MIXER_KNOB_H / 2);
uint16_t top_cy = (uint16_t)(f->y + half);
uint16_t bot_cy = (uint16_t)(f->y + f->h - (MIXER_KNOB_H - half));
uint16_t cy = (uint16_t)(bot_cy - ((uint32_t)(bot_cy - top_cy) * f->val) / 10);
return (uint16_t)(cy - half);
}
int CheckTouchFader(uint16_t x, uint16_t y)
{
for (int i = 0; i < 4; i++) {
Fader_t *f = &faders[i];
if (x >= f->x - 10 && x <= f->x + f->w + 10 &&
/* 热区不超过轨宽+两侧小余量,避免与邻轨重叠误触 */
if (x >= f->x - 4 && x <= f->x + f->w + 4 &&
y >= f->y && y <= f->y + f->h) {
return i;
}
@ -178,6 +187,7 @@ int CheckTouchFader(uint16_t x, uint16_t y)
void UI_Mixer_Init(void)
{
s_mixer_focus = -1;
s_mixer_grab = -1;
UI_ClearFocus();
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
UI_DrawSubPageHeader((const uint8_t*)"\xB5\xF7\xD2\xF4\xCC\xA8");
@ -193,13 +203,27 @@ void UI_Mixer_Process(DisplayTaskMessage_Type msg)
switch(msg.MessageType)
{
case MSG_ID_TOUCH:
/* 推子拖动会 early-return:须先复位,否则调音台操作无法打断自动关机 */
ResetAutoPowerCount();
tx = msg.HiByte;
ty = msg.LoByte;
/* ID=0:抬起,解开推子锁定 */
if (msg.ID == 0)
{
s_mixer_grab = -1;
break;
}
if (s_mixer_grab >= 0)
{
UpdateFaderByTouch(s_mixer_grab, ty);
return;
}
// 1. ?????????
fader_idx = CheckTouchFader(tx, ty);
if (fader_idx >= 0)
{
s_mixer_grab = (int8_t)fader_idx;
UpdateFaderByTouch(fader_idx, ty);
return;
}
@ -218,11 +242,10 @@ void UI_Mixer_Process(DisplayTaskMessage_Type msg)
break;
}
}
ResetAutoPowerCount();
break;
case MSG_ID_EC_VOL:
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, msg.HiByte, 1, WHITE, GRAY);
/* 调音台子页无状态栏音量条(与返回键重叠);主音量已在 MainTask 下发 */
ResetAutoPowerCount();
break;
}

View File

@ -1,24 +1,22 @@
#include "includes.h"
/* 0904 / 0902-07 ??????? + ?? + ????????? */
extern const Touch_AreaTypeDef *pCurrentTouch_Area;
const Touch_AreaTypeDef Touch_SystemSetting_Areas[] =
{
/* ?? */
/* 返回 */
{ 0, 44, 0, 40, 0, 0, GUI_CANCEL, NULL },
/* ???? */
/* USB模式 左右半行 */
{ UI0902_SET_ROW_X, (uint16_t)(UI0902_SET_ROW_X + UI0902_SET_ROW_W / 2 - 1),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH + UI0902_SET_ROW_H - 1),
-1, 0, GUI_BLUETOOTH_SW, NULL },
-1, 0, GUI_USB_MODE, NULL },
{ (uint16_t)(UI0902_SET_ROW_X + UI0902_SET_ROW_W / 2),
(uint16_t)(UI0902_SET_ROW_X + UI0902_SET_ROW_W - 1),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH + UI0902_SET_ROW_H - 1),
1, 0, GUI_BLUETOOTH_SW, NULL },
/* ?????? */
1, 0, GUI_USB_MODE, NULL },
/* 自动关机 */
{ UI0902_SET_ROW_X, (uint16_t)(UI0902_SET_ROW_X + UI0902_SET_ROW_W / 2 - 1),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 2),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 2 + UI0902_SET_ROW_H - 1),
@ -28,7 +26,7 @@ const Touch_AreaTypeDef Touch_SystemSetting_Areas[] =
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 2),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 2 + UI0902_SET_ROW_H - 1),
1, 0, GUI_AUTOCLOSE, NULL },
/* ???? */
/* 恢复出厂 */
{ UI0902_SET_ROW_X, (uint16_t)(UI0902_SET_ROW_X + UI0902_SET_ROW_W - 1),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 3),
(uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 3 + UI0902_SET_ROW_H - 1),
@ -39,8 +37,7 @@ const Touch_AreaTypeDef Touch_SystemSetting_Areas[] =
GUI_SWITCH mGuiData_SystemSETTING[] = {
{ 0, 0, 2, GUI_VERSION},
{ 1, 0, 1, GUI_BLUETOOTH_SW}, /* 默认开;开机由 NVM BluetoothSW 覆盖 */
/* 手册:15/30/45/60 分钟 + 不自动;默认 15 分钟(index 0) */
{ 0, 0, 1, GUI_USB_MODE}, /* 0=USB MIDI 1=USB更新;开机由 NVM UsbMode 覆盖 */
{ 0, 0, 4, GUI_AUTOCLOSE},
{ 0, 0, 1, GUI_RESTORE},
};
@ -52,9 +49,9 @@ LEBEL_UI SystemSetting[] =
LCD_ALIGN_LEFT, WHITE, BLACK, UI0902_SET_ROW_FONT,
LCD_ALIGN_CENTER, WHITE, BLACK, UI0902_FONT_LABEL, GUI_VERSION},
{UI0902_SET_ROW_X, UI0902_SET_ROW_W, (uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH),
UI0902_SET_ROW_H, (const uint8_t*)"\xC0\xB6\xD1\xC0\xC1\xAC\xBD\xD3",
UI0902_SET_ROW_H, (const uint8_t*)"USB\xC4\xA3\xCA\xBD",
LCD_ALIGN_LEFT, WHITE, BLACK, UI0902_SET_ROW_FONT,
LCD_ALIGN_CENTER, WHITE, BLACK, UI0902_FONT_LABEL, GUI_BLUETOOTH_SW},
LCD_ALIGN_CENTER, WHITE, BLACK, UI0902_FONT_LABEL, GUI_USB_MODE},
{UI0902_SET_ROW_X, UI0902_SET_ROW_W, (uint16_t)(UI0902_SET_ROW_Y0 + UI0902_SET_ROW_PITCH * 2),
UI0902_SET_ROW_H, (const uint8_t*)"\xD7\xD4\xB6\xAF\xB9\xD8\xBB\xFA",
LCD_ALIGN_LEFT, WHITE, BLACK, UI0902_SET_ROW_FONT,
@ -68,7 +65,7 @@ LEBEL_UI SystemSetting[] =
void DrawSystemSetting(void)
{
Draw_System_Item_List(&SystemSetting[GUI_VERSION], &mGuiData_SystemSETTING[GUI_VERSION]);
Draw_System_Item_List(&SystemSetting[GUI_BLUETOOTH_SW], &mGuiData_SystemSETTING[GUI_BLUETOOTH_SW]);
Draw_System_Item_List(&SystemSetting[GUI_USB_MODE], &mGuiData_SystemSETTING[GUI_USB_MODE]);
Draw_System_Item_List(&SystemSetting[GUI_AUTOCLOSE], &mGuiData_SystemSETTING[GUI_AUTOCLOSE]);
Draw_System_Item_List(&SystemSetting[GUI_RESTORE], &mGuiData_SystemSETTING[GUI_RESTORE]);
}
@ -76,20 +73,29 @@ void DrawSystemSetting(void)
void Touch_SystemSettingAction(int8_t FLAG, uint8_t ID, uint8_t areaIndex, uint8_t value)
{
uint16_t last_value;
NvmParam_Type *nvm;
(void)areaIndex;
(void)value;
if (ID == GUI_CANCEL)
{
MenuPage_SystemSetting_Proc(); /* ? 0902-11 ???? */
MenuPage_SystemSetting_Proc();
return;
}
last_value = mGuiData_SystemSETTING[ID].Current;
switch (ID)
{
case GUI_BLUETOOTH_SW:
mGuiData_SystemSETTING[ID].Current = !mGuiData_SystemSETTING[ID].Current;
case GUI_USB_MODE:
GUI_Item_AjustLoopValue(&mGuiData_SystemSETTING[ID], FLAG >= 0 ? 1 : -1);
if (mGuiData_SystemSETTING[ID].Current == NVM_USB_UPDATE)
{
MenuPage_UsbConfirm_Proc();
return;
}
nvm = drv_nvm_param_ptr();
nvm->param.UsbMode = NVM_USB_MIDI;
drv_nvm_save_to_flash();
if (!UI_SetFocus(ID))
RefreshSystemSetting(last_value, &SystemSetting[ID], &mGuiData_SystemSETTING[ID]);
break;
@ -113,7 +119,7 @@ void UI_Setting_Init(void)
{
UI_ClearFocus();
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
UI_DrawSubPageHeader((const uint8_t *)"\xCF\xB5\xCD\xB3\xC9\xE8\xD6\xC3");
UI_DrawSystemSetHeader();
DrawSystemSetting();
pCurrentTouch_Area = Touch_SystemSetting_Areas;
}

View File

@ -111,12 +111,20 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
int8_t new_trans = mGuiData[GUI_TRANSPOSE].Current;
delta = new_trans - last_value;
USE_MIDI.Midi_1 += delta;
USE_MIDI.Midi_2 += delta;
USE_MIDI.Midi_3 += delta;
USE_MIDI.Midi_4 += delta;
USE_MIDI.Midi_5 += delta;
USE_MIDI.Midi_6 += delta;
/* 固定调:换调后按新映射重填 6 弦;未按指板时维持旧平移 */
if (KEY_ID_1629 >= 1 && KEY_ID_1629 <= 21)
{
FretChord_FillUseMidi(KEY_ID_1629);
}
else
{
USE_MIDI.Midi_1 += delta;
USE_MIDI.Midi_2 += delta;
USE_MIDI.Midi_3 += delta;
USE_MIDI.Midi_4 += delta;
USE_MIDI.Midi_5 += delta;
USE_MIDI.Midi_6 += delta;
}
if(StartFlag)
{
@ -152,11 +160,8 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
Speed[4] = mGuiData[ID].Current % 128;
USART4_SendData(Speed,sizeof(Speed));
if(nvm->param.BPM != mGuiData[ID].Current)
{
nvm->param.BPM = mGuiData[ID].Current;
}
AutoBandTop1_ChangeBPM(mGuiData[ID].Current); // AutoBand 模块未加入工程
/* 同一曲目内的手调速度只在本次开机有效 */
AutoBandTop1_ChangeBPM(mGuiData[ID].Current);
}
break;
@ -177,14 +182,18 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
if (!UI_SetFocus(GUI_MODE_PARAM))
show_Param(&UI_Label[GUI_MODE_PARAM], pCurData);
/* 切歌/切走向:先停当前伴奏并静音,避免旧曲尾音残留 */
if (last_value != pCurData->Current)
Stop_AutoBand();
UI_ApplyToneAddress();
int ret = 0;
if (tab == 0)
ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
ret = App_Auto_LoadPresetFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
else if (mGuiData[GUI_AUTOBAND_SW].Current)
ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current);
ret = App_Auto_LoadPresetFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current);
else
ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
ret = App_Auto_LoadPresetFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
if (ret != 0)
LOG_E("tone", "load preset failed tab=%d sw=%d ret=%d addr=0x%08X",
tab, mGuiData[GUI_AUTOBAND_SW].Current, ret, (unsigned)ADDRESS);
@ -193,6 +202,7 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
tab, mGuiData[GUI_AUTOBAND_SW].Current,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
(unsigned)ADDRESS);
TrackBpm_OnPresetLoaded();
if (tab == 0)
nvm->param.Param3 = ParamGuiData[ALL_MODE_PARAM].Current;
@ -200,6 +210,19 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
nvm->param.Param2 = ParamGuiData[EXPRESS_MODE_PARAM].Current;
else
nvm->param.Param1 = ParamGuiData[SONG_MODE_PARAM].Current;
/* 联动 App:本地切换节奏风格后上报(格式同 03 04 读回复;万能 tab 为和弦走向不上报) */
if (tab != 0)
{
uint8_t style_src = (uint8_t)mGuiData[GUI_AUTOBAND_SW].Current;
uint16_t style_id = style_src ? ParamGuiData[EXPRESS_MODE_PARAM].Current
: ParamGuiData[SONG_MODE_PARAM].Current;
uint8_t StyleNotify[9] = {0xF0,0x60,0x03,0x04,0x00,0x00,0x00,0x00,0xF7};
StyleNotify[5] = style_src;
StyleNotify[6] = (uint8_t)(style_id / 128);
StyleNotify[7] = (uint8_t)(style_id % 128);
USART4_SendData(StyleNotify,sizeof(StyleNotify));
}
}
break;
case GUI_TIMBRE_SELECT:
@ -233,18 +256,41 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
UI_ReloadTonePreset();
if (!UI_SetFocus(GUI_MODE_PARAM))
label_ModeSelece_ui(&UI_Label[GUI_MODE_PARAM],&mGuiData[GUI_MODE_PARAM]);
/* 联动 App:节奏类型/本地曲目切换后上报当前风格 */
{
uint16_t style_id = value ? ParamGuiData[EXPRESS_MODE_PARAM].Current
: ParamGuiData[SONG_MODE_PARAM].Current;
uint8_t StyleNotify[9] = {0xF0,0x60,0x03,0x04,0x00,0x00,0x00,0x00,0xF7};
StyleNotify[5] = (uint8_t)value;
StyleNotify[6] = (uint8_t)(style_id / 128);
StyleNotify[7] = (uint8_t)(style_id % 128);
USART4_SendData(StyleNotify,sizeof(StyleNotify));
}
return;
}
else if(ID==GUI_PLAY_SECTION)
{
/* 万能模式第4键是尾奏,不是第4加花:不改 1/2/3 焦点 */
if (mGuiData[GUI_TAB_INDEX].Current == 0 && value == 3)
{
AutoBand_StartOutro();
return;
}
if(mGuiData[ID].Current != value)
{
mGuiData[ID].Current = value;
AutoBandTop1_SetRunVar(mGuiData[ID].Current);
AutoBandTop1_SetRunVar(mGuiData[ID].Current);
/* 专业本地曲:切段后 PlayTick 可能短暂不变,刷新活动以免随后指板误走 Stop */
if (StartFlag)
Band_NotifyPlayActivity();
}else
{
{
/* 触摸起奏前补发主音量,保证实际音量与图标一致 */
MasterVolume_Reapply();
AutoBandTop1_FillinWithIndex(value);
AutoBandTop1_Start();
if (StartFlag)
Band_NotifyPlayActivity();
}
if (!UI_SetFocus(GUI_PLAY_SECTION))
Refresh_SectionSelect(last_value, &UI_Label[ID], &mGuiData[ID]);
@ -259,15 +305,20 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
{
if(mGuiData[ID].Current != value)
{
/* 改 TAB 前先记住当前专业/普通指板与移调 */
Accomp_RememberPlayContext();
mGuiData[ID].Current = value;
app_tm1629_all_on(LED_COLOR_G);
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
switch(mGuiData[ID].Current)
{
case 0: /* 万能 → 3.bin / 本地→2.bin */
if(mGuiData[GUI_TAB_LAST_INDEX].Current == mGuiData[ID].Current)
break;
StartFlag = 0;
KEY_ID_1629 = 0; /* 清专业等残留指板键,拨片按当前调走走向 */
PressFlag = 0;
AutoBandTop1_Stop();
UI_ReloadTonePreset(); /* 切换模式必须换库,避免专业仍播万能数据 */
break;
@ -293,9 +344,8 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
return;
}
else if(ID==GUI_BL_SW)
{
mGuiData[ID].Current = !mGuiData[ID].Current;
Show_BL_Icon(mGuiData[GUI_BL_SW].Current);
{
UI_StatusBar_ToggleBluetooth();
return;
}
}
@ -303,11 +353,15 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
void UI_SongMode_Init(void)
{
uint8_t keep = (UI_IsSettingsPage() && mGuiData[GUI_TAB_INDEX].Current == 0) ? 1u : 0u;
CurrentMode = 0;
//mGuiData[GUI_AUTOBAND_SW].Current = 0;
mGuiData[GUI_TAB_INDEX].Current = 0;
mGuiData[GUI_TAB_LAST_INDEX].Current = mGuiData[GUI_TAB_INDEX].Current;
UI_ReloadTonePreset(); /* TAB=万能 后再加载 3.bin */
/* 从设置回到同一万能:不停、不换库 */
if (!keep)
UI_ReloadTonePreset(); /* TAB=万能 后再加载 3.bin */
/* 已在主页互切用差分;从 Idle/设置进入仍整页 */
if (CurrUIProcress == UI_SongMode_Process)
Show_home_UI_Diff();
@ -317,6 +371,78 @@ void UI_SongMode_Init(void)
}
void UI_PlaySectionKey(uint8_t value)
{
if (value > 3u)
return;
/* 万能第4键是尾奏,不改 1/2/3 焦点 */
if (mGuiData[GUI_TAB_INDEX].Current == 0 && value == 3u)
{
AutoBand_StartOutro();
return;
}
if (mGuiData[GUI_PLAY_SECTION].Current != value)
{
mGuiData[GUI_PLAY_SECTION].Current = value;
AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current);
if (StartFlag)
Band_NotifyPlayActivity();
}
else
{
MasterVolume_Reapply();
AutoBandTop1_FillinWithIndex(value);
AutoBandTop1_Start();
if (StartFlag)
Band_NotifyPlayActivity();
}
}
void UI_ApplyModeKeysOnSettings(DisplayTaskMessage_Type msg)
{
NvmParam_Type *nvm = drv_nvm_param_ptr();
if (msg.MessageType == MSG_ID_TAP_SPEED)
{
mGuiData[GUI_SPEED].Current = msg.ID;
AutoBandTop1_ChangeBPM(mGuiData[GUI_SPEED].Current);
Speed[3] = mGuiData[GUI_SPEED].Current / 128;
Speed[4] = mGuiData[GUI_SPEED].Current % 128;
USART4_SendData(Speed, sizeof(Speed));
return;
}
if (msg.MessageType == MSG_ID_BP_TRANSPOSE)
{
uint8_t lastvalue = mGuiData[GUI_TRANSPOSE].Current;
int8_t new_trans;
if (mGuiData[GUI_TRANSPOSE].Current != msg.ID)
mGuiData[GUI_TRANSPOSE].Current = msg.ID;
if (nvm->param.Transpose != mGuiData[GUI_TRANSPOSE].Current)
nvm->param.Transpose = mGuiData[GUI_TRANSPOSE].Current;
transpose[3] = mGuiData[GUI_TRANSPOSE].Current;
USART4_SendData(transpose, 5);
new_trans = (int8_t)mGuiData[GUI_TRANSPOSE].Current;
delta = (int8_t)(new_trans - (int8_t)lastvalue);
/* 固定调:换调后按新映射重填 6 弦;未按指板时维持旧平移 */
if (KEY_ID_1629 >= 1 && KEY_ID_1629 <= 21)
{
FretChord_FillUseMidi(KEY_ID_1629);
}
else
{
USE_MIDI.Midi_1 += delta;
USE_MIDI.Midi_2 += delta;
USE_MIDI.Midi_3 += delta;
USE_MIDI.Midi_4 += delta;
USE_MIDI.Midi_5 += delta;
USE_MIDI.Midi_6 += delta;
}
if (StartFlag && KEY_ID_1629 != 22 && KEY_ID_1629 != 23)
Accomp_UpdatePlayingChord();
}
}
void UI_SongMode_Process(DisplayTaskMessage_Type msg)
{
NvmParam_Type * nvm = drv_nvm_param_ptr();
@ -363,11 +489,7 @@ void UI_SongMode_Process(DisplayTaskMessage_Type msg)
if (!UI_SetFocus(GUI_SPEED))
Refresh_Transpose(&UI_Label[GUI_SPEED], &mGuiData[GUI_SPEED]);
AutoBandTop1_ChangeBPM(mGuiData[GUI_SPEED].Current);
if(nvm->param.BPM != mGuiData[GUI_SPEED].Current)
{
nvm->param.BPM = mGuiData[GUI_SPEED].Current;
}
Speed[3] = mGuiData[GUI_SPEED].Current / 128;
Speed[4] = mGuiData[GUI_SPEED].Current % 128;
USART4_SendData(Speed,sizeof(Speed));
@ -422,10 +544,6 @@ void UI_SongMode_Process(DisplayTaskMessage_Type msg)
{
Refresh_Transpose(&UI_Label[GUI_SPEED], &mGuiData[GUI_SPEED]);
if(nvm->param.BPM != mGuiData[GUI_SPEED].Current)
{
nvm->param.BPM = mGuiData[GUI_SPEED].Current;
}
uint8_t Speed[6] = {0xF0, 0x51, 0x03, 0x00, 0x00, 0xF7};
Speed[3] = mGuiData[GUI_SPEED].Current / 128;
Speed[4] = mGuiData[GUI_SPEED].Current % 128;
@ -474,6 +592,35 @@ void UI_SongMode_Process(DisplayTaskMessage_Type msg)
ResetAutoPowerCount();
}
break;
case MSG_ID_BLE_UI_REFRESH:
/* BLE 写指令的 LCD 刷新:状态已在 BLE 任务更新,此处仅在 UI 任务上下文绘制。
本消息经 MainTask→UITask 转发到 CurrUIProcress,只在曲目页才会被处理,
其它页面天然忽略,无需页面判断 */
switch (msg.ID)
{
case GUI_TIMBRE_SELECT:
UI_SetFocus(GUI_TIMBRE_SELECT);
Refresh_StringTimbre(0, &UI_Label[GUI_TIMBRE_SELECT], &mGuiData[GUI_TIMBRE_SELECT]);
break;
case GUI_MODE_PARAM:
if (!UI_SetFocus(GUI_MODE_PARAM))
label_ModeSelece_ui(&UI_Label[GUI_MODE_PARAM], &mGuiData[GUI_MODE_PARAM]);
break;
case GUI_SPEED:
Refresh_Transpose(&UI_Label[GUI_SPEED], &mGuiData[GUI_SPEED]);
break;
case GUI_TRANSPOSE:
Refresh_Transpose(&UI_Label[GUI_TRANSPOSE], &mGuiData[GUI_TRANSPOSE]);
break;
default:
break;
}
break;
case MSG_ID_BLE_STYLE_SET:
/* 停伴奏+换库已在 TaskUIThread 全局处理;此处仅刷新节奏风格卡片 */
if (!UI_SetFocus(GUI_MODE_PARAM))
label_ModeSelece_ui(&UI_Label[GUI_MODE_PARAM], &mGuiData[GUI_MODE_PARAM]);
break;
case MSG_ID_CHARG:
Show_Battery_Icon(msg.ID);
break;

View File

@ -20,6 +20,10 @@ void Draw_Tab_Mode_Menu(const LEBEL_UI *UI,GUI_SWITCH * Group);
void UI_SongMode_Init();
void UI_SongMode_Process(DisplayTaskMessage_Type xEvent);
/* 设置页上的 1~4 加花键:只改演奏段落,不画演奏页、不点设置 */
void UI_PlaySectionKey(uint8_t value);
/* 设置页上的拍速/快移调:改演奏状态,不刷新设置画面 */
void UI_ApplyModeKeysOnSettings(DisplayTaskMessage_Type msg);

View File

@ -1,54 +1,42 @@
#include "includes.h"
/* 0902-11 设置入口:调音台 / 系统设置 两大入口 + 底栏设置高亮 */
/* 0924 设置入口:调音台 / 系统语言 / 系统设置 + 底栏设置高亮 */
const Touch_AreaTypeDef Touch_SetingSelect_Areas[] = {
/* 调音台卡片 */
{ UI0902_BT_HIT_X0, UI0902_BT_HIT_X1, UI0902_BT_HIT_Y0, UI0902_BT_HIT_Y1,
0, 0, GUI_BL_SW, NULL },
{ UI0902_HUB_CARD_X, (uint16_t)(UI0902_HUB_CARD_X + UI0902_HUB_CARD_W - 1),
UI0902_HUB_CARD_Y0, (uint16_t)(UI0902_HUB_CARD_Y0 + UI0902_HUB_CARD_H - 1),
0, 0, GUI_SETING_SELECT1, NULL },
/* 系统设置卡片 */
{ UI0902_HUB_CARD_X, (uint16_t)(UI0902_HUB_CARD_X + UI0902_HUB_CARD_W - 1),
UI0902_HUB_CARD_Y1, (uint16_t)(UI0902_HUB_CARD_Y1 + UI0902_HUB_CARD_H - 1),
0, 0, GUI_SETING_SELECT2, NULL },
{ UI0902_HUB_CARD_X, (uint16_t)(UI0902_HUB_CARD_X + UI0902_HUB_CARD_W - 1),
UI0902_HUB_CARD_Y2, (uint16_t)(UI0902_HUB_CARD_Y2 + UI0902_HUB_CARD_H - 1),
0, 0, GUI_SETING_SELECT3, NULL },
/* 底栏四键 */
{ 0, 69, 280, 319, 0, UI0902_NAV_UNIVERSAL, GUI_NAV_BAR, NULL },
{ 70, 129, 280, 319, 0, UI0902_NAV_NORMAL, GUI_NAV_BAR, NULL },
{ 130, 184, 280, 319, 0, UI0902_NAV_EXPERT, GUI_NAV_BAR, NULL },
{ 185, 239, 280, 319, 0, UI0902_NAV_SETTING, GUI_NAV_BAR, NULL },
{ UI0902_NAV_X0(0), UI0902_NAV_X1(0), UI0902_NAV_Y0, UI0902_NAV_Y1, 0, UI0902_NAV_UNIVERSAL, GUI_NAV_BAR, NULL },
{ UI0902_NAV_X0(1), UI0902_NAV_X1(1), UI0902_NAV_Y0, UI0902_NAV_Y1, 0, UI0902_NAV_NORMAL, GUI_NAV_BAR, NULL },
{ UI0902_NAV_X0(2), UI0902_NAV_X1(2), UI0902_NAV_Y0, UI0902_NAV_Y1, 0, UI0902_NAV_EXPERT, GUI_NAV_BAR, NULL },
{ UI0902_NAV_X0(3), UI0902_NAV_X1(3), UI0902_NAV_Y0, UI0902_NAV_Y1, 0, UI0902_NAV_SETTING, GUI_NAV_BAR, NULL },
};
#define TOUCH_AREA_SETING_SELECT_NUM (sizeof(Touch_SetingSelect_Areas)/sizeof(Touch_AreaTypeDef))
static void UI_Hub_DrawCard(uint16_t y, const uint8_t *icon, uint16_t icon_w, uint16_t icon_h,
const uint8_t *title_gbk)
{
uint16_t x = UI0902_HUB_CARD_X;
uint16_t w = UI0902_HUB_CARD_W;
uint16_t h = UI0902_HUB_CARD_H;
uint16_t cy = y + h / 2;
uint16_t text_y = y + (h - UI0902_HUB_FONT) / 2;
uint16_t icon_x = x + 22;
uint16_t icon_y = y + (h - icon_h) / 2;
LCD_FillRoundRect(x, y, w, h, UI0902_RADIUS_CARD, UI0902_ROW_BG);
LCD_WR_PIC_Trans(icon_x, icon_y, icon_w, icon_h, icon, BLACK);
/* 标题相对卡片水平居中(略偏右给左侧图标留空) */
LCD_ShowChinese_AutoAlign(
x + 56, x + w - 36, text_y, title_gbk,
LCD_ALIGN_CENTER, WHITE, UI0902_ROW_BG, 0, UI0902_HUB_FONT);
LCD_DrawChevron_Right((uint16_t)(x + w - 24), cy, 6, 2, WHITE);
}
void Touch_Seting_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex, uint8_t value)
{
(void)FLAG;
(void)areaIndex;
if (ID == GUI_BL_SW)
{
UI_StatusBar_ToggleBluetooth();
return;
}
if (ID == GUI_NAV_BAR)
{
if (value == UI0902_NAV_SETTING)
return; /* 已在设置入口 */
return;
UI_NavBar_Action(value);
return;
}
@ -58,8 +46,11 @@ void Touch_Seting_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex, uint
case GUI_SETING_SELECT1:
MenuPage_Mixer_Proc();
break;
case GUI_SETING_SELECT2:
MenuPage_Language_Proc();
break;
case GUI_SETING_SELECT3:
MenuPage_Setting_Proc(); /* 系统设置明细 0902-07 */
MenuPage_Setting_Proc();
break;
default:
break;
@ -70,14 +61,15 @@ void UI_DrawSysModeSelectScreen(void)
{
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
label_top();
/* 调音台:0907 素材 13(34x33 推子图标) */
UI_Hub_DrawCard(UI0902_HUB_CARD_Y0, gImage_mixer, 34, 33,
(const uint8_t *)"\xB5\xF7\xD2\xF4\xCC\xA8");
/* 系统设置:0907 素材 14(33x33 齿轮图标) */
UI_Hub_DrawCard(UI0902_HUB_CARD_Y1, gImage_SystemSetting, 33, 33,
(const uint8_t *)"\xCF\xB5\xCD\xB3\xC9\xE8\xD6\xC3");
LCD_WR_PIC_FROM_FLASH(UI0902_HUB_CARD_X, UI0902_HUB_CARD_Y0,
UI0902_ROW_HUB_MIXER_W, UI0902_ROW_HUB_MIXER_H,
UI0902_ROW_HUB_MIXER_ADDR);
LCD_WR_PIC_FROM_FLASH(UI0902_HUB_CARD_X, UI0902_HUB_CARD_Y1,
UI0902_ROW_HUB_LANG_W, UI0902_ROW_HUB_LANG_H,
UI0902_ROW_HUB_LANG_ADDR);
LCD_WR_PIC_FROM_FLASH(UI0902_HUB_CARD_X, UI0902_HUB_CARD_Y2,
UI0902_ROW_HUB_SYSTEM_W, UI0902_ROW_HUB_SYSTEM_H,
UI0902_ROW_HUB_SYSTEM_ADDR);
Draw_Bottom_Bar(UI0902_NAV_SETTING, 0);
}
@ -124,6 +116,14 @@ void UI_SystemSet_Process(DisplayTaskMessage_Type msg)
label_top();
break;
case MSG_ID_CHARG:
label_top();
break;
case MSG_ID_EC_VOL:
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, msg.HiByte, 1, WHITE, GRAY);
break;
default:
break;
}

View File

@ -4,8 +4,8 @@
typedef enum {
GUI_SETING_SELECT1 = 0,
//GUI_SETING_SELECT2 = 1,
GUI_SETING_SELECT3 = 2,
GUI_SETING_SELECT2 = 1,
GUI_SETING_SELECT3 = 2,
}SETING_SELECT_ID;

84
UI/UI_UsbModeConfirm.c Normal file
View File

@ -0,0 +1,84 @@
#include "includes.h"
extern const Touch_AreaTypeDef *pCurrentTouch_Area;
const Touch_AreaTypeDef Touch_UsbConfirm_Areas[] =
{
{ 0, 44, 0, 40, 0, 0, GUI_CANCEL, NULL },
{ UI0902_USB_BTN_XL, (uint16_t)(UI0902_USB_BTN_XL + UI0902_USB_BTN_W - 1),
UI0902_USB_BTN_Y, (uint16_t)(UI0902_USB_BTN_Y + UI0902_USB_BTN_H - 1),
0, 0, GUI_CANCEL, NULL },
{ UI0902_USB_BTN_XR, (uint16_t)(UI0902_USB_BTN_XR + UI0902_USB_BTN_W - 1),
UI0902_USB_BTN_Y, (uint16_t)(UI0902_USB_BTN_Y + UI0902_USB_BTN_H - 1),
0, 0, GUI_CONFIRM, NULL },
};
#define TOUCH_AREA_USB_CONFIRM_NUM (sizeof(Touch_UsbConfirm_Areas)/sizeof(Touch_AreaTypeDef))
static void UI_UsbConfirm_RevertToMidi(void)
{
NvmParam_Type *nvm = drv_nvm_param_ptr();
mGuiData_SystemSETTING[GUI_USB_MODE].Current = NVM_USB_MIDI;
nvm->param.UsbMode = NVM_USB_MIDI;
drv_nvm_save_to_flash();
MenuPage_Setting_Proc();
}
void UI_UsbModeConfirm_Init(void)
{
UI_ClearFocus();
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_TXT_USB_CONFIRM_W, UI0902_TXT_USB_CONFIRM_H,
UI0902_TXT_USB_CONFIRM_ADDR);
UI_DrawSubPageHeader((const uint8_t *)"\xCF\xB5\xCD\xB3\xC9\xE8\xD6\xC3");
LCD_WR_PIC_FROM_FLASH(UI0902_USB_BTN_XL, UI0902_USB_BTN_Y,
UI0902_BTN_USB_CANCEL_DARK_W, UI0902_BTN_USB_CANCEL_DARK_H,
UI0902_BTN_USB_CANCEL_DARK_ADDR);
LCD_WR_PIC_FROM_FLASH(UI0902_USB_BTN_XR, UI0902_USB_BTN_Y,
UI0902_BTN_USB_CONFIRM_BLUE_W, UI0902_BTN_USB_CONFIRM_BLUE_H,
UI0902_BTN_USB_CONFIRM_BLUE_ADDR);
pCurrentTouch_Area = Touch_UsbConfirm_Areas;
}
void UI_UsbModeConfirm_Process(DisplayTaskMessage_Type msg)
{
uint8_t k;
NvmParam_Type *nvm;
switch (msg.MessageType)
{
case MSG_ID_TOUCH:
for (k = 0; k < TOUCH_AREA_USB_CONFIRM_NUM; k++)
{
if (msg.HiByte >= pCurrentTouch_Area[k].x_min &&
msg.HiByte <= pCurrentTouch_Area[k].x_max &&
msg.LoByte >= pCurrentTouch_Area[k].y_min &&
msg.LoByte <= pCurrentTouch_Area[k].y_max)
{
switch (pCurrentTouch_Area[k].ID)
{
case GUI_CANCEL:
UI_UsbConfirm_RevertToMidi();
break;
case GUI_CONFIRM:
nvm = drv_nvm_param_ptr();
nvm->param.UsbMode = NVM_USB_UPDATE;
/* 先记备份寄存器,再写 Flash。系统复位不清 BPR,
* Boot 不按圆键 4 也会留下烧录。关中断放在保存之后,
* 避免日志互斥在关中断后永远等不到超时。 */
drv_nvm_arm_usb_boot();
drv_nvm_save_to_flash();
__disable_irq();
nvic_system_reset();
break;
default:
break;
}
ResetAutoPowerCount();
break;
}
}
break;
default:
break;
}
}

7
UI/UI_UsbModeConfirm.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UI_USB_MODE_CONFIRM_H_
#define UI_USB_MODE_CONFIRM_H_
void UI_UsbModeConfirm_Init(void);
void UI_UsbModeConfirm_Process(DisplayTaskMessage_Type msg);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,9 @@ extern void (*MenuPage_FreeMode_Proc)(void);
extern void (*MenuPage_Setting_Proc)(void);
extern void (*MenuPage_SystemSetting_Proc)(void);
extern void (*MenuPage_Mixer_Proc)(void);
extern void (*MenuPage_Restore_Proc)(void);;
extern void (*MenuPage_Restore_Proc)(void);
extern void (*MenuPage_Language_Proc)(void);
extern void (*MenuPage_UsbConfirm_Proc)(void);
// ==============================================
// <20><><EFBFBD><EFBFBD> UI <20><><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>
@ -22,6 +24,8 @@ void CallUI_Setting(void);
void CallUI_Mixer(void);
void CallUI_SystemSetting(void);
void CallUI_RestoreSelect(void);
void CallUI_Language(void);
void CallUI_UsbConfirm(void);
@ -30,29 +34,33 @@ void CallUI_RestoreSelect(void);
#define UI_STATUS_BAR_H 26
/* 0902-01/02 需求稿:分割线 y=36,居中于顶栏图标底与移调/速度控件顶之间 */
#define UI0902_STATUS_SEP_Y 36
/* 顶/底共用:偏亮灰蓝,2px 厚,保证暗底上可辨 */
#define UI0902_SEP_LINE_COLOR 0x94D5 /* RGB(144,152,168) */
/* 顶/底共用:暗灰蓝,1px;暗底上可辨但不抢眼 */
#define UI0902_SEP_LINE_COLOR 0x31C9 /* RGB(48,56,72) */
#define UI0902_SEP_LINE_THICK 1
#define UI0902_STATUS_SEP_COLOR UI0902_SEP_LINE_COLOR
/* 0902 设计稿配色与底栏导航 */
#define UI0902_BG_COLOR 0x0042 /* #000813 页面背景 */
#define UI0902_ROW_BG 0x2147 /* #242B3A 列表行背景 */
/* 0902-04 普通模式实测(240×320):
* 双卡 y48 h55 w105 gap8;和弦行 y130 h31;音色 y180 h30;段落钮 y229 h34 */
/* K1_UI_0923-04(240×320):
* 状态栏底约 y29,移调/速度 y39–94;TAB y98;曲目行 y120–151;
* 音色行 y172–203;段落钮 y224–258;底栏图标 y264。 */
#define UI0902_MARGIN_X 12
#define UI0902_CONTENT_W 216
#define UI0902_CARD_GAP_TOP 22
#define UI0902_CARD_Y (UI_STATUS_BAR_H + UI0902_CARD_GAP_TOP) /* 48 */
#define UI0902_CARD_GAP_TOP 13
/* K1_UI_0923-05:移调卡 x11–115 y39–93;速度卡紧随其后,三角色块中线 y74 */
#define UI0902_CARD_X 11
#define UI0902_CARD_Y 39
#define UI0902_CARD_H 55
#define UI0902_CARD_W 105
#define UI0902_CARD_GAP 8
#define UI0902_MODE_Y (UI0902_CARD_Y + UI0902_CARD_H + 5) /* 108:TAB 顶 */
#define UI0902_MODE_H 53 /* TAB18 + 间隙4 + 曲目行31 */
#define UI0902_TIMBRE_Y 180
#define UI0902_TIMBRE_H 30
#define UI0902_SECTION_Y 231 /* 0904:段落钮顶 ≈231 */
#define UI0902_SECTION_H 34
#define UI0902_CARD_GAP 7
#define UI0902_CARD_CTRL_CY 74
#define UI0902_MODE_Y 98 /* 节奏类型 / 本地曲目 顶 */
#define UI0902_MODE_H 54 /* TAB18 + 间隙4 + 曲目行32(顶 y120) */
#define UI0902_TIMBRE_Y 172
#define UI0902_TIMBRE_H 32
#define UI0902_SECTION_Y 224
#define UI0902_SECTION_H 35
#define UI0902_FONT_LABEL 11 /* 标注:移调/速度 Medium 11 */
#define UI0902_FONT_BODY 13 /* 曲目/音色正文、演奏段落 */
#define UI0902_FONT_HERO 16 /* 主值 C/88 与稿面大号一致 */
@ -67,31 +75,29 @@ void CallUI_RestoreSelect(void);
(sz) == 13 || (sz) == 15 ? 11 : \
(sz) == 16 ? 13 : ((sz) / 2 + 1))
/* 移调卡文字(主值加宽+下移 KEY,防 Cb/101 底/右裁切) */
#define UI0902_CARD_TEXT_CX_L (UI0902_MARGIN_X + UI0902_CARD_W / 2) /* 64 */
#define UI0902_CARD_TEXT_CX_R (UI0902_MARGIN_X + UI0902_CARD_W + UI0902_CARD_GAP + UI0902_CARD_W / 2) /* 176 */
#define UI0902_CARD_TEXT_CX_L (UI0902_CARD_X + UI0902_CARD_W / 2)
#define UI0902_CARD_TEXT_CX_R (UI0902_CARD_X + UI0902_CARD_W + UI0902_CARD_GAP + UI0902_CARD_W / 2)
#define UI0902_CARD_LABEL_SIZE UI0902_FONT_LABEL /* 11 */
#define UI0902_CARD_LABEL_LH 13
#define UI0902_CARD_LABEL_W 22
#define UI0902_CARD_LABEL_H 11
#define UI0902_CARD_LABEL_Y 54
#define UI0902_CARD_LABEL_Y 46
#define UI0902_CARD_VALUE_SIZE UI0902_FONT_HERO /* 16 */
#define UI0902_CARD_VALUE_LH 16
#define UI0902_CARD_VALUE_W 42 /* 3×13:101/Cb 完整 */
#define UI0902_CARD_VALUE_H 17
/* mode.png:主值≈y71–85,KEY/BPM≈y89;加大与「移调/速度」间距、收紧与 KEY/BPM */
#define UI0902_CARD_VALUE_Y 73
/* 仅主值字母/数字:相对基准右移、上移(三角/±/KEY/BPM 不动) */
#define UI0902_CARD_VALUE_OX 3
#define UI0902_CARD_VALUE_OY (-3)
/* 主值顶 = CTRL_CY - 字高/2,与左右三角、± 同一水平中线 */
#define UI0902_CARD_VALUE_Y (UI0902_CARD_CTRL_CY - UI0902_CARD_VALUE_SIZE / 2)
#define UI0902_CARD_VALUE_OX 0
#define UI0902_CARD_VALUE_OY 0
#define UI0902_CARD_SUB_SIZE UI0902_FONT_SUB /* 9 */
#define UI0902_CARD_SUB_LH 9
#define UI0902_CARD_SUB_W 32
#define UI0902_CARD_SUB_H 9
#define UI0902_CARD_SUB_Y 89
#define UI0902_CARD_SUB_Y 80
/* 段落钮与底栏分隔线(mode.png ≈ y274);颜色与顶栏共用 UI0902_SEP_LINE_COLOR */
#define UI0902_SEP_LINE_Y 274
@ -104,7 +110,7 @@ void CallUI_RestoreSelect(void);
#define UI0902_TAB_W 55
#define UI0902_TAB_GAP 6
#define UI0902_ROW_H 31
#define UI0902_SECTION_BTN_H 34
#define UI0902_SECTION_BTN_H 35
#define UI0902_SECTION_BTN_W 47
#define UI0902_SECTION_PITCH 57
#define UI0902_RADIUS_CARD 10
@ -124,26 +130,62 @@ void CallUI_RestoreSelect(void);
/* 0902 状态栏:左音量条 / 中蓝牙 / 右电池+百分比(对齐屏幕参考 0902-01) */
#define UI0902_VOL_X 8
#define UI0902_VOL_Y 3
#define UI0902_BT_W 11
#define UI0902_BT_H 17
/* 0923:开 13x20 / 关 19x20;擦除区取最大宽度并居中 */
#define UI0902_BT_ON_W 13
#define UI0902_BT_ON_H 20
#define UI0902_BT_OFF_W 19
#define UI0902_BT_OFF_H 20
#define UI0902_BT_W UI0902_BT_OFF_W
#define UI0902_BT_H UI0902_BT_OFF_H
#define UI0902_BT_X ((240 - UI0902_BT_W) / 2) /* 居中 */
#define UI0902_BT_Y 5
/* 状态栏蓝牙点击热区:略大于图标,便于点按 */
#define UI0902_BT_HIT_PAD_X 14
#define UI0902_BT_HIT_X0 ((UI0902_BT_X > UI0902_BT_HIT_PAD_X) \
? (uint16_t)(UI0902_BT_X - UI0902_BT_HIT_PAD_X) : 0)
#define UI0902_BT_HIT_X1 (uint16_t)(UI0902_BT_X + UI0902_BT_W + UI0902_BT_HIT_PAD_X - 1)
#define UI0902_BT_HIT_Y0 0
#define UI0902_BT_HIT_Y1 (uint16_t)(UI_STATUS_BAR_H + 2)
#define UI0902_BATTERY_W 29
#define UI0902_BATTERY_H 12
/* 0924 充电态:闪电电池图 40x13。外壳左壁在图内 x=11,内腔 x=14 起、宽 21 */
#define UI0902_BATTERY_CHG_W 40
#define UI0902_BATTERY_CHG_H 13
#define UI0902_BATTERY_CHG_FILL_DX 14
#define UI0902_BATTERY_CHG_FILL_DY 3
#define UI0902_BATTERY_CHG_FILL_MAX 21
#define UI0902_BATTERY_CHG_FILL_H 6
#define UI0902_BATTERY_CHG_FILL 0xDF04 /* 与闪电同色 RGB(217,224,33) */
/* 与音量/蓝牙大致居中后再下移 2px:12px 高 → 顶 y9 */
#define UI0902_BATTERY_Y 9
#define UI0902_BATTERY_RIGHT_MARGIN 6
#define UI0902_BATTERY_TEXT_GAP 2
#define UI0902_BATTERY_TEXT_SIZE 9 /* mode.png 百分比字号 ≈9,完整显示 % */
/* 0904 / 0902-11 设置入口:两大卡片 + 底栏「设置」高亮 */
#define UI0902_HUB_CARD_X 10
#define UI0902_HUB_CARD_W 220
#define UI0902_HUB_CARD_H 85
#define UI0902_HUB_CARD_Y0 67
#define UI0902_HUB_CARD_GAP 5
#define UI0902_HUB_CARD_Y1 (UI0902_HUB_CARD_Y0 + UI0902_HUB_CARD_H + UI0902_HUB_CARD_GAP) /* 157 */
#define UI0902_HUB_CARD_X 8
#define UI0902_HUB_CARD_W 223
#define UI0902_HUB_CARD_H 66
#define UI0902_HUB_CARD_Y0 48
#define UI0902_HUB_CARD_GAP 8
#define UI0902_HUB_CARD_Y1 (UI0902_HUB_CARD_Y0 + UI0902_HUB_CARD_H + UI0902_HUB_CARD_GAP) /* 122 */
#define UI0902_HUB_CARD_Y2 (UI0902_HUB_CARD_Y1 + UI0902_HUB_CARD_H + UI0902_HUB_CARD_GAP) /* 196 */
#define UI0902_HUB_FONT UI0902_FONT_HERO /* 16,与标题级统一 */
/* 0924 系统语言:两档大按钮 223x82 */
#define UI0902_LANG_BTN_X 8
#define UI0902_LANG_BTN_W 223
#define UI0902_LANG_BTN_H 82
#define UI0902_LANG_BTN_Y0 58
#define UI0902_LANG_BTN_GAP 10
#define UI0902_LANG_BTN_Y1 (UI0902_LANG_BTN_Y0 + UI0902_LANG_BTN_H + UI0902_LANG_BTN_GAP)
/* 0924 USB 确认:底部横排取消(灰)/确认(蓝) */
#define UI0902_USB_BTN_W 103
#define UI0902_USB_BTN_H 64
#define UI0902_USB_BTN_Y 236
#define UI0902_USB_BTN_XL 13
#define UI0902_USB_BTN_XR 124
/* 0904 / 0902-06·07·08 子页顶栏:返回用 调音台控件-1.png(30×24) */
#define UI0902_SUB_BACK_X 8
#define UI0902_SUB_BACK_Y 7
@ -154,12 +196,13 @@ void CallUI_RestoreSelect(void);
#define UI0902_SUB_SEP_Y 38
/* 0904 / 0902-07 系统设置四行(稿面行框 ≈x16 w207) */
#define UI0902_SET_ROW_X 16
#define UI0902_SET_ROW_W 207
#define UI0902_SET_ROW_H 58
#define UI0902_SET_ROW_Y0 51
#define UI0902_SET_ROW_PITCH 63
#define UI0902_SET_ROW_FONT UI0902_FONT_BODY /* 13 */
/* 与设置入口卡片同一套:x=8、宽 223、圆角 12、间距 8。四行排不下 66 高,改为 62。 */
#define UI0902_SET_ROW_X 8
#define UI0902_SET_ROW_W 223
#define UI0902_SET_ROW_H 62
#define UI0902_SET_ROW_Y0 42
#define UI0902_SET_ROW_PITCH 70
#define UI0902_SET_ROW_FONT UI0902_FONT_HERO
/* 0904 / 0902-08 恢复出厂:竖排确认(灰)/取消(蓝) */
#define UI0902_RESTORE_BTN_X 10
@ -173,19 +216,27 @@ void CallUI_RestoreSelect(void);
#define UI0902_NAV_EXPERT 2 /* 底栏:专业模式 */
#define UI0902_NAV_SETTING 3 /* 底栏:设置 */
#define UI0902_NAV_NONE 0xFF
/* 底栏触区:段落钮底(y264)之下四等分全宽,各 60×55 */
#define UI0902_NAV_Y0 265
#define UI0902_NAV_Y1 319
#define UI0902_NAV_W 60
#define UI0902_NAV_X0(i) ((uint16_t)((i) * UI0902_NAV_W))
#define UI0902_NAV_X1(i) ((uint16_t)((i) * UI0902_NAV_W + UI0902_NAV_W - 1))
/* 兼容旧名(已废弃三键:设置|调音台|模式) */
#define UI0902_NAV_MIXER UI0902_NAV_NORMAL
#define UI0902_NAV_MODE UI0902_NAV_EXPERT
/* 底部图标实际内容(生成脚本曾把 万能/普通/专业/设置 误命名为 Setting/Mixer/Mode) */
#define gImage_Nav_Universal_Not gImage_UI0902_TabSetting_Sel_36x28 /* 底部-10 白 */
#define gImage_Nav_Universal_Sel gImage_UI0902_TabMode_Sel_36x28 /* 底部-14 蓝 */
#define gImage_Nav_Normal_Not gImage_UI0902_TabSetting_Not_35x28 /* 底部-11 白 */
#define gImage_Nav_Normal_Sel gImage_UI0902_TabMode_Not_35x29 /* 底部-15 蓝 */
#define gImage_Nav_Expert_Not gImage_UI0902_TabMixer_Sel_35x27 /* 底部-12 白 */
#define gImage_Nav_Expert_Sel gImage_UI0902_TabBack_Sel_35x27 /* 底部-16 蓝 */
#define gImage_Nav_Setting_Not gImage_UI0902_TabMixer_Not_18x28 /* 底部-13 白 */
#define gImage_Nav_Setting_Sel gImage_UI0902_TabBack_Not_18x28 /* 底部-17 蓝 */
/* 0924 底栏:从图 K1_UI_0924-03/04/05 切出的放大图标+两字(万能/普通/专业/设置) */
#define gImage_Nav_Universal_Sel gImage_Nav0924_Universal_Sel_33x46
#define gImage_Nav_Universal_Not gImage_Nav0924_Universal_Not_33x46
#define gImage_Nav_Normal_Sel gImage_Nav0924_Normal_Sel_34x46
#define gImage_Nav_Normal_Not gImage_Nav0924_Normal_Not_34x46
#define gImage_Nav_Expert_Sel gImage_Nav0924_Expert_Sel_33x46
#define gImage_Nav_Expert_Not gImage_Nav0924_Expert_Not_33x46
#define gImage_Nav_Setting_Sel gImage_Nav0924_Setting_Sel_34x46
#define gImage_Nav_Setting_Not gImage_Nav0924_Setting_Not_34x46
#define UI0902_NAV_ICON_Y 264
#define UI0902_NAV_ICON_H 46
/* 旧几何电池(Draw_Battery_Icon)最左起点;0902 图电池用 Draw_Status_Battery_Icon */
#define UI_STATUS_BATTERY_X 150
#define UI_STATUS_BATTERY_H 11
@ -203,8 +254,12 @@ void Show_Battery_Icon(uint8_t flag);
void UI_DrawStatusSepLine(void);
void Show_BL_Icon(uint8_t value);
/* 状态栏蓝牙图标点击:开关电源、同步设置项与 NVM、刷新图标 */
void UI_StatusBar_ToggleBluetooth(void);
void Draw_Tab_Section_Menu(const LEBEL_UI *UI, TAB_SECTION_INDEX select_tab);
void UI_NavBar_Action(uint8_t value);
/* 设置入口及其子页:播放与物理键仍按进入前的模式,不点设置项 */
uint8_t UI_IsSettingsPage(void);
void Draw_Bottom_Bar(uint8_t sel, uint8_t first_back);
void UI_GotoCurrentModePage(void);
void GET_Num_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign);
@ -230,7 +285,16 @@ extern void RestoreSetting(void);
extern void Draw_System_Item_List(const LEBEL_UI *UI, GUI_SWITCH *Group);
/* 子页顶栏:左返回 + 居中标题(调音台/系统设置) */
extern void UI_DrawSubPageHeader(const uint8_t *title_gbk);
/* 系统设置顶栏:MiSans 标题 + 需求图返回箭头 */
extern void UI_DrawSystemSetHeader(void);
/* 节奏类型→1.bin / 本地曲目→2.bin / 万能→3.bin */
extern void UI_ApplyToneAddress(void);
extern void UI_ReloadTonePreset(void);
/* 开机/切曲目:万能与节奏套默认 BPM;本地曲目不改速度。键未变则不覆盖手调 */
void TrackBpm_Invalidate(void);
uint8_t TrackBpm_SyncGui(void);
uint16_t TrackBpm_Peek(void);
void TrackBpm_OnPresetLoaded(void);
/* 每次开机:蓝牙开、节奏/曲目/走向/段落回默认,并套当前曲目 BPM */
void Session_ApplyPowerOnDefaults(void);
#endif

78
UI/mixer_knob_0902.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef MIXER_KNOB_0902_H
#define MIXER_KNOB_0902_H
/* Doc/UI/调音台色块.zip 0902-31 24x23 方圆,透明角。a<128 为 0x0000。 */
#include <stdint.h>
#define MIXER_KNOB_ART_W 24
#define MIXER_KNOB_ART_H 23
static const uint8_t gImage_MixerKnob_24x23[1104] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,
0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,0x02,0x7A,
0x02,0x7A,0x02,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
#endif

View File

@ -231,6 +231,105 @@ AD85020B_StatusTypeDef AD85020B_I2C_Read(uint8_t reg, uint8_t *data)
return AD85020B_I2C_ReadImpl(reg, data);
}
static AD85020B_StatusTypeDef AD85020B_RamWaitClear(uint8_t mask)
{
uint8_t i;
uint8_t st;
for (i = 0U; i < 20U; i++)
{
if (AD85020B_I2C_Read(AD85020B_REG_CFRW, &st) != AD85020B_OK)
return AD85020B_ERROR;
if ((st & mask) == 0U)
return AD85020B_OK;
wk_delay_ms(1);
}
return AD85020B_TIMEOUT;
}
/* 样机抓包:0x1D 写完整 RAM 地址,0x2D bit6=RBS 选 bank。
Channel-1 = bank 0,Channel-2 = bank 1。 */
AD85020B_StatusTypeDef AD85020B_RamWrite24(uint8_t ram_addr, uint8_t bank, uint32_t value)
{
uint8_t cfrw;
if (AD85020B_I2C_Write(AD85020B_REG_CFA, ram_addr) != AD85020B_OK)
return AD85020B_ERROR;
if (AD85020B_I2C_Write(AD85020B_REG_A1_T, (uint8_t)((value >> 16) & 0xFFU)) != AD85020B_OK)
return AD85020B_ERROR;
if (AD85020B_I2C_Write(AD85020B_REG_A1_M, (uint8_t)((value >> 8) & 0xFFU)) != AD85020B_OK)
return AD85020B_ERROR;
if (AD85020B_I2C_Write(AD85020B_REG_A1_B, (uint8_t)(value & 0xFFU)) != AD85020B_OK)
return AD85020B_ERROR;
cfrw = (uint8_t)(AD85020B_CFRW_W1 | (bank ? AD85020B_CFRW_RBS : 0U));
if (AD85020B_I2C_Write(AD85020B_REG_CFRW, cfrw) != AD85020B_OK)
return AD85020B_ERROR;
return AD85020B_RamWaitClear(AD85020B_CFRW_W1);
}
AD85020B_StatusTypeDef AD85020B_RamRead24(uint8_t ram_addr, uint8_t bank, uint32_t *value)
{
uint8_t cfrw;
uint8_t hi, mid, lo;
if (value == 0)
return AD85020B_ERROR;
if (AD85020B_I2C_Write(AD85020B_REG_CFA, ram_addr) != AD85020B_OK)
return AD85020B_ERROR;
cfrw = (uint8_t)(AD85020B_CFRW_R1 | (bank ? AD85020B_CFRW_RBS : 0U));
if (AD85020B_I2C_Write(AD85020B_REG_CFRW, cfrw) != AD85020B_OK)
return AD85020B_ERROR;
if (AD85020B_RamWaitClear(AD85020B_CFRW_R1) != AD85020B_OK)
return AD85020B_TIMEOUT;
if (AD85020B_I2C_Read(AD85020B_REG_A1_T, &hi) != AD85020B_OK)
return AD85020B_ERROR;
if (AD85020B_I2C_Read(AD85020B_REG_A1_M, &mid) != AD85020B_OK)
return AD85020B_ERROR;
if (AD85020B_I2C_Read(AD85020B_REG_A1_B, &lo) != AD85020B_OK)
return AD85020B_ERROR;
*value = ((uint32_t)hi << 16) | ((uint32_t)mid << 8) | (uint32_t)lo;
return AD85020B_OK;
}
/* 样机 EQ 会留在功放 RAM 里,软复位清不掉。写回手册直通,恢复样机表之前的功放音色。
直通:A1/A2/B1/B2 = 0,A0 = 0x200000。覆盖两路 EQ1–EQ18。 */
static AD85020B_StatusTypeDef AD85020B_RestoreDefaultEq(void)
{
uint8_t bank;
uint8_t addr;
AD85020B_StatusTypeDef status;
for (bank = 0U; bank < 2U; bank++)
{
for (addr = 0x00U; addr <= 0x4AU; addr++)
{
status = AD85020B_RamWrite24(addr, bank,
((addr % 5U) == 4U) ? 0x200000UL : 0UL);
if (status != AD85020B_OK)
return status;
}
for (addr = 0xA0U; addr <= 0xAEU; addr++)
{
status = AD85020B_RamWrite24(addr, bank,
((addr % 5U) == 4U) ? 0x200000UL : 0UL);
if (status != AD85020B_OK)
return status;
}
}
return AD85020B_OK;
}
AD85020B_StatusTypeDef AD85020B_MasterMute(uint8_t mute)
{
AD85020B_I2C_Init();
return AD85020B_I2C_Write(AD85020B_REG_SCTL3,
mute ? AD85020B_SCTL3_MMUTE : 0x00);
}
/**
* @brief AD85020B 初始化
* @retval AD85020B_StatusTypeDef: 初始化结果
@ -249,9 +348,11 @@ AD85020B_StatusTypeDef AD85020B_Init(void)
if (status != AD85020B_OK) return status;
wk_delay_ms(20); // 等待复位完成(文档未明确,建议10~50ms)
/* 步骤3:复位后恢复正常模式(BIT5=1) */
/* 步骤3:复位后恢复正常模式(BIT5=1)。复位默认是不静音,立刻拉回主静音 */
status = AD85020B_I2C_Write(AD85020B_REG_SCTL6, AD85020B_SW_NORMAL);
if (status != AD85020B_OK) return status;
status = AD85020B_I2C_Write(AD85020B_REG_SCTL3, AD85020B_SCTL3_MMUTE);
if (status != AD85020B_OK) return status;
wk_delay_ms(10);
/* 步骤4:配置输入格式(文档SCTL1,默认I2S格式,0x00) */
@ -308,6 +409,9 @@ AD85020B_StatusTypeDef AD85020B_Init(void)
/* 写回直通 EQ。失败也要解除静音,否则拨片和琴弦无声 */
(void)AD85020B_RestoreDefaultEq();
/* 步骤6:解除静音(文档SCTL3,MMUTE=0,0x00) */
status = AD85020B_I2C_Write(AD85020B_REG_SCTL3, 0x00);
if (status != AD85020B_OK) return status;

View File

@ -37,9 +37,27 @@
#define AD85020B_REG_SCTL1 0x00 // 输入格式配置
#define AD85020B_REG_SCTL2 0x01 // 采样率配置
#define AD85020B_REG_SCTL3 0x02 // 静音控制
#define AD85020B_SCTL3_MMUTE 0x40 /* B6=1:主静音,退出时芯片做淡入 */
#define AD85020B_REG_MVOL 0x03 // 主音量控制
#define AD85020B_REG_HEADPHONEVOL 0x87 // 耳机音量控制
/* 系数 RAM 间接访问(手册 0x1D~0x2D)。CFA 按 8 位写入,RAM 图地址到 0xB0。 */
#define AD85020B_REG_CFA 0x1D /* CFA[7:0] RAM 基址 */
#define AD85020B_REG_A1_T 0x1E /* 系数 top [23:16] */
#define AD85020B_REG_A1_M 0x1F /* 系数 middle [15:8] */
#define AD85020B_REG_A1_B 0x20 /* 系数 bottom [7:0] */
#define AD85020B_REG_CFRW 0x2D /* CfRW 读写触发 */
#define AD85020B_CFRW_W1 0x01 /* 写单系数 */
#define AD85020B_CFRW_WA 0x02
#define AD85020B_CFRW_R1 0x04 /* 读单系数 */
#define AD85020B_CFRW_RA 0x08
#define AD85020B_CFRW_W3 0x10
#define AD85020B_CFRW_R3 0x20
#define AD85020B_CFRW_RBS 0x40 /* 0=bank0/CH1, 1=bank1/CH2 */
#define AD85020B_RAM_CH2_EQ16_A1 0xA0 /* CH2EQ16A1 */
#define AD85020B_RAM_CH2_EQ18_A0 0xAE /* CH2EQ18A0 */
/* 软件复位配置:SCTL6寄存器BIT5=SW_RSTB,0=复位,1=正常 */
#define AD85020B_SW_RESET 0x50 // BIT5=0(0x50二进制1010000,BIT5=0)
#define AD85020B_SW_NORMAL 0x70 // BIT5=1(复位后恢复正常)
@ -56,6 +74,9 @@ typedef enum
void AD85020B_I2C_Init(void);
AD85020B_StatusTypeDef AD85020B_I2C_Write(uint8_t reg, uint8_t data);
AD85020B_StatusTypeDef AD85020B_I2C_Read(uint8_t reg, uint8_t *data);
AD85020B_StatusTypeDef AD85020B_RamWrite24(uint8_t ram_addr, uint8_t bank, uint32_t value);
AD85020B_StatusTypeDef AD85020B_RamRead24(uint8_t ram_addr, uint8_t bank, uint32_t *value);
AD85020B_StatusTypeDef AD85020B_MasterMute(uint8_t mute);
AD85020B_StatusTypeDef AD85020B_Init(void);
#endif

View File

@ -1831,31 +1831,37 @@ static uint16_t LCD_BlendColor565(uint16_t c0, uint16_t c1, uint8_t num, uint8_t
}
/**
* @brief 绘制音量条(5格实心,从左到右亮度递增,对齐需求图)
* @param volume_level: 音量等级(0-5,0=静音,5=最大)
* @note 强度为 N 时显示前 N 格实心条;最右点亮格最亮(白),向左依次变暗
* @brief 绘制音量条(8格,左低右高,对齐 K1_UI_0923-05)
* @param volume_level: 音量等级(0-8,0=静音,8=最大)
* @note 强度为 N 时显示前 N 格;最右点亮格最亮(白),向左依次变暗
*/
void Draw_Volume_Bar(uint16_t x, uint16_t y, uint8_t volume_level,uint8_t scale,uint16_t color_on, uint16_t color_off)
{
uint8_t i;
uint8_t bar_count = 5;
uint8_t bar_count = 8;
uint8_t w = 3 * scale;
uint8_t gap = 2 * scale;
uint8_t radius = 1 * scale;
uint8_t height[5] = {6, 9, 12, 15, 18};
uint8_t max_h = height[4];
static const uint8_t height[8] = {5, 7, 9, 11, 12, 14, 16, 18};
uint8_t max_h = height[7];
uint16_t clear_w;
uint16_t dim_color = color_off;
uint16_t bar_x;
const uint8_t spk_w = 10;
const uint8_t spk_h = 15;
(void)color_on;
if(volume_level > 5)
if(volume_level > 8)
{
volume_level = 5;
volume_level = 8;
}
clear_w = (uint16_t)(w + gap) * bar_count - gap;
bar_x = (uint16_t)(x + spk_w + 2);
clear_w = (uint16_t)(spk_w + 2 + (w + gap) * bar_count - gap);
LCD_FillByColor(x, y, x + clear_w, y + max_h * scale, UI0902_BG_COLOR);
LCD_WR_PIC_Trans(x, (uint16_t)(y + (max_h * scale - spk_h) / 2),
spk_w, spk_h, gImage_UI0902_Speaker_10x15, BLACK);
if(volume_level == 0)
{
@ -1864,7 +1870,7 @@ void Draw_Volume_Bar(uint16_t x, uint16_t y, uint8_t volume_level,uint8_t scale,
for(i = 0; i < bar_count; i++)
{
uint16_t curr_x = x + (w + gap) * i;
uint16_t curr_x = bar_x + (w + gap) * i;
uint8_t curr_h = height[i] * scale;
uint8_t curr_y = y + (max_h * scale - curr_h);
uint16_t bar_color;

View File

@ -59,6 +59,7 @@ const char CHS8Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
};
@ -125,6 +126,7 @@ const char CHS9Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
};
@ -191,6 +193,9 @@ const char CHS11Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
{0xB8,0xFC}, // 更
{0xD0,0xC2}, // 新
};
@ -256,6 +261,7 @@ const char CHS12Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
};
@ -449,7 +455,10 @@ const char CHS13Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
{0xD3,0xEF}, // 语
{0xD1,0xD4}, // 言
};
@ -641,6 +650,7 @@ const char CHS15Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
};
@ -837,7 +847,10 @@ const char CHS16Table[][2] = {
{0xC0,0xAB}, // 阔
{0xCC,0xEC}, // 天
{0xBF,0xD5}, // 空
{0xB1,0xD5}, // 闭
{0xD3,0xEF}, // 语
{0xD1,0xD4}, // 言
};
@ -871,6 +884,7 @@ const char CHS24Table[][2] = {
{0xB6, 0xA8},// 认
{0xB7, 0xD6},// 分
{0xD6, 0xD3},// 钟
{0xB1,0xD5}, // 闭
};
@ -930,6 +944,7 @@ const unsigned char Chinese_font_8[][8] = {
{0x1F,0x41,0x89,0x89,0xA9,0xDD,0xD7,0xC1},/*"阔",52*/
{0x7E,0x00,0x00,0xFF,0x18,0x00,0x00,0x81},/*"天",53*/
{0x18,0x41,0x00,0x00,0x3C,0x00,0x00,0x7F},/*"空",54*/
{0x4F,0x01,0x89,0xBD,0x99,0xA9,0x89,0x83},/*"闭",55*/
};
const unsigned char Chinese_font_12[][24] = {
@ -993,6 +1008,7 @@ const unsigned char Chinese_font_12[][24] = {
{0x4F,0xE0,0x20,0x20,0xA1,0xA0,0x96,0x20,0xC2,0x20,0xAF,0xA0,0x92,0x20,0xAF,0xA0,0xE8,0xA0,0xAF,0xA0,0xA0,0x60,0x00,0x00},/*"阔",57*/
{0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0xC0,0x60,0x00,0x00},/*"天",58*/
{0x04,0x00,0x7F,0xE0,0x40,0x20,0x89,0x00,0x10,0x80,0x60,0x40,0x1F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xE0,0x00,0x00},/*"空",59*/
{0x47,0xE0,0x20,0x20,0x82,0x20,0x82,0x20,0xBF,0xA0,0x86,0x20,0x8A,0x20,0x92,0x20,0xA2,0x20,0x86,0x20,0x80,0xE0,0x00,0x00},/*"闭",60*/
};
const unsigned char Chinese_font_9[][18] = {
@ -1058,6 +1074,7 @@ const unsigned char Chinese_font_9[][18] = {
{0x5F,0x80,0x00,0x80,0x84,0x80,0x84,0x80,0x9E,0x80,0xA4,0x80,0xDE,0x80,0xDE,0x80,0x81,0x80},/*"阔",59*/
{0x7F,0x00,0x08,0x00,0x08,0x00,0xFF,0x80,0x08,0x00,0x14,0x00,0x14,0x00,0x00,0x00,0xC1,0x80},/*"天",60*/
{0x08,0x00,0x7F,0x80,0x80,0x00,0x00,0x00,0x41,0x00,0x1E,0x00,0x08,0x00,0x08,0x00,0x7F,0x80},/*"空",61*/
{0x4F,0x80,0x00,0x80,0x84,0x80,0xBE,0x80,0x8C,0x80,0x94,0x80,0xA4,0x80,0x8C,0x80,0x81,0x80},/*"闭",62*/
};
const unsigned char Chinese_font_11[][22] = {
@ -1123,6 +1140,9 @@ const unsigned char Chinese_font_11[][22] = {
{0x4F,0xE0,0x20,0x20,0xA1,0xA0,0x96,0x20,0xC2,0x20,0xAF,0xA0,0x92,0x20,0xAF,0xA0,0xE8,0xA0,0xAF,0xA0,0xA0,0x60},/*"阔",59*/
{0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0xC0,0x60},/*"天",60*/
{0x04,0x00,0x7F,0xE0,0x40,0x20,0x89,0x00,0x10,0x80,0x60,0x40,0x1F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xE0},/*"空",61*/
{0x47,0xE0,0x20,0x20,0x82,0x20,0x82,0x20,0xBF,0xA0,0x86,0x20,0x8A,0x20,0x92,0x20,0xA2,0x20,0x86,0x20,0x80,0xE0},/*"闭",62*/
{0x7F,0xE0,0x02,0x00,0x3F,0xC0,0x22,0x40,0x3F,0xC0,0x22,0x40,0x3F,0xC0,0x0A,0x00,0x04,0x00,0x1B,0x00,0xE0,0xE0},/*"更",63*/
{0x10,0x60,0xFD,0x80,0x45,0x00,0x29,0x00,0xFD,0xE0,0x11,0x40,0xFD,0x40,0x11,0x40,0x55,0x40,0x92,0x40,0x34,0x40},/*"新",64*/
};
@ -1320,6 +1340,10 @@ const unsigned char Chinese_font_13[][26] = {
{0x4F,0xE0,0x20,0x20,0xA1,0xA0,0x96,0x20,0xC2,0x20,0xAF,0xA0,0x92,0x20,0xAF,0xA0,0xE8,0xA0,0xAF,0xA0,0xA8,0xA0,0x80,0x60,0x00,0x00},/*"阔",186*/
{0x7F,0xE0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xF0,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x10,0x80,0x20,0x40,0xC0,0x30,0x00,0x00},/*"天",187*/
{0x04,0x00,0xFF,0xE0,0x80,0x20,0x91,0x20,0x20,0x80,0xC0,0x40,0x3F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x00,0x00},/*"空",188*/
{0x4F,0xE0,0x20,0x20,0x42,0x20,0x42,0x20,0x7F,0xA0,0x42,0x20,0x46,0x20,0x4A,0x20,0x52,0x20,0x62,0x20,0x46,0x20,0x40,0x60,0x00,0x00},/*"闭",189*/
{0x00,0x00,0x27,0xE0,0x37,0xE0,0x13,0x00,0x07,0xE0,0x73,0x60,0x3F,0xF0,0x33,0xC0,0x37,0xE0,0x3C,0x20,0x37,0xE0,0x27,0xE0,0x00,0x00},/*"语",190*/
{0x00,0x00,0x02,0x00,0x7F,0xF0,0x7F,0xF0,0x3F,0xE0,0x1F,0xC0,0x3F,0xE0,0x1F,0xC0,0x3F,0xE0,0x30,0x60,0x3F,0xE0,0x30,0x60,0x00,0x00},/*"言",191*/
};
@ -1514,6 +1538,7 @@ const unsigned char Chinese_font_15[][30] = {
{0x20,0x08,0x1B,0xFC,0x08,0x08,0x50,0x68,0x4B,0x88,0x40,0x88,0x57,0xF8,0x48,0x88,0x4B,0xE8,0x5A,0x28,0x4A,0x28,0x4B,0xE8,0x4A,0x28,0x40,0x18,0x00,0x00},/*"阔",184*/
{0x00,0x00,0x3F,0xF0,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFF,0xFC,0x02,0x00,0x05,0x00,0x04,0x80,0x08,0x40,0x10,0x20,0x20,0x1C,0xC0,0x08,0x00,0x00},/*"天",185*/
{0x04,0x00,0x02,0x00,0x7F,0xF8,0x40,0x10,0x88,0x80,0x10,0x40,0x20,0x20,0x40,0x10,0x3F,0xE0,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFF,0xF8,0x00,0x00},/*"空",186*/
{0x20,0x00,0x1B,0xF8,0x08,0x08,0x40,0x88,0x40,0x88,0x5F,0xE8,0x40,0x88,0x41,0x88,0x42,0x88,0x44,0x88,0x48,0x88,0x43,0x88,0x40,0x28,0x40,0x10,0x00,0x00},/*"闭",187*/
};
const unsigned char Chinese_font_16[][32] = {
@ -1707,6 +1732,10 @@ const unsigned char Chinese_font_16[][32] = {
{0x20,0x00,0x17,0xFC,0x00,0x04,0x48,0x34,0x45,0xC4,0x64,0x44,0x50,0x44,0x51,0xF4,0x44,0x44,0x48,0x44,0x79,0xF4,0x49,0x14,0x49,0x14,0x49,0xF4,0x40,0x04,0x40,0x0C},/*"阔",187*/
{0x00,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0xFE,0x01,0x00,0x02,0x80,0x02,0x80,0x04,0x40,0x04,0x40,0x08,0x20,0x10,0x10,0x20,0x08,0xC0,0x06},/*"天",188*/
{0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x88,0x24,0x10,0x10,0x20,0x08,0x00,0x00,0x1F,0xF0,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x7F,0xFC,0x00,0x00},/*"空",189*/
{0x20,0x00,0x17,0xFC,0x00,0x04,0x40,0x84,0x40,0x84,0x5F,0xF4,0x40,0x84,0x41,0x84,0x42,0x84,0x44,0x84,0x48,0x84,0x50,0x84,0x42,0x84,0x41,0x04,0x40,0x14,0x40,0x08},/*"闭",190*/
{0x67,0xFE,0x77,0xFE,0x30,0xC0,0x13,0xFC,0x07,0xFC,0xE1,0x8C,0xE1,0x8C,0x2F,0xFF,0x27,0xFF,0x20,0x00,0x23,0xFE,0x2B,0x06,0x3F,0x06,0x7B,0xFE,0x73,0xFE,0x03,0x06},/*"语",191*/
{0x01,0x80,0x01,0xC0,0xFF,0xFF,0x00,0x00,0x3F,0xFC,0x3F,0xFC,0x00,0x00,0x3F,0xFC,0x3F,0xFC,0x00,0x00,0x3F,0xFC,0x3F,0xFC,0x20,0x04,0x34,0x2C,0x3F,0xFC,0x30,0x0C},/*"言",192*/
};
const unsigned char Chinese_font_24[][72] = {
@ -1739,6 +1768,7 @@ const unsigned char Chinese_font_24[][72] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x28,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"认",26*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x3C,0x00,0x00,0x14,0x00,0x00,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"分",27*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"钟",28*/
{0x18,0x00,0x00,0x18,0x00,0x00,0x04,0xFF,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x20,0x0C,0x08,0x20,0x0C,0x08,0x20,0x0C,0x08,0x27,0xFF,0xC8,0x20,0x0C,0x08,0x20,0x0C,0x08,0x20,0x1C,0x08,0x20,0x6C,0x08,0x20,0x6C,0x08,0x20,0x8C,0x08,0x23,0x0C,0x08,0x23,0x0C,0x08,0x24,0x0C,0x08,0x20,0x6C,0x08,0x20,0x6C,0x08,0x20,0x10,0x08,0x20,0x00,0x48,0x20,0x00,0x48,0x20,0x00,0x30},/*"闭",29*/
};

View File

@ -104,101 +104,101 @@ const unsigned char ascii_1306[][13]={
const unsigned char ascii_1608[][32]={
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
{0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x48,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/
{0x00,0x00,0x00,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0xFF,0x01,0x44,0x00,0x44,0x00,0x44,0x00,0xFF,0x01,0x22,0x00,0x22,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"#",3*/
{0x00,0x00,0x10,0x00,0x7C,0x00,0x96,0x00,0x12,0x00,0x12,0x00,0x14,0x00,0x38,0x00,0x50,0x00,0x90,0x00,0x90,0x00,0x92,0x00,0x7C,0x00,0x10,0x00,0x00,0x00,0x00,0x00},/*"$",4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0x00,0x89,0x00,0x49,0x00,0x29,0x00,0x96,0x01,0x50,0x02,0x48,0x02,0x44,0x02,0xC4,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"%",5*/
{0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x44,0x00,0x24,0x00,0x14,0x00,0x8A,0x00,0x91,0x00,0x51,0x00,0x61,0x00,0x61,0x00,0x9E,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"&",6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
{0x40,0x00,0x20,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x00,0x00},/*"(",8*/
{0x08,0x00,0x10,0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x00,0x00},/*")",9*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x7C,0x00,0x10,0x00,0x28,0x00,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"*",10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0xFE,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"+",11*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"-",13*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/
{0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00},/*"/",15*/
{0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"0",16*/
{0x00,0x00,0x00,0x00,0x18,0x00,0x14,0x00,0x12,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/
{0x00,0x00,0x00,0x00,0x3C,0x00,0x42,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x18,0x00,0x04,0x00,0x02,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/
{0x00,0x00,0x00,0x00,0x3C,0x00,0x42,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x80,0x00,0x80,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/
{0x00,0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x50,0x00,0x48,0x00,0x48,0x00,0x44,0x00,0x42,0x00,0xFE,0x01,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"4",20*/
{0x00,0x00,0x00,0x00,0xFE,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x3A,0x00,0x46,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/
{0x00,0x00,0x00,0x00,0x78,0x00,0x84,0x00,0x02,0x00,0x02,0x00,0x3A,0x00,0x46,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"6",22*/
{0x00,0x00,0x00,0x00,0xFE,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"7",23*/
{0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"8",24*/
{0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0xC4,0x00,0xB8,0x00,0x80,0x00,0x80,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"9",25*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/
{0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x70,0x00,0x0C,0x00,0x02,0x00,0x0E,0x00,0x70,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"<",28*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"=",29*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x1C,0x00,0x60,0x00,0x80,0x00,0x60,0x00,0x1C,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*">",30*/
{0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"?",31*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x04,0x01,0xB2,0x02,0xC9,0x02,0x45,0x02,0x45,0x02,0x65,0x02,0x99,0x01,0x02,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"@",32*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x48,0x00,0x48,0x00,0x84,0x00,0xFC,0x00,0x02,0x01,0x02,0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"A",33*/
{0x00,0x00,0x00,0x00,0xFF,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"B",34*/
{0x00,0x00,0x00,0x00,0xF8,0x00,0x06,0x01,0x02,0x02,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x02,0x02,0x06,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"C",35*/
{0x00,0x00,0x00,0x00,0x7F,0x00,0x81,0x01,0x01,0x01,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x01,0x81,0x01,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"D",36*/
{0x00,0x00,0x00,0x00,0xFF,0x01,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"E",37*/
{0x00,0x00,0x00,0x00,0xFE,0x01,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFE,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"F",38*/
{0x00,0x00,0x00,0x00,0xF8,0x00,0x06,0x01,0x02,0x02,0x01,0x00,0x01,0x00,0x01,0x00,0xC1,0x03,0x01,0x02,0x02,0x02,0x06,0x03,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"G",39*/
{0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"H",40*/
{0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/
{0x00,0x00,0x00,0x00,0xE0,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x84,0x00,0x84,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"J",42*/
{0x00,0x00,0x00,0x00,0x81,0x00,0x41,0x00,0x21,0x00,0x11,0x00,0x09,0x00,0x17,0x00,0x21,0x00,0x41,0x00,0x81,0x00,0x01,0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"K",43*/
{0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"L",44*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x03,0x03,0x03,0x85,0x02,0x85,0x02,0x49,0x02,0x49,0x02,0x31,0x02,0x31,0x02,0x31,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"M",45*/
{0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x01,0x05,0x01,0x09,0x01,0x09,0x01,0x11,0x01,0x21,0x01,0x21,0x01,0x41,0x01,0x81,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"N",46*/
{0x00,0x00,0x00,0x00,0x78,0x00,0x86,0x01,0x02,0x01,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x02,0x01,0x86,0x01,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"O",47*/
{0x00,0x00,0x00,0x00,0x7F,0x00,0x81,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"P",48*/
{0x00,0x00,0x78,0x00,0x86,0x01,0x02,0x01,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x01,0x02,0x02,0x01,0x86,0x01,0x78,0x00,0x20,0x00,0x40,0x00,0x80,0x01,0x00,0x00},/*"Q",49*/
{0x00,0x00,0x00,0x00,0xFF,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0x00,0x11,0x00,0x21,0x00,0x41,0x00,0x81,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"R",50*/
{0x00,0x00,0x00,0x00,0x7C,0x00,0x82,0x00,0x01,0x01,0x01,0x00,0x06,0x00,0x78,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x82,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"S",51*/
{0x00,0x00,0x00,0x00,0xFF,0x01,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"T",52*/
{0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x82,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"U",53*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x01,0x02,0x01,0x84,0x00,0x84,0x00,0x48,0x00,0x48,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"V",54*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x31,0x02,0x00,0x00,0x48,0x00,0x86,0x01,0x86,0x01,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"W",55*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x01,0x84,0x00,0x48,0x00,0x30,0x00,0x30,0x00,0x48,0x00,0x84,0x00,0x02,0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"X",56*/
{0x00,0x00,0x00,0x00,0x01,0x01,0x82,0x00,0x44,0x00,0x44,0x00,0x28,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Y",57*/
{0x00,0x00,0x00,0x00,0xFE,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Z",58*/
{0x38,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x38,0x00,0x00,0x00},/*"[",59*/
{0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00},/*"\",60*/
{0x38,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x38,0x00,0x00,0x00},/*"]",61*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x28,0x00,0x28,0x00,0x44,0x00,0x44,0x00,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"_",63*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xC2,0x00,0x80,0x00,0x80,0x00,0xFC,0x00,0x82,0x00,0x82,0x00,0xC2,0x00,0x3C,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"a",65*/
{0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x3A,0x00,0x46,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x46,0x00,0x3A,0x00,0x00,0x00,0x00,0x00},/*"b",66*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x88,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x88,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/
{0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xB8,0x00,0xC4,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0xC4,0x00,0xB8,0x00,0x00,0x00,0x00,0x00},/*"d",68*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x82,0x00,0xFE,0x00,0x02,0x00,0x02,0x00,0x84,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"e",69*/
{0x00,0x00,0x00,0x00,0x60,0x00,0x10,0x00,0x10,0x00,0x78,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00},/*"f",70*/
{0x00,0x00,0x00,0x00,0xB8,0x00,0xC4,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0xC4,0x00,0xB8,0x00,0x80,0x00,0x42,0x00,0x3C,0x00,0x00,0x00,0x00,0x00},/*"g",71*/
{0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x74,0x00,0x8C,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x00,0x00,0x00,0x00},/*"h",72*/
{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00},/*"i",73*/
{0x20,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x00,0x00},/*"j",74*/
{0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x42,0x00,0x22,0x00,0x12,0x00,0x0A,0x00,0x0E,0x00,0x12,0x00,0x22,0x00,0x42,0x00,0x82,0x00,0x00,0x00,0x00,0x00},/*"k",75*/
{0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00},/*"l",76*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDD,0x01,0x33,0x02,0x31,0x02,0x31,0x02,0x31,0x02,0x31,0x02,0x31,0x02,0x31,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"m",77*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x00,0x8C,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"n",78*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x44,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"o",79*/
{0x00,0x00,0x00,0x00,0x3A,0x00,0x46,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x46,0x00,0x3A,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/*"p",80*/
{0x00,0x00,0x00,0x00,0xB8,0x00,0xC4,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0xC4,0x00,0xB8,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00},/*"q",81*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x18,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"r",82*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x84,0x00,0x04,0x00,0x04,0x00,0x78,0x00,0x80,0x00,0x80,0x00,0x84,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"s",83*/
{0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x78,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0xC4,0x00,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"u",85*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x44,0x00,0x44,0x00,0x28,0x00,0x28,0x00,0x28,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"v",86*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x11,0x01,0x29,0x01,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0x44,0x00,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"w",87*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x44,0x00,0x44,0x00,0x28,0x00,0x10,0x00,0x28,0x00,0x4C,0x00,0x44,0x00,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"x",88*/
{0x00,0x00,0x00,0x00,0x82,0x00,0x82,0x00,0x44,0x00,0x44,0x00,0x44,0x00,0x28,0x00,0x28,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x06,0x00,0x00,0x00,0x00,0x00},/*"y",89*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"z",90*/
{0x60,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x0C,0x00,0x18,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x60,0x00,0x00,0x00},/*"{",91*/
{0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00},/*"|",92*/
{0x0C,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x60,0x00,0x30,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x0C,0x00,0x00,0x00},/*"}",93*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x92,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*1*/
{0x00,0x00,0x48,0x00,0x78,0x00,0x78,0x00,0x48,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x00,0x98,0x00,0xD8,0x00,0xFE,0x03,0xCC,0x00,0x4C,0x00,0xFE,0x01,0xFF,0x01,0x64,0x00,0x64,0x00,0x26,0x00,0x00,0x00,0x00,0x00},/*3*/
{0x00,0x00,0x00,0x00,0x30,0x00,0x78,0x00,0xFC,0x00,0x86,0x00,0x06,0x00,0x1C,0x00,0xF8,0x00,0xE0,0x01,0x80,0x01,0xC6,0x01,0xFC,0x00,0x78,0x00,0x30,0x00,0x00,0x00},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0x01,0xCB,0x00,0xC9,0x00,0x6F,0x00,0x26,0x00,0x30,0x00,0xD8,0x01,0x58,0x03,0x4C,0x02,0xC4,0x03,0x86,0x01,0x00,0x00,0x00,0x00},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x7E,0x00,0xC6,0x00,0x0E,0x00,0x0C,0x00,0x9E,0x01,0xBF,0x01,0xF3,0x01,0xE3,0x00,0xFE,0x01,0xBE,0x03,0x00,0x00,0x00,0x00},/*6*/
{0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*7*/
{0x00,0x00,0x00,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x20,0x00,0x00,0x00},/*8*/
{0x00,0x00,0x00,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x20,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x00,0x00},/*9*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0xFC,0x00,0xFE,0x01,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*11*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x20,0x00,0x30,0x00},/*12*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*13*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*14*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x08,0x00,0x00,0x00,0x00,0x00},/*15*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0xFC,0x00,0xCE,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0xCE,0x00,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*16*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x78,0x00,0x78,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00},/*17*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xFC,0x00,0xC4,0x00,0xC0,0x00,0xC0,0x00,0xE0,0x00,0x70,0x00,0x38,0x00,0x1C,0x00,0xFE,0x01,0xFE,0x01,0x00,0x00,0x00,0x00},/*18*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x00,0x60,0x00,0x30,0x00,0x78,0x00,0xF8,0x00,0xC0,0x01,0x80,0x01,0xCC,0x01,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*19*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0xF0,0x00,0xF8,0x00,0xD8,0x00,0xDC,0x00,0xCC,0x00,0xCE,0x00,0xFE,0x01,0xFE,0x01,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00},/*20*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x00,0x0C,0x00,0x0C,0x00,0xFC,0x00,0xFE,0x00,0xC0,0x01,0x80,0x01,0xC4,0x01,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*21*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x18,0x00,0x1C,0x00,0xFC,0x00,0xFE,0x00,0xC6,0x01,0x86,0x01,0xCE,0x01,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*22*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0xFE,0x00,0xC0,0x00,0xE0,0x00,0x60,0x00,0x70,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x00,0x00,0x00,0x00},/*23*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x00,0xCE,0x01,0xCC,0x00,0xFC,0x00,0xFC,0x00,0xCE,0x01,0x86,0x01,0xC6,0x01,0xFE,0x00,0x7C,0x00,0x00,0x00,0x00,0x00},/*24*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xFE,0x00,0xC6,0x01,0x86,0x01,0xCE,0x01,0xFC,0x00,0xFC,0x00,0x60,0x00,0x70,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0x00,0x00},/*25*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*26*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x20,0x00,0x30,0x00},/*27*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0xE0,0x01,0xF8,0x00,0x3C,0x00,0x0E,0x00,0x3C,0x00,0xF0,0x00,0xC0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*28*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0xFC,0x00,0x00,0x00,0xFC,0x00,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*29*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x1E,0x00,0x7C,0x00,0xF0,0x00,0xC0,0x01,0xF0,0x00,0x3C,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*30*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xFC,0x00,0xCC,0x00,0xC0,0x00,0x60,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*31*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0x86,0x01,0x02,0x03,0xFB,0x02,0xC9,0x02,0xCD,0x02,0xF9,0x03,0xBB,0x01,0x02,0x00,0x8E,0x00,0xF8,0x00,0x00,0x00,0x00,0x00},/*32*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0xCC,0x00,0xCC,0x00,0xFC,0x00,0xFE,0x01,0x86,0x01,0x87,0x03,0x03,0x03,0x00,0x00,0x00,0x00},/*33*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0xFE,0x00,0xC6,0x01,0xC6,0x01,0xFE,0x00,0xFE,0x00,0xC6,0x01,0x86,0x01,0xC6,0x01,0xFE,0x01,0x7E,0x00,0x00,0x00,0x00,0x00},/*34*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xFC,0x01,0x8E,0x01,0x06,0x00,0x07,0x00,0x07,0x00,0x06,0x00,0x06,0x00,0x8E,0x01,0xFC,0x01,0xF8,0x00,0x00,0x00,0x00,0x00},/*35*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0xFF,0x00,0xC3,0x01,0x83,0x01,0x83,0x03,0x83,0x03,0x83,0x01,0x83,0x01,0xC3,0x01,0xFF,0x00,0x3F,0x00,0x00,0x00,0x00,0x00},/*36*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0xFE,0x00,0x0E,0x00,0x0E,0x00,0xFE,0x00,0xFE,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0xFE,0x01,0xFE,0x01,0x00,0x00,0x00,0x00},/*37*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0xFE,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0xFE,0x00,0xFE,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0C,0x00,0x00,0x00,0x00,0x00},/*38*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xFC,0x01,0x8E,0x01,0x06,0x00,0x07,0x00,0xE7,0x03,0xE7,0x03,0x06,0x03,0x8E,0x03,0xFC,0x01,0xF8,0x00,0x00,0x00,0x00,0x00},/*39*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x03,0x87,0x03,0x87,0x03,0x87,0x03,0xFF,0x03,0xFF,0x03,0x87,0x03,0x87,0x03,0x87,0x03,0x87,0x03,0x86,0x01,0x00,0x00,0x00,0x00},/*40*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*41*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xCC,0x00,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*42*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xC7,0x01,0xE7,0x00,0x77,0x00,0x3F,0x00,0x1F,0x00,0x1F,0x00,0x3F,0x00,0x77,0x00,0xE7,0x00,0xC7,0x01,0x83,0x01,0x00,0x00,0x00,0x00},/*43*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0xFE,0x01,0xFE,0x01,0x00,0x00,0x00,0x00},/*44*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x87,0x03,0x87,0x03,0xCF,0x03,0xCF,0x03,0x7B,0x03,0x7B,0x03,0x33,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x00,0x00,0x00,0x00},/*45*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x01,0x8F,0x01,0x8F,0x01,0x9F,0x01,0xBF,0x01,0xB7,0x01,0xF7,0x01,0xE7,0x01,0xC7,0x01,0xC7,0x01,0x86,0x01,0x00,0x00,0x00,0x00},/*46*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFE,0x01,0x86,0x01,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x87,0x03,0x86,0x01,0xFE,0x01,0x78,0x00,0x00,0x00,0x00,0x00},/*47*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0xFE,0x00,0xC6,0x01,0x86,0x01,0xC6,0x01,0xFE,0x00,0x7E,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00},/*48*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFE,0x01,0x86,0x01,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x87,0x03,0x86,0x01,0xFE,0x01,0xF8,0x03,0x00,0x01,0x00,0x00},/*49*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0xFE,0x00,0xC6,0x01,0xC6,0x01,0xC6,0x01,0xFE,0x00,0x7E,0x00,0x66,0x00,0xE6,0x00,0xC6,0x00,0x86,0x01,0x00,0x00,0x00,0x00},/*50*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x01,0x86,0x00,0x0E,0x00,0x3C,0x00,0xF8,0x00,0xC0,0x01,0x80,0x01,0x86,0x01,0xFE,0x01,0xF8,0x00,0x00,0x00,0x00,0x00},/*51*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0xFE,0x01,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*52*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0x86,0x01,0xC6,0x01,0xFE,0x00,0x7C,0x00,0x00,0x00,0x00,0x00},/*53*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x86,0x01,0x86,0x01,0x86,0x01,0xCC,0x00,0xCC,0x00,0xCC,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*54*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x03,0x33,0x03,0x33,0x03,0x32,0x01,0x7A,0x01,0x6A,0x01,0xCE,0x01,0xCE,0x01,0xCC,0x00,0xCC,0x00,0x84,0x00,0x00,0x00,0x00,0x00},/*55*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x01,0xCE,0x01,0xEC,0x00,0x78,0x00,0x78,0x00,0x38,0x00,0x78,0x00,0xEC,0x00,0xCE,0x00,0xC6,0x01,0x87,0x03,0x00,0x00,0x00,0x00},/*56*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x03,0x86,0x01,0xCC,0x00,0xCC,0x00,0x78,0x00,0x78,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*57*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0xFE,0x01,0xC0,0x00,0x60,0x00,0x70,0x00,0x38,0x00,0x18,0x00,0x1C,0x00,0x0E,0x00,0xFE,0x01,0xFE,0x01,0x00,0x00,0x00,0x00},/*58*/
{0x00,0x00,0x00,0x00,0x78,0x00,0x78,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x78,0x00,0x78,0x00,0x00,0x00},/*59*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x40,0x00,0x00,0x00,0x00,0x00},/*60*/
{0x00,0x00,0x00,0x00,0x78,0x00,0x78,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x78,0x00,0x38,0x00,0x00,0x00},/*61*/
{0x00,0x00,0x00,0x00,0x30,0x00,0x78,0x00,0x48,0x00,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*62*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00},/*63*/
{0x00,0x00,0x00,0x00,0x10,0x00,0x30,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*64*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xCC,0x00,0xC0,0x00,0xF8,0x00,0xFC,0x00,0xCC,0x00,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,0x00},/*65*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0xFE,0x00,0xFE,0x00,0xC6,0x01,0x86,0x01,0x86,0x01,0xCE,0x01,0xFE,0x00,0x76,0x00,0x00,0x00,0x00,0x00},/*66*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xFC,0x00,0x0C,0x00,0x0E,0x00,0x0E,0x00,0x8C,0x00,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*67*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0xFC,0x01,0xFC,0x01,0xCE,0x01,0x86,0x01,0x86,0x01,0xCE,0x01,0xFC,0x01,0xB8,0x01,0x00,0x00,0x00,0x00},/*68*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0xCC,0x00,0x8E,0x01,0xFE,0x01,0xFE,0x00,0x0E,0x00,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*69*/
{0x00,0x00,0x00,0x00,0x60,0x00,0xF0,0x00,0x30,0x00,0x38,0x00,0xFC,0x00,0x78,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x10,0x00,0x00,0x00,0x00,0x00},/*70*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0xFC,0x01,0xCE,0x01,0x86,0x01,0x86,0x01,0xCE,0x01,0xFC,0x01,0xB8,0x01,0x80,0x01,0xCC,0x00},/*71*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0xFE,0x00,0xFE,0x00,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0x84,0x00,0x00,0x00,0x00,0x00},/*72*/
{0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*73*/
{0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x70,0x00},/*74*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0xE6,0x00,0x76,0x00,0x3E,0x00,0x1E,0x00,0x3E,0x00,0x76,0x00,0xE6,0x00,0xC6,0x00,0x00,0x00,0x00,0x00},/*75*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*76*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDF,0x01,0xFF,0x03,0x33,0x03,0x33,0x03,0x33,0x03,0x33,0x03,0x33,0x03,0x33,0x03,0x00,0x00,0x00,0x00},/*77*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0xFE,0x00,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0x84,0x00,0x00,0x00,0x00,0x00},/*78*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x00,0xCE,0x01,0x86,0x01,0x86,0x01,0xCE,0x01,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*79*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0xFE,0x00,0xC6,0x01,0x86,0x01,0x86,0x01,0xCE,0x01,0xFE,0x00,0x76,0x00,0x06,0x00,0x06,0x00},/*80*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0xFC,0x01,0xCE,0x01,0x86,0x01,0x86,0x01,0xCE,0x01,0xFC,0x01,0xB8,0x01,0x80,0x01,0x80,0x01},/*81*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0x7C,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x08,0x00,0x00,0x00,0x00,0x00},/*82*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xEC,0x00,0x0C,0x00,0x7C,0x00,0xF0,0x00,0xC0,0x00,0xFC,0x00,0x78,0x00,0x00,0x00,0x00,0x00},/*83*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x38,0x00,0x38,0x00,0xFC,0x00,0x7C,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x70,0x00,0xF0,0x00,0x00,0x00,0x00,0x00},/*84*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xCE,0x01,0xFC,0x01,0xFC,0x00,0x00,0x00,0x00,0x00},/*85*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x01,0xCE,0x01,0xCC,0x00,0xCC,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*86*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x03,0x33,0x03,0x32,0x01,0xFA,0x01,0xCE,0x01,0xCE,0x01,0xCC,0x00,0xCC,0x00,0x00,0x00,0x00,0x00},/*87*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCC,0x00,0xDC,0x00,0x78,0x00,0x30,0x00,0x78,0x00,0x78,0x00,0xCC,0x00,0xCE,0x01,0x00,0x00,0x00,0x00},/*88*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x01,0xCE,0x01,0xCC,0x00,0xCC,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x30,0x00,0x30,0x00,0x18,0x00},/*89*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x00,0x60,0x00,0x70,0x00,0x38,0x00,0x1C,0x00,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,0x00},/*90*/
{0x00,0x00,0x00,0x00,0xE0,0x00,0x70,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x38,0x00,0x1C,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x70,0x00,0xE0,0x00,0x00,0x00,0x00,0x00},/*91*/
{0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00},/*92*/
{0x00,0x00,0x00,0x00,0x1C,0x00,0x38,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x70,0x00,0xE0,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x1C,0x00,0x00,0x00,0x00,0x00},/*93*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9C,0x01,0xFE,0x00,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*94*/
};
const unsigned char ascii_2412[][48]={

View File

@ -0,0 +1,333 @@
#include "Drv_ILI9341_Lcd_Image_SysSet.h"
/* Auto-generated by tools/gen_sysset_font.py — MiSans Medium */
const unsigned char gImage_SysSet_Title_72x18[162] = { /* 72x18 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x03,0x0C,0x03,0x0F,0xE0,
0xFF,0xFC,0x3F,0xFF,0x06,0x0E,0x03,0x8F,0xE0,0xFF,0xFC,0x3F,0xC0,0x06,0x7F,0xE1,
0xCC,0x60,0xCC,0xCC,0x07,0x0C,0x0C,0xFF,0xC0,0x8C,0x60,0xFF,0xFC,0x0E,0x1C,0x1D,
0x99,0x00,0x18,0x78,0x03,0x00,0x1F,0xF0,0x1F,0x31,0x87,0x30,0x79,0xFF,0xFE,0x1F,
0xE8,0x1F,0x61,0xC7,0x80,0x00,0x03,0x00,0x03,0x8C,0x06,0x7F,0xC1,0x9F,0xF0,0x7F,
0xF8,0x1E,0x0E,0x0C,0x7F,0x61,0x9F,0xF0,0x60,0x18,0x3F,0xFF,0x0F,0x13,0x01,0x98,
0x60,0x7F,0xF8,0x3F,0xE3,0x1F,0x13,0x01,0x8C,0xE0,0x60,0x18,0x04,0xC8,0x00,0x33,
0x21,0xE7,0xC0,0x7F,0xF8,0x0C,0xDE,0x01,0x33,0x61,0xE3,0x80,0x60,0x18,0x38,0xC7,
0x1F,0xF3,0x61,0xCF,0xC0,0x7F,0xF8,0x73,0xC3,0x9F,0xE3,0xE3,0xBC,0xF9,0xFF,0xFE,
0x03,0xC0,0x00,0xC3,0xC0,0x30,0x39,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_Title = { gImage_SysSet_Title_72x18, 72, 18, 72, 0, 0 };
const unsigned char gImage_SysSet_LblVer_71x18[162] = { /* 71x18 1-bit MSB */
0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x06,0x0C,0x06,0xC0,0x60,
0x06,0x00,0x7F,0xFE,0x06,0xCC,0x06,0xDF,0xF0,0x06,0x00,0x61,0x86,0x0C,0xCC,0x06,
0xDF,0x81,0xFF,0xF8,0x61,0x86,0x0C,0xFF,0x86,0xD8,0x03,0xFF,0xFC,0x7F,0xFE,0x1C,
0xFF,0xC6,0xD8,0x00,0x0F,0x00,0x7F,0xFE,0x1D,0x8C,0x07,0xFF,0xE0,0x1F,0x80,0x61,
0x86,0x3D,0x8C,0x07,0xDF,0xE0,0x1F,0x80,0x6F,0xF6,0x3D,0x8C,0x06,0x1E,0x60,0x36,
0xC0,0x6F,0xF6,0x2C,0x0C,0x07,0xDE,0x60,0x76,0xE0,0x6C,0x36,0x2D,0xFF,0xC7,0xDB,
0x40,0xE6,0x70,0x6C,0x36,0x0D,0xFF,0xC6,0xDB,0xC1,0xC6,0x38,0x6F,0xF6,0x0C,0x0C,
0x06,0xD9,0xC3,0xBF,0xDC,0x67,0xE6,0x0C,0x0C,0x06,0xF1,0x83,0x3F,0xCC,0x60,0x06,
0x0C,0x0C,0x04,0xF3,0xC0,0x06,0x00,0x7F,0xFE,0x0C,0x0C,0x0C,0xFE,0x70,0x06,0x00,
0x7F,0xFE,0x0C,0x0C,0x0C,0xEC,0x30,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_LblVer = { gImage_SysSet_LblVer_71x18, 71, 18, 71, 0, 0 };
const unsigned char gImage_SysSet_LblUsb_70x18[162] = { /* 70x18 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x08,0x80,
0x01,0xA0,0xC0,0x61,0xF0,0xFF,0x03,0x7F,0xF0,0x01,0xB8,0xE0,0xE3,0xFC,0xFF,0x83,
0x7F,0xF0,0x01,0x98,0xE0,0xE7,0x1C,0xE3,0xCF,0x88,0x83,0xFF,0xFC,0xE0,0xE6,0x00,
0xE1,0xCF,0xBF,0xE3,0xFF,0xFC,0xE0,0xE6,0x00,0xE1,0xC3,0x3F,0xE0,0x01,0x80,0xE0,
0xE7,0x00,0xE3,0x87,0x3F,0xE0,0x01,0x80,0xE0,0xE3,0xE0,0xFF,0x07,0xBF,0xE3,0xFD,
0x80,0xE0,0xE1,0xF8,0xFF,0x8F,0xF0,0x61,0xFD,0x80,0xE0,0xE0,0x3C,0xE1,0xCF,0x3F,
0xE0,0x61,0x80,0xE0,0xE0,0x0E,0xE0,0xCB,0x06,0x00,0x61,0x80,0xE0,0xE0,0x0E,0xE0,
0xEB,0x7F,0xF0,0x60,0xCC,0x70,0xC6,0x0C,0xE1,0xC3,0x7F,0xE0,0x7E,0xCC,0x7F,0xC7,
0xFC,0xFF,0xC3,0x0F,0x83,0xFE,0xEC,0x3F,0x83,0xF8,0xFF,0x03,0x79,0xE3,0xF0,0x78,
0x00,0x00,0x00,0x00,0x03,0x70,0x70,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_LblUsb = { gImage_SysSet_LblUsb_70x18, 70, 18, 70, 0, 0 };
const unsigned char gImage_SysSet_LblAuto_69x18[162] = { /* 69x18 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x10,0x03,0x03,0x01,
0x80,0x00,0x06,0x00,0x3F,0x10,0x01,0x86,0x01,0x8F,0xC0,0x7F,0xFC,0x3F,0x10,0x01,
0x8E,0x01,0x8F,0xC0,0x7F,0xFC,0x00,0x7F,0x0F,0xFF,0xC7,0xEC,0xC0,0x60,0x1C,0x00,
0x7F,0x0F,0xFF,0xC7,0xEC,0xC0,0x60,0x1C,0x7F,0x31,0x00,0x30,0x01,0x8C,0xC0,0x7F,
0xFC,0x7F,0xB1,0x00,0x30,0x01,0x8C,0xC0,0x60,0x1C,0x18,0x31,0x00,0x30,0x03,0xEC,
0xC0,0x60,0x1C,0x18,0x31,0x1F,0xFF,0xE3,0xFC,0xC0,0x7F,0xFC,0x1A,0x31,0x0F,0xFF,
0xC7,0xAC,0xC0,0x7F,0xFC,0x33,0x33,0x00,0x78,0x07,0x8C,0xC8,0x60,0x1C,0x33,0x33,
0x00,0xFC,0x05,0x8C,0xD8,0x60,0x1C,0x7F,0xE3,0x01,0xCE,0x01,0x98,0xD8,0x7F,0xFC,
0x7F,0xE3,0x07,0x87,0x01,0x98,0xD8,0x7F,0xFC,0x00,0xFF,0x1F,0x03,0xE1,0xB0,0xF8,
0x60,0x1C,0x00,0xCE,0x1C,0x00,0xE1,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_LblAuto = { gImage_SysSet_LblAuto_69x18, 69, 18, 69, 0, 0 };
const unsigned char gImage_SysSet_LblRestore_108x18[252] = { /* 108x18 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xC0,
0x03,0x00,0x00,0x0C,0x00,0x00,0x00,0x30,0xFE,0x0F,0xFF,0xC0,0x18,0xC0,0x07,0xFF,
0xE1,0x0C,0x20,0x7F,0xFE,0x38,0xFE,0x0F,0xFF,0xC0,0x1B,0xFF,0x87,0xFF,0xC3,0x0C,
0x30,0x7F,0xFE,0x1C,0xC6,0x0C,0xCC,0xC0,0x7C,0xC0,0x0F,0xFF,0x83,0x0C,0x30,0x60,
0x00,0x08,0xC6,0x0F,0xFF,0xC0,0x7E,0xC8,0x1F,0xFF,0x83,0x0C,0x30,0x60,0x00,0x01,
0x87,0x80,0x30,0x00,0x78,0xD8,0x16,0x01,0x83,0x0C,0x30,0x60,0x00,0x73,0x07,0x9F,
0xFF,0xE0,0x79,0xD9,0x87,0xFF,0x83,0xFF,0xF0,0x60,0x00,0x78,0x00,0x00,0x30,0x00,
0x59,0xFB,0x06,0x01,0x81,0xFF,0xE0,0x60,0x00,0x19,0xFF,0x07,0xFF,0x80,0x59,0xFB,
0x07,0xFF,0x80,0x0C,0x00,0x60,0x00,0x19,0xFF,0x06,0x01,0x80,0x19,0xBE,0x01,0x80,
0x03,0x0C,0x30,0x60,0x00,0x19,0x86,0x07,0xFF,0x80,0x1B,0x1C,0x03,0xFF,0x83,0x0C,
0x30,0x60,0x00,0x18,0xCE,0x06,0x01,0x80,0x1B,0x3C,0x07,0xFF,0x83,0x0C,0x30,0xE0,
0x00,0x1E,0x7C,0x07,0xFF,0x80,0x1E,0x36,0x1D,0xC7,0x03,0x0C,0x30,0xC0,0x00,0x1E,
0x38,0x06,0x01,0x80,0x1E,0x67,0x08,0x7E,0x03,0x0C,0x30,0xC0,0x00,0x1C,0xFC,0x07,
0xFF,0x80,0x19,0xC3,0x83,0xFF,0xC3,0xFF,0xF1,0xC0,0x00,0x3B,0xCF,0x9F,0xFF,0xE0,
0x19,0x81,0x9F,0x83,0xE0,0x00,0x31,0x80,0x00,0x03,0x03,0x9F,0xFF,0xE0,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
const SysSetGlyph g_SysSet_LblRestore = { gImage_SysSet_LblRestore_108x18, 108, 18, 108, 0, 0 };
const unsigned char gImage_SysSet_UsbUpdate_71x18[162] = { /* 71x18 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xF0,
0x60,0x08,0xC0,0x61,0xF0,0xFF,0x0F,0xFF,0xF1,0xFD,0xFC,0xE0,0xE3,0xFC,0xFF,0x80,
0x18,0x03,0xFD,0xF0,0xE0,0xE7,0x1C,0xE3,0xC3,0xFF,0xC0,0x99,0x80,0xE0,0xE6,0x00,
0xE1,0xC3,0xFF,0xE0,0xD9,0x80,0xE0,0xE6,0x00,0xE1,0xC2,0x18,0x63,0xFD,0x80,0xE0,
0xE7,0x00,0xE3,0x83,0xFF,0xE3,0xFF,0xFC,0xE0,0xE3,0xE0,0xFF,0x03,0xFF,0xE0,0x21,
0xFC,0xE0,0xE1,0xF8,0xFF,0x82,0x18,0x60,0x71,0x90,0xE0,0xE0,0x3C,0xE1,0xC3,0xFF,
0xE3,0xFD,0x90,0xE0,0xE0,0x0E,0xE0,0xC3,0xFF,0xC0,0x61,0x90,0xE0,0xE0,0x0E,0xE0,
0xE3,0x98,0x01,0xB9,0x90,0x70,0xC6,0x0C,0xE1,0xC1,0xF0,0x01,0x2F,0x90,0x7F,0xC7,
0xFC,0xFF,0xC0,0xF8,0x03,0x27,0x10,0x3F,0x83,0xF8,0xFF,0x07,0xFF,0xF3,0xE3,0x10,
0x00,0x00,0x00,0x00,0x0F,0x03,0xF0,0xE6,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_UsbUpdate = { gImage_SysSet_UsbUpdate_71x18, 71, 18, 71, 0, 0 };
const unsigned char gImage_SysSet_UsbMidi_80x16[160] = { /* 80x16 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x61,0xF0,0xFF,0x00,0x38,
0x03,0x31,0xFE,0x06,0xE0,0xE3,0xFC,0xFF,0x80,0x38,0x07,0x39,0xFF,0x07,0xE0,0xE7,
0x1C,0xE3,0xC0,0x3C,0x0F,0x39,0xC3,0x87,0xE0,0xE6,0x00,0xE1,0xC0,0x3C,0x0F,0x39,
0xC1,0xC7,0xE0,0xE6,0x00,0xE1,0xC0,0x3E,0x1F,0x39,0xC0,0xC7,0xE0,0xE7,0x00,0xE3,
0x80,0x37,0x1B,0x39,0xC0,0xE7,0xE0,0xE3,0xE0,0xFF,0x00,0x33,0x33,0x39,0xC0,0xE7,
0xE0,0xE1,0xF8,0xFF,0x80,0x33,0xF3,0x39,0xC0,0x67,0xE0,0xE0,0x3C,0xE1,0xC0,0x31,
0xE3,0x39,0xC0,0xE7,0xE0,0xE0,0x0E,0xE0,0xC0,0x30,0xE3,0x39,0xC0,0xE7,0xE0,0xE0,
0x0E,0xE0,0xE0,0x30,0xC3,0x39,0xC0,0xC7,0x70,0xC6,0x0C,0xE1,0xC0,0x30,0x03,0x39,
0xC3,0xC7,0x7F,0xC7,0xFC,0xFF,0xC0,0x30,0x03,0x39,0xFF,0x87,0x3F,0x83,0xF8,0xFF,
0x00,0x30,0x03,0x39,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
const SysSetGlyph g_SysSet_UsbMidi = { gImage_SysSet_UsbMidi_80x16, 80, 16, 80, 0, 0 };
const unsigned char gImage_SysSet_Off_34x18[90] = { /* 34x18 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x0C,0x30,0x0E,0xFF,0x80,0x0C,
0x70,0x06,0x01,0x80,0x7F,0xFE,0x10,0x19,0x80,0x7F,0xFE,0x18,0x19,0x80,0x01,0x80,
0x1B,0xFF,0x80,0x01,0x80,0x1B,0xFF,0x80,0x01,0x80,0x18,0x79,0x80,0xFF,0xFF,0x18,
0x79,0x80,0x7F,0xFE,0x18,0xD9,0x80,0x03,0xC0,0x19,0x99,0x80,0x07,0xE0,0x1F,0x19,
0x80,0x0E,0x70,0x1E,0x19,0x80,0x3C,0x38,0x18,0xF9,0x80,0xF8,0x1F,0x18,0x7F,0x80,
0xE0,0x07,0x18,0x07,0x80,0x00,0x00,0x00,0x00,0x00,
};
const SysSetGlyph g_SysSet_Off = { gImage_SysSet_Off_34x18, 34, 18, 34, 0, 0 };
const unsigned char gImage_SysSet_D0_10x25[50] = { /* 10x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x7F,0x00,0x63,0x80,
0xE1,0x80,0xE1,0xC0,0xC1,0xC0,0xC1,0xC0,0xC1,0xC0,0xC1,0xC0,0xC1,0xC0,0xE1,0x80,
0x63,0x80,0x7F,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D0 = { gImage_SysSet_D0_10x25, 10, 25, 12, 1, 0 };
const unsigned char gImage_SysSet_D1_5x25[25] = { /* 5x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x38,0xF8,0xF8,0x98,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
};
const SysSetGlyph g_SysSet_D1 = { gImage_SysSet_D1_5x25, 5, 25, 8, 1, 0 };
const unsigned char gImage_SysSet_D2_10x25[50] = { /* 10x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x3F,0x80,0x71,0x80,
0x61,0x80,0x01,0x80,0x01,0x80,0x03,0x80,0x07,0x00,0x0E,0x00,0x1C,0x00,0x18,0x00,
0x38,0x00,0x7F,0xC0,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D2 = { gImage_SysSet_D2_10x25, 10, 25, 11, 0, 0 };
const unsigned char gImage_SysSet_D3_9x25[50] = { /* 9x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x07,0x00,
0x0E,0x00,0x1C,0x00,0x38,0x00,0x3E,0x00,0x1F,0x00,0x03,0x80,0x01,0x80,0x01,0x80,
0xC3,0x80,0xFF,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D3 = { gImage_SysSet_D3_9x25, 9, 25, 11, 1, 0 };
const unsigned char gImage_SysSet_D4_11x25[50] = { /* 11x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x07,0x80,0x0F,0x80,
0x0F,0x80,0x1D,0x80,0x19,0x80,0x39,0x80,0x31,0x80,0x61,0x80,0x7F,0xC0,0xFF,0xE0,
0x03,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D4 = { gImage_SysSet_D4_11x25, 11, 25, 11, 0, 0 };
const unsigned char gImage_SysSet_D5_9x25[50] = { /* 9x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x7F,0x00,0x60,0x00,
0x60,0x00,0xE0,0x00,0xFC,0x00,0xFF,0x00,0xF7,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
0xC3,0x80,0xFF,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D5 = { gImage_SysSet_D5_9x25, 9, 25, 11, 1, 0 };
const unsigned char gImage_SysSet_D6_10x25[50] = { /* 10x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x1C,0x00,0x18,0x00,
0x38,0x00,0x30,0x00,0x7E,0x00,0x7F,0x00,0xE3,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,
0xE1,0x80,0x7F,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D6 = { gImage_SysSet_D6_10x25, 10, 25, 11, 1, 0 };
const unsigned char gImage_SysSet_D7_9x25[50] = { /* 9x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0xFF,0x80,0x03,0x80,
0x03,0x00,0x03,0x00,0x07,0x00,0x06,0x00,0x0E,0x00,0x0C,0x00,0x1C,0x00,0x18,0x00,
0x18,0x00,0x38,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D7 = { gImage_SysSet_D7_9x25, 9, 25, 10, 0, 0 };
const unsigned char gImage_SysSet_D8_10x25[50] = { /* 10x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x7F,0x00,0x63,0x80,
0xE1,0x80,0x61,0x80,0x73,0x80,0x3F,0x00,0x7F,0x00,0xE1,0x80,0xC1,0xC0,0xC1,0xC0,
0xE1,0xC0,0x7F,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D8 = { gImage_SysSet_D8_10x25, 10, 25, 12, 1, 0 };
const unsigned char gImage_SysSet_D9_11x25[50] = { /* 11x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x3F,0x80,0x71,0xC0,
0x60,0xC0,0x60,0xC0,0x60,0xC0,0x71,0xC0,0x3F,0xC0,0x1F,0x80,0x03,0x80,0x03,0x00,
0x07,0x00,0x0E,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const SysSetGlyph g_SysSet_D9 = { gImage_SysSet_D9_11x25, 11, 25, 11, 0, 0 };
const unsigned char gImage_SysSet_Dot_3x25[25] = { /* 3x25 1-bit MSB */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,
};
const SysSetGlyph g_SysSet_Dot = { gImage_SysSet_Dot_3x25, 3, 25, 5, 1, 0 };
const unsigned char gImage_SysSet_Back_16x10[20] = { /* 16x10 1-bit MSB */
0x1E,0x00,0x3C,0x00,0x38,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x78,0x00,0x3C,0x00,
0x1E,0x00,0x0E,0x00,
};
const SysSetGlyph g_SysSet_Back = { gImage_SysSet_Back_16x10, 16, 10, 16, 0, 0 };
const unsigned char gImage_SysSet_Chevron_10x16[32] = { /* 10x16 1-bit MSB */
0xC0,0x00,0x60,0x00,0x78,0x00,0x3C,0x00,0x1E,0x00,0x07,0x00,0x03,0x80,0x01,0xC0,
0x01,0xC0,0x03,0xC0,0x07,0x80,0x0E,0x00,0x3C,0x00,0x78,0x00,0x70,0x00,0xE0,0x00,
};
const SysSetGlyph g_SysSet_Chevron = { gImage_SysSet_Chevron_10x16, 10, 16, 10, 0, 0 };
const unsigned char gImage_SysSet_TriL_19x18[684] = { /* 19x18 RGB565 BE */
0x00,0x00,0x00,0x20,0x08,0x62,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,
0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,
0x08,0x62,0x00,0x20,0x00,0x00,0x00,0x20,0x08,0x83,0x10,0x83,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0x83,0x08,0xA4,0x00,0x21,0x08,0x62,0x08,0x84,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xC4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,
0x08,0x83,0x08,0x63,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x00,0x01,0x08,0x63,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x08,0x83,0x00,0x22,0x39,0xE8,
0xA5,0x34,0x4A,0x8B,0x08,0x63,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x08,0x63,0x08,0x63,
0x29,0x67,0xA5,0x34,0xEF,0x7D,0xFF,0xFF,0xA5,0x35,0x00,0x42,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xC4,0x08,0x63,
0x00,0x01,0x29,0x67,0x84,0x31,0xE7,0x5D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA5,0x55,
0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x08,0x83,
0x10,0xA4,0x00,0x01,0x21,0x25,0x4A,0x69,0xE7,0x5D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xF7,0xDE,0xFF,0xFF,0xA5,0x35,0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x08,0x83,0x10,0xA4,0x10,0xA4,0x08,0x83,0x31,0xA7,0xBE,0x18,0xFF,0xFF,0xFF,0xFF,
0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA5,0x35,0x00,0x42,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xC4,0x00,0x01,0x94,0xB3,
0xFF,0xFF,0xF7,0xDE,0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xA5,0x35,0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,
0x10,0xA4,0x08,0x83,0x19,0x25,0x6B,0x8E,0xDE,0xFC,0xFF,0xFF,0xFF,0xFF,0xF7,0xDE,
0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,0xA5,0x35,0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x63,0x08,0x63,0x21,0x46,
0x94,0x92,0xEF,0x9D,0xFF,0xFF,0xFF,0xFF,0xF7,0xDE,0xFF,0xFF,0xA5,0x35,0x00,0x42,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x08,0x83,0x08,0x63,0x21,0x46,0x94,0xB2,0xE7,0x3C,0xFF,0xFF,
0xFF,0xFF,0xAD,0x96,0x00,0x22,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,
0x00,0x00,0x31,0xA7,0xA5,0x34,0xDE,0xFB,0x73,0xCF,0x08,0x63,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x08,0x62,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xC4,0x08,0x83,0x00,0x00,0x31,0xA7,0x00,0x00,
0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,
0x10,0xC5,0x08,0x63,0x10,0xC4,0x10,0xA3,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0xA4,
0x00,0x21,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x08,0x62,0x00,0x00,0x08,0x82,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0x83,0x08,0x83,0x00,0x00,
};
const SysSetGlyph g_SysSet_TriL = { gImage_SysSet_TriL_19x18, 19, 18, 19, 0, 1 };
const unsigned char gImage_SysSet_TriR_18x18[648] = { /* 18x18 RGB565 BE */
0x00,0x00,0x00,0x21,0x08,0x63,0x08,0x82,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,
0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x83,0x08,0x82,0x08,0x83,
0x00,0x21,0x00,0x00,0x00,0x21,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x62,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xC4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x08,0x83,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x00,0x22,0x00,0x22,0x08,0x83,0x10,0xA4,0x08,0x83,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x63,0x73,0xD0,0x8C,0x72,0x19,0x25,
0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x00,0x22,0xDF,0x1B,
0xFF,0xDF,0xE7,0x3C,0x5B,0x0C,0x00,0x20,0x08,0x83,0x08,0x63,0x10,0xC4,0x10,0xA4,
0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x00,0x22,0xDE,0xFB,0xFF,0xFF,0xFF,0xFF,0xF7,0x9E,0xD6,0xDA,0x39,0xE8,0x10,0xA4,
0x00,0x21,0x08,0x83,0x10,0xA4,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x00,0x22,0xDE,0xFB,0xFF,0xFF,0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xBE,0x18,0x39,0xE7,0x10,0xC4,0x00,0x21,0x10,0xA4,0x08,0x83,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x00,0x22,0xDE,0xFB,0xFF,0xFF,0xF7,0xDE,
0xFF,0xFF,0xFF,0xFF,0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,0x9C,0xD3,0x18,0xE4,0x08,0x84,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x00,0x22,0xDE,0xFB,
0xFF,0xFF,0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xBE,0xFF,0xFF,0xFF,0xFF,
0x4A,0x6A,0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x00,0x22,0xDE,0xFB,0xFF,0xFF,0xF7,0xDE,0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xB5,0xB6,0x31,0xA6,0x18,0xE5,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x00,0x22,0xDE,0xFB,0xFF,0xFF,0xF7,0xDE,0xFF,0xFF,0xFF,0xFF,
0xD6,0xDB,0x6B,0x6E,0x10,0xC4,0x00,0x01,0x08,0x83,0x08,0x83,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x00,0x22,0xE7,0x3C,0xFF,0xFF,0xFF,0xFF,
0xD6,0xDB,0x6B,0xAF,0x18,0xE5,0x08,0x63,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x00,0x42,0xB5,0xF7,
0xDE,0xFB,0x94,0x92,0x21,0x46,0x00,0x42,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x08,0x83,0x21,0x26,0x29,0x87,0x00,0x01,0x08,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0x83,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,0x08,0x83,0x10,0xC4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x08,0x83,
0x08,0xA3,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x00,0x20,0x08,0xA3,0x10,0x83,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,0x10,0xA4,
0x10,0xA4,0x10,0x83,0x08,0xA4,0x00,0x20,
};
const SysSetGlyph g_SysSet_TriR = { gImage_SysSet_TriR_18x18, 18, 18, 18, 0, 1 };

View File

@ -0,0 +1,59 @@
#ifndef __DRV_ILI9341_LCD_IMAGE_SYSSET_H
#define __DRV_ILI9341_LCD_IMAGE_SYSSET_H
#include "stdint.h"
/* MiSans-Medium strips, same blit path as the settings hub cards. */
typedef struct {
const unsigned char *data;
uint8_t w;
uint8_t h;
uint8_t adv;
int8_t bear;
uint8_t mode; /* 0 = 1-bit ink, 1 = RGB565 */
} SysSetGlyph;
extern const SysSetGlyph g_SysSet_Title;
extern const SysSetGlyph g_SysSet_LblVer;
extern const SysSetGlyph g_SysSet_LblUsb;
extern const SysSetGlyph g_SysSet_LblAuto;
extern const SysSetGlyph g_SysSet_LblRestore;
extern const SysSetGlyph g_SysSet_UsbUpdate;
extern const SysSetGlyph g_SysSet_UsbMidi;
extern const SysSetGlyph g_SysSet_Off;
extern const SysSetGlyph g_SysSet_D0;
extern const SysSetGlyph g_SysSet_D1;
extern const SysSetGlyph g_SysSet_D2;
extern const SysSetGlyph g_SysSet_D3;
extern const SysSetGlyph g_SysSet_D4;
extern const SysSetGlyph g_SysSet_D5;
extern const SysSetGlyph g_SysSet_D6;
extern const SysSetGlyph g_SysSet_D7;
extern const SysSetGlyph g_SysSet_D8;
extern const SysSetGlyph g_SysSet_D9;
extern const SysSetGlyph g_SysSet_Dot;
extern const SysSetGlyph g_SysSet_Back;
extern const SysSetGlyph g_SysSet_Chevron;
extern const SysSetGlyph g_SysSet_TriL;
extern const SysSetGlyph g_SysSet_TriR;
#define SYSSET_BACK_X 15
#define SYSSET_BACK_Y 14
#define SYSSET_CHEV_X 211
#define SYSSET_CHEV_Y 275
#define SYSSET_TRIL_X 96
#define SYSSET_TRIL_DY 22
#define SYSSET_TRIR_X 203
#define SYSSET_TRIR_DY 22
#define SYSSET_TITLE_Y 12
#define SYSSET_LABEL_DX 12
#define SYSSET_VAL_X 119
#define SYSSET_VAL_W 80
#define SYSSET_PILL_DX 139
#define SYSSET_PILL_DY 14
#define SYSSET_PILL_W 74
#define SYSSET_PILL_H 33
#define SYSSET_PILL_R 6
#define SYSSET_CARD_R 12
#endif

File diff suppressed because it is too large Load Diff

View File

@ -4,26 +4,27 @@
#include "stdint.h"
extern const unsigned char gImage_UI0902_BatteryOutline_29x12[];
extern const unsigned char gImage_UI0902_Volume_20x15[600];
extern const unsigned char gImage_UI0902_Bluetooth_11x17[374];
extern const unsigned char gImage_UI0902_BatteryFill_22x9[396];
extern const unsigned char gImage_UI0902_TabSetting_Sel_36x28[2016];
extern const unsigned char gImage_UI0902_TabSetting_Not_35x28[1960];
extern const unsigned char gImage_UI0902_TabMixer_Sel_35x27[1890];
extern const unsigned char gImage_UI0902_TabMixer_Not_18x28[1008];
extern const unsigned char gImage_UI0902_TabMixer_Not_35x28[1960];
extern const unsigned char gImage_UI0902_TabMode_Sel_36x28[2016];
extern const unsigned char gImage_UI0902_TabMode_Not_35x29[2030];
extern const unsigned char gImage_UI0902_TabBack_Sel_35x27[1890];
extern const unsigned char gImage_UI0902_TabBack_Not_18x28[1008];
extern const unsigned char gImage_UI0902_Volume_20x15[600];
extern const unsigned char gImage_UI0902_Speaker_10x15[300];
extern const unsigned char gImage_UI0902_Bluetooth_On_13x20[520];
extern const unsigned char gImage_UI0902_Bluetooth_Off_19x20[760];
extern const unsigned char gImage_UI0902_BatteryCharging_40x13[1040];
extern const unsigned char gImage_Nav0924_Universal_Sel_33x46[3036];
extern const unsigned char gImage_Nav0924_Universal_Not_33x46[3036];
extern const unsigned char gImage_Nav0924_Normal_Sel_34x46[3128];
extern const unsigned char gImage_Nav0924_Normal_Not_34x46[3128];
extern const unsigned char gImage_Nav0924_Expert_Sel_33x46[3036];
extern const unsigned char gImage_Nav0924_Expert_Not_33x46[3036];
extern const unsigned char gImage_Nav0924_Setting_Sel_34x46[3128];
extern const unsigned char gImage_Nav0924_Setting_Not_34x46[3128];
extern const unsigned char gImage_UI0902_BtnMinus_23x22[1012];
extern const unsigned char gImage_UI0902_BtnPlus_23x22[1012];
extern const unsigned char gImage_UI0902_TabBack_30x24[1440];
extern const unsigned char gImage_UI0902_TriLeft_22x22[968];
extern const unsigned char gImage_UI0902_TriRight_23x22[1012];
extern const unsigned char gImage_UI0902_Txt_Confirm_50x24[2400];
extern const unsigned char gImage_UI0902_Txt_Cancel_50x24[2400];
#endif

View File

@ -36,17 +36,35 @@ static void TM1629D_DIO_Output(void)
gpio_init(TM1629D_DIO_PORT, &g);
}
/* DIO 引脚切换为输入模式(读按键) */
/* DIO 引脚切换为输入模式(读按键)。上拉:板子拔掉时读到全 1,用来识别未插入。 */
static void TM1629D_DIO_Input(void)
{
gpio_init_type g;
gpio_default_para_init(&g);
g.gpio_mode = GPIO_MODE_INPUT;
g.gpio_pull = GPIO_PULL_NONE;
g.gpio_pull = GPIO_PULL_UP;
g.gpio_pins = TM1629D_DIO_PIN;
gpio_init(TM1629D_DIO_PORT, &g);
}
/* 显示模式 + 开显示。芯片掉电(拔插/后插入)后必须重发,否则显存写了也不亮。 */
static void TM1629D_DisplayOn(void)
{
TM1629D_STB_L();
TM1629D_Delay1us();
TM1629D_SendByte(0x40);
TM1629D_STB_H();
TM1629D_Delay1us();
TM1629D_STB_L();
TM1629D_Delay1us();
TM1629D_SendByte(0x8F);
TM1629D_STB_H();
TM1629D_Delay1us();
}
static void TM1629D_OnKeySample(const uint8_t *keyBuf);
/* GPIO初始化 */
void TM1629D_Key_LED_Init(void)
{
@ -74,23 +92,8 @@ void TM1629D_Key_LED_Init(void)
TM1629D_CLK_H();
TM1629D_DIO_H();
// 清寄存器
TM1629D_AllLedOff();
// 配置TM1629D为“普通显示模式”(无译码,8个GRID)
TM1629D_STB_L();
TM1629D_Delay1us();
TM1629D_SendByte(0x40); // 普通模式命令(文档1-46)
TM1629D_STB_H();
TM1629D_Delay1us();
// 配置亮度(示例:中亮度)
TM1629D_STB_L();
TM1629D_Delay1us();
TM1629D_SendByte(0x8F); // 0x88(最暗)~0x8F(最亮)
TM1629D_STB_H();
TM1629D_Delay1us();
TM1629D_AllLedOn(COLOR_OTHER);
TM1629D_DisplayOn();
TM1629D_UpdateDisplay(0);
}
@ -190,6 +193,13 @@ Key_TypeDef TM1629D_GetKey(void)
{
uint8_t keyBuf[4] = {0};
TM1629D_ReadKeyData(keyBuf); // 读取原始按键数据(与原逻辑一致)
TM1629D_OnKeySample(keyBuf);
/* 拔掉时上拉读到全 1,不能当成按键 */
if (keyBuf[0] == 0xFF && keyBuf[1] == 0xFF &&
keyBuf[2] == 0xFF && keyBuf[3] == 0xFF)
{
return KEY_NONE;
}
// 遍历映射表匹配按键(C语言循环写法)
for (uint8_t i = 0; i < KEY_MAP_LEN; i++)
@ -291,6 +301,8 @@ void TM1629D_SetGridSeg(uint8_t grid, uint8_t seg, uint8_t on)
void TM1629D_UpdateDisplay(uint8_t u8LH)
{
uint8_t grid;
/* 每次刷灯都重开显示,后插入的板子不用等下一次拔插检测 */
TM1629D_DisplayOn();
TM1629D_STB_L();
TM1629D_Delay1us();
@ -310,6 +322,36 @@ void TM1629D_UpdateDisplay(uint8_t u8LH)
TM1629D_Delay1us();
}
/* 连续全 0xFF 视为板子不在;重新读到键值后把当前灯态刷回去,闪烁逻辑不用重来。 */
static uint8_t s_board_present;
static uint8_t s_absent_cnt;
static uint8_t s_present_cnt;
static void TM1629D_OnKeySample(const uint8_t *keyBuf)
{
int absent = (keyBuf[0] == 0xFF && keyBuf[1] == 0xFF &&
keyBuf[2] == 0xFF && keyBuf[3] == 0xFF);
if (absent)
{
s_present_cnt = 0;
if (s_absent_cnt < 8)
s_absent_cnt++;
if (s_absent_cnt >= 3)
s_board_present = 0;
return;
}
s_absent_cnt = 0;
if (s_present_cnt < 8)
s_present_cnt++;
if (!s_board_present && s_present_cnt >= 2)
{
s_board_present = 1;
TM1629D_UpdateDisplay(0);
}
}
// 向指定地址写入1字节数据(单独调用调试用)
void TM1629D_WriteDisplayByte(uint8_t addr, uint8_t data)
{

View File

@ -1,6 +1,7 @@
// File: w25q128.c
#include "w25q128.h"
#include "wk_system.h"
#include "rtthread.h"
/* W25Q128 挂在 SPI1 上(PA5=SCK, PA6=MISO, PA7=MOSI),CS 用 PA4 GPIO 控制 */
#define W25Q128_SPI SPI1
@ -82,6 +83,12 @@ static void W25Q128_WaitBusy(void)
W25Q128_ReadWriteByte(W25X_ReadStatusReg1); // 发送读状态寄存器命令
do {
status = W25Q128_ReadWriteByte(0xFF); // 循环读取状态字
if (status & 0x01) {
SPI_CS_HIGH();
rt_thread_mdelay(1);
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_ReadStatusReg1);
}
} while (status & 0x01); // 等待BUSY位清零
SPI_CS_HIGH();
}

View File

@ -170,7 +170,7 @@ uint8_t drv_nvm_save_to_flash(void)
pData16 = (uint16_t *)NvmDataToSave;
flash_unlock();
flash_sector_erase(INNER_FLASH_SAVE_ADDRESS);
flash_sector_erase(INNER_FLASH_SECTOR_ADDRESS);
flash_write_nocheck(addr,pData16,len);
flash_lock();
@ -199,8 +199,8 @@ void drv_nvm_load_default_calibration_static_value(NvmParam_Type * pData, uint8
if(reset_open_status)
{
pData->param.BPM = 100;
pData->param.Timbre = 0;
pData->param.BPM = 92; /* 万能默认;进节奏后由曲目表覆盖 */
pData->param.Timbre = TIMBRE_BOOT_SLOT;
pData->param.BandVol = 7;
pData->param.StringVol = 7;
pData->param.MIcVol = 7;
@ -212,8 +212,29 @@ void drv_nvm_load_default_calibration_static_value(NvmParam_Type * pData, uint8
pData->param.Param1 = 0;
pData->param.Param2 = 0;
pData->param.Param3 = 0;
pData->param.Language = NVM_LANG_CN;
pData->param.UsbMode = NVM_USB_MIDI;
}
mGuiData[GUI_SPEED].Current = pData->param.BPM;
else
{
/* 不记忆:忽略 Flash 里上次的蓝牙、节奏、曲目、走向、BPM */
pData->param.BluetoothSW = 1;
pData->param.Param1 = 0;
pData->param.Param2 = 0;
pData->param.Param3 = 0;
}
if (pData->param.Timbre > 4)
pData->param.Timbre = TIMBRE_BOOT_SLOT;
if (pData->param.Transpose > 11)
pData->param.Transpose = 0;
if (pData->param.BandVol > 10)
pData->param.BandVol = 7;
if (pData->param.StringVol > 10)
pData->param.StringVol = 7;
if (pData->param.MIcVol > 10)
pData->param.MIcVol = 7;
if (pData->param.MicRev > 10)
pData->param.MicRev = 7;
mGuiData[GUI_TIMBRE_SELECT].Current = pData->param.Timbre;
mGuiData[GUI_TRANSPOSE].Current = pData->param.Transpose;
faders[0].val = pData->param.BandVol;
@ -226,8 +247,12 @@ void drv_nvm_load_default_calibration_static_value(NvmParam_Type * pData, uint8
/* 旧固件 Language 槽可能为 0xFF;非法值按默认开处理 */
if (pData->param.BluetoothSW > 1)
pData->param.BluetoothSW = 1;
mGuiData_SystemSETTING[GUI_BLUETOOTH_SW].Current = pData->param.BluetoothSW;
mGuiData[GUI_BL_SW].Current = pData->param.BluetoothSW;
if (pData->param.Language > 1)
pData->param.Language = NVM_LANG_CN;
if (pData->param.UsbMode > 1)
pData->param.UsbMode = NVM_USB_MIDI;
mGuiData_SystemSETTING[GUI_USB_MODE].Current = pData->param.UsbMode;
/* 开机/出厂:同步自动关机运行时秒表(手册 15/30/45/60/不自动) */
AutoCloseFlag = true;
switch (pData->param.AutoCloseTime)
@ -244,6 +269,10 @@ void drv_nvm_load_default_calibration_static_value(NvmParam_Type * pData, uint8
ParamGuiData[SONG_MODE_PARAM].Current = pData->param.Param1;
ParamGuiData[EXPRESS_MODE_PARAM].Current = pData->param.Param2;
ParamGuiData[ALL_MODE_PARAM].Current = pData->param.Param3;
/* BPM 跟当前曲目,不恢复 Flash 里的旧速度 */
TrackBpm_Invalidate();
TrackBpm_SyncGui();
pData->param.BPM = mGuiData[GUI_SPEED].Current;
// mGuiData[GUI_SPEED].Current = pData->param.ReverbVolume;
// mGuiData[GUI_SPEED].Current = pData->param.WirelessSW;

View File

@ -1,15 +1,35 @@
#ifndef _DRV_NVM_H_
#define _DRV_NVM_H_
#define NVM_VERSION 0x02
#include <stdint.h>
#define NVM_VERSION 0x03
#define NVM_LANG_CN 0
#define NVM_LANG_EN 1
#define NVM_USB_MIDI 0
#define NVM_USB_UPDATE 1
#ifndef FLASH_BASE
#define FLASH_BASE 0x08000000UL
#endif
#define fwname "BRS08L\x00"
#define fwdata __DATE__
#define fwtime __TIME__
#define INNER_FLASH_SAVE_ADDRESS (FLASH_BASE + 0x00040000 - SECTOR_SIZE)
/* 参数固定在 0x0803FC00(256KB 末尾倒数第 2 个 1KB)。
* 地址不能跟 SECTOR_SIZE 走:App 与 Boot 对该宏不一致时,Boot 会读错,
* USB 更新标志对不上。AT32F403A 扇区是 2KB,擦除必须对齐扇区起点,
* 否则 0->1(MIDI->更新)写不进去。应用程序链接范围必须停在该扇区之前。 */
#define NVM_FLASH_SECTOR 2048UL
#define INNER_FLASH_SAVE_ADDRESS (FLASH_BASE + 0x00040000UL - 1024UL)
#define INNER_FLASH_SECTOR_ADDRESS (INNER_FLASH_SAVE_ADDRESS & ~(NVM_FLASH_SECTOR - 1UL))
/* 备份寄存器在系统复位后仍保留。确认 USB 更新时先写下这个值,
* Boot 即使没读到 Flash 里的 UsbMode,不按圆键 4 也会停在烧录模式。 */
#define NVM_USB_BOOT_MAGIC 0xB007u
#pragma pack(push, 1)
typedef struct {
uint16_t BPM;
uint8_t Timbre;
@ -19,10 +39,12 @@ typedef struct {
uint8_t MicRev;
uint8_t AutoCloseTime;
uint8_t Transpose;
uint8_t BluetoothSW; /* 0=关 1=开;复用原 Language 槽位,布局不变 */
uint8_t BluetoothSW; /* 0=关 1=开 */
uint8_t Param1;
uint8_t Param2;
uint8_t Param3;
uint8_t Language; /* 0=中文 1=English;本轮仅记忆,不切全机文案 */
uint8_t UsbMode; /* 0=USB MIDI 1=USB更新 */
} DeviceParam_Type;
typedef struct {
@ -52,6 +74,7 @@ typedef struct {
NvmParam_Type data;
uint16_t sum[2];
} NvmData_Type;
#pragma pack(pop)
#define MAGIC_POWER_ON_RESTORE 0xA637
@ -67,4 +90,36 @@ void drv_nvm_load_default_calibration_static_value(NvmParam_Type * pData, uint8_
uint8_t drv_nvm_get_param_value_by_id (uint8_t nvmId);
#include "at32f403a_407_bpr.h"
#include "at32f403a_407_crm.h"
#include "at32f403a_407_pwc.h"
static inline void drv_nvm_bpr_open(void)
{
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
pwc_battery_powered_domain_access(TRUE);
while (PWC->ctrl_bit.bpwen == FALSE)
{
}
}
static inline void drv_nvm_arm_usb_boot(void)
{
drv_nvm_bpr_open();
BPR->dt1 = NVM_USB_BOOT_MAGIC;
}
static inline uint8_t drv_nvm_usb_boot_armed(void)
{
drv_nvm_bpr_open();
return ((BPR->dt1 & 0xFFFFu) == NVM_USB_BOOT_MAGIC) ? 1u : 0u;
}
static inline void drv_nvm_clear_usb_boot_arm(void)
{
drv_nvm_bpr_open();
BPR->dt1 = 0;
}
#endif // _DRV_NVM_H_

View File

@ -27,13 +27,111 @@ void SendVolumeChangeMidiEvent(uint8_t channel,uint8_t CC)
SendMidiDataToDreamDSP(midibuff,3);
}
void SendBankChangeMidiEvent(uint8_t CC)
/* Bank Select:CC0(MSB)=bank,CC32(LSB)=0。Dream 双音色库:0=伴奏,1=主弦 */
void SendBankChangeMidiEvent(uint8_t channel, uint8_t bank)
{
uint8_t midibuff[3] = {0xB0 ,0x00, CC };
uint8_t midibuff[3] = {0xB0|(channel & 0x0F) ,0x00, bank };
SendMidiDataToDreamDSP(midibuff,3);
midibuff[1] = 0x20; /* CC32 Bank LSB */
midibuff[2] = 0;
SendMidiDataToDreamDSP(midibuff,3);
}
/* 先选 Bank 再 Program Change,避免漏发 Bank Select 落到错误音色库 */
void SendProgramWithBankMidiEvent(uint8_t channel, uint8_t bank, uint8_t program)
{
SendBankChangeMidiEvent(channel, bank);
SendProgramChangeMidiEvent(channel, program);
}
void SendMidiDataToDreamDSP(uint8_t* buff, uint16_t cnt)
{
USART2_SendData(buff,cnt);
}
/* Roland/Dream GS:checksum = 0x80 - (addr+data 低 7 位) */
static void Dream_Dt1(uint8_t ah, uint8_t am, uint8_t al, const uint8_t *data, uint8_t n)
{
uint8_t msg[16];
uint8_t i;
uint8_t sum;
msg[0] = 0xF0;
msg[1] = 0x41;
msg[2] = 0x00;
msg[3] = 0x42;
msg[4] = 0x12;
msg[5] = ah;
msg[6] = am;
msg[7] = al;
sum = (uint8_t)(ah + am + al);
for (i = 0; i < n; i++)
{
msg[8 + i] = data[i];
sum = (uint8_t)(sum + data[i]);
}
msg[8 + n] = (uint8_t)((0x80u - (sum & 0x7Fu)) & 0x7Fu);
msg[9 + n] = 0xF7;
SendMidiDataToDreamDSP(msg, (uint16_t)(10u + n));
}
static void Dream_Dt1Byte(uint8_t ah, uint8_t am, uint8_t al, uint8_t data)
{
Dream_Dt1(ah, am, al, &data, 1);
}
/* 音师编辑器 B:Reverb / E:PEQ Normal。
混响是 GS 系统区 40 01 30:Hall2=4,Size=Character,PreLP,Level,Time,Delay Feedback。
PEQ 为同一套 4 段参量:增益按 0.1 dB/档、0=0 dB;频率按 Hz 的 14 位原值;Q 按 0.1 显示(2.00→20)。 */
void Dream_ApplyEditorParams(void)
{
uint8_t hz[2];
Dream_Dt1Byte(0x40, 0x01, 0x30, 4); /* Type Hall2 */
Dream_Dt1Byte(0x40, 0x01, 0x31, 4); /* Size */
Dream_Dt1Byte(0x40, 0x01, 0x32, 2); /* PreLP */
Dream_Dt1Byte(0x40, 0x01, 0x33, 85); /* Level */
Dream_Dt1Byte(0x40, 0x01, 0x34, 64); /* Time */
Dream_Dt1Byte(0x40, 0x01, 0x35, 0); /* DelFdbck */
/* 40 04 00.. 与编辑器从左到右、从上到下一致 */
Dream_Dt1Byte(0x40, 0x04, 0x00, 81); /* GainLow 8.1 dB */
Dream_Dt1Byte(0x40, 0x04, 0x01, 12); /* GainLoMid 1.2 dB */
Dream_Dt1Byte(0x40, 0x04, 0x02, 7); /* GainHiMid 0.7 dB */
Dream_Dt1Byte(0x40, 0x04, 0x03, 28); /* GainHigh 2.8 dB */
hz[0] = (uint8_t)((412 >> 7) & 0x7F);
hz[1] = (uint8_t)(412 & 0x7F);
Dream_Dt1(0x40, 0x04, 0x04, hz, 2); /* FreqLow 412 Hz */
hz[0] = (uint8_t)((2294 >> 7) & 0x7F);
hz[1] = (uint8_t)(2294 & 0x7F);
Dream_Dt1(0x40, 0x04, 0x06, hz, 2); /* FreqLoMid 2294 Hz */
hz[0] = (uint8_t)((6048 >> 7) & 0x7F);
hz[1] = (uint8_t)(6048 & 0x7F);
Dream_Dt1(0x40, 0x04, 0x08, hz, 2); /* FreqHiMid 6048 Hz */
hz[0] = (uint8_t)((3126 >> 7) & 0x7F);
hz[1] = (uint8_t)(3126 & 0x7F);
Dream_Dt1(0x40, 0x04, 0x0A, hz, 2); /* FreqHigh 3126 Hz */
Dream_Dt1Byte(0x40, 0x04, 0x0C, 20); /* Q-LoMid 2.00 */
Dream_Dt1Byte(0x40, 0x04, 0x0D, 20); /* Q-HiMid 2.00 */
}
#define AT32_UID_BASE 0x1FFFF7E8UL
void BleBuildDeviceName(char *out)
{
static const char hex[] = "0123456789ABCDEF";
const uint32_t *uid = (const uint32_t *)AT32_UID_BASE;
uint32_t tail = uid[2] & 0x00FFFFFFu;
unsigned i;
out[0] = 'P';
out[1] = 'H';
out[2] = 'O';
out[3] = 'N';
out[4] = '_';
for (i = 0; i < 6; i++)
out[5 + i] = hex[(tail >> (4 * (5 - i))) & 0xFu];
out[BLE_DEVICE_NAME_LEN] = '\0';
}

View File

@ -2,13 +2,24 @@
#define __MIDI_SEND_H__
/* Dream 音色库 Bank:0=自动伴奏,1=主音色/弦 */
#define MIDI_BANK_ACCOMP 0
#define MIDI_BANK_STRING 1
/* MIDI 发送函数 */
void SendNoteOnMidiEvent(uint8_t Key, uint8_t OnVal);
void SendNoteOffMidiEvent(uint8_t Key, uint8_t OffVal);
void SendProgramChangeMidiEvent(uint8_t channel, uint8_t CC);
void SendBankChangeMidiEvent(uint8_t CC);
void SendBankChangeMidiEvent(uint8_t channel, uint8_t bank);
void SendProgramWithBankMidiEvent(uint8_t channel, uint8_t bank, uint8_t program);
void SendVolumeChangeMidiEvent(uint8_t channel, uint8_t CC);
void SendMidiDataToDreamDSP(uint8_t* buff, uint16_t cnt);
/* 开机/进模式:音师照片中的 Hall2 混响和 Normal 四段 PEQ */
void Dream_ApplyEditorParams(void);
void DefaultTask_SendMsg(uint16_t Data1, uint16_t Data2, uint16_t Data3, uint16_t Data4);
/* Unique BLE/BT name from AT32 UID: "PHON_" + 6 hex (last 3 UID bytes). out >= 12. */
#define BLE_DEVICE_NAME_LEN 11
void BleBuildDeviceName(char *out);
#endif /* __MIDI_SEND_H__ */

View File

@ -24,9 +24,9 @@ CHORD_TYPE_INDEX chord_type_index_map[22] =
{1, 0, 1, 0}, // index 16
{1, 0, 1, 0}, // index 17
{1, 0, 1, 0}, // index 18
{0, 0, 1, 0}, // index 19
{0, 0, 1, 0}, // index 20
{0, 0, 1, 0}, // index 21
{1, 0, 1, 0}, // index 19 (VII 出厂小三,对照新表 Bm)
{1, 0, 1, 0}, // index 20
{1, 0, 1, 0}, // index 21
};
STRING_MIDI MIDI_1[] =
@ -118,7 +118,7 @@ STRING_MIDI MIDI_7[] =
{0x29,0x2F,0x32,0x35,0x39,0x3E,"Bm7-5"},
{0x29,0x2F,0x31,0x36,0x3B,0x3D,"Bsus2"},
{0x29,0x2F,0x34,0x36,0x3B,0x40,"Bsus4"},
{0x29,0x2F,0x32,0x35,0x3B,0x3E,"Bdim"},
{0x29,0x2F,0x32,0x35,0x3B,0x3E,"Bm-5"},
};
const STRING_MIDI OrganMIDI_1[] =
@ -210,7 +210,7 @@ const STRING_MIDI OrganMIDI_7[] =
{0x29,0x2F,0x32,0x35,0x39,0x3E,"Bm7-5"},
{0x29,0x2F,0x31,0x36,0x3B,0x3D,"Bsus2"},
{0x29,0x2F,0x34,0x36,0x3B,0x40,"Bsus4"},
{0x29,0x2F,0x32,0x35,0x3B,0x3E,"Bdim"},
{0x29,0x2F,0x32,0x35,0x3B,0x3E,"Bm-5"},
};
/* 和弦根音表索引 */
@ -220,7 +220,8 @@ const STRING_MIDI *Chord_Midi_Table[7] =
const STRING_MIDI *OrganChord_Midi_Table[7] =
{ OrganMIDI_1,OrganMIDI_2,OrganMIDI_3,OrganMIDI_4,OrganMIDI_5,OrganMIDI_6, OrganMIDI_7 };
const uint8_t Timbre_index[5] = {0x18,0x19,0x1B,0x1E,0x22};
/* UI槽位0~4 → Bank1 Program:24音乐会钢弦 / 25经典钢弦 / 27清音 / 30失真 / 33电贝司 */
const uint8_t Timbre_index[5] = {0x18, 0x19, 0x1B, 0x1E, 0x21};

View File

@ -49,6 +49,8 @@ extern const STRING_MIDI OrganMIDI_7[];
extern const STRING_MIDI *Chord_Midi_Table[7];
extern const STRING_MIDI *OrganChord_Midi_Table[7];
extern const uint8_t Timbre_index[5];
/* 开机不记忆:显示第 1 项「音乐会钢弦吉他」= Bank1 Program 24 = Timbre_index[0] */
#define TIMBRE_BOOT_SLOT 0u
/* 当前使用的 MIDI 音符 */
extern STRING_MIDI USE_MIDI;

View File

@ -5,7 +5,8 @@
define symbol __ICFEDIT_intvec_start__ = 0x08008000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08008000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
/* 0x0803F800-0x0803FFFF 是 NVM 扇区,留给 UsbMode。代码放进来会被参数擦除毁掉。 */
define symbol __ICFEDIT_region_ROM_end__ = 0x0803F7FF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
/* AT32F403ARCT7: 96KB SRAM (0x20000000-0x20017FFF). Do NOT use 224KB. */
define symbol __ICFEDIT_region_RAM_end__ = 0x20017FFF;

View File

@ -5,7 +5,8 @@
define symbol __ICFEDIT_intvec_start__ = 0x08008000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
/* 0x0803F800-0x0803FFFF 是 NVM 扇区,留给 UsbMode。 */
define symbol __ICFEDIT_region_ROM_end__ = 0x0803F7FF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x20037FFF;
define symbol __ICFEDIT_boot_start__ = 0x08000000;

View File

@ -185,7 +185,7 @@
<state>USE_STDPERIPH_DRIVER</state>
<state>AT_START_F403A_V1</state>
<state>autoband</state>
<state>DEBUG_LCD_DUMP=1</state>
<state>DEBUG_LCD_DUMP=0</state>
</option>
<option>
<name>CCPreprocFile</name>
@ -663,7 +663,7 @@
<name>BUILDACTION</name>
<archiveVersion>1</archiveVersion>
<data>
<prebuild></prebuild>
<prebuild>python &quot;$PROJ_DIR$\..\..\tools\gen_git_user_fw_ver.py&quot;</prebuild>
<postbuild></postbuild>
</data>
</settings>
@ -1650,7 +1650,7 @@
<name>BUILDACTION</name>
<archiveVersion>1</archiveVersion>
<data>
<prebuild></prebuild>
<prebuild>python &quot;$PROJ_DIR$\..\..\tools\gen_git_user_fw_ver.py&quot;</prebuild>
<postbuild></postbuild>
</data>
</settings>
@ -2096,6 +2096,12 @@
<file>
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image_ChargePct.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image_SysSet.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image_SysSet.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image.h</name>
</file>
@ -2409,6 +2415,18 @@
<file>
<name>$PROJ_DIR$\..\..\UI\UI_SystemSet.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\UI\UI_Language.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\UI\UI_Language.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\UI\UI_UsbModeConfirm.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\UI\UI_UsbModeConfirm.h</name>
</file>
</group>
<group>
<name>user</name>

View File

@ -4,10 +4,10 @@
/* Auto-generated by tools/pack_extflash_tone_0903.py — do not hand-edit. */
/* W25Q128 absolute offsets. Boot logo display uses UI0902_BOOT_LOGO_ADDR. */
/* Tone resource pack has no in-bin version field; release tag = EXTFLASH_TONE_RES_VER. */
#define EXTFLASH_TONE_RES_VER "0903"
#define EXTFLASH_TONE_RES_VER "1019"
#define EXTFLASH_TONE_RES_VER_MAJOR 0
#define EXTFLASH_TONE_RES_VER_MINOR 9
#define EXTFLASH_TONE_RES_VER_PATCH 3
#define EXTFLASH_TONE_RES_VER_MINOR 10
#define EXTFLASH_TONE_RES_VER_PATCH 19
#define EXTFLASH_LOGO_ADDR 0x00000000UL
#define EXTFLASH_LOGO_SIZE 52080UL
@ -18,13 +18,13 @@
#define EXTFLASH_CHARGING_H 190
#define EXTFLASH_BIN1_RHYTHM_ADDR 0x0001B8F0UL
#define EXTFLASH_BIN1_RHYTHM_SIZE 530317UL
#define EXTFLASH_BIN1_RHYTHM_SIZE 499354UL
#define EXTFLASH_BIN2_SONG_HAITIAN_ADDR 0x0009D07DUL
#define EXTFLASH_BIN2_SONG_HAITIAN_SIZE 41263UL
#define EXTFLASH_BIN2_SONG_HAITIAN_SIZE 41914UL
#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x000A71ACUL
#define EXTFLASH_BIN3_UNIVERSAL_SIZE 31854UL
#define EXTFLASH_BIN3_UNIVERSAL_ADDR 0x000A7437UL
#define EXTFLASH_BIN3_UNIVERSAL_SIZE 33945UL
/* Convenience aliases used by UI ADDRESS */
#define FLASH_ADDR_MODE_NORMAL EXTFLASH_BIN1_RHYTHM_ADDR /* 普通 */
@ -32,11 +32,11 @@
#define FLASH_ADDR_SONG_HAITIAN EXTFLASH_BIN2_SONG_HAITIAN_ADDR
#define FLASH_ADDR_MODE_UNIVERSAL EXTFLASH_BIN3_UNIVERSAL_ADDR /* 万能 */
/* Legacy AutoBand bank — not repacked in 0903; left unchanged in firmware */
/* Legacy AutoBand bank — not repacked; may overlap 2.bin — do not enable until remapped */
#define FLASH_ADDR_AUTOBAND_LEGACY 0x0009EB5FUL
#define EXTFLASH_TONE_PACK_END 0x000AEE1AUL
#define EXTFLASH_TONE_PACK_SIZE 716314UL
#define EXTFLASH_TONE_PACK_END 0x000AF8D0UL
#define EXTFLASH_TONE_PACK_SIZE 719056UL
#define UI0902_RES_BASE_SAFE_GAP (0x00100000UL - EXTFLASH_TONE_PACK_END)
#endif

View File

@ -180,115 +180,151 @@
#define UI0902_SLIDER_WIDGET_W 219
#define UI0902_SLIDER_WIDGET_H 32
#define UI0902_BTN_LANG_SEL_ADDR (UI0902_RES_BASE + 0x069000UL) /* 3332 bytes */
#define UI0902_BTN_LANG_SEL_W 49
#define UI0902_BTN_LANG_SEL_H 34
#define UI0902_BTN_LANG_SEL_ADDR (UI0902_RES_BASE + 0x069000UL) /* 36572 bytes */
#define UI0902_BTN_LANG_SEL_W 223
#define UI0902_BTN_LANG_SEL_H 82
#define UI0902_BTN_LANG_CN1_ADDR (UI0902_RES_BASE + 0x06A000UL) /* 3264 bytes */
#define UI0902_BTN_LANG_CN1_W 48
#define UI0902_BTN_LANG_CN1_H 34
#define UI0902_BTN_LANG_CN1_ADDR (UI0902_RES_BASE + 0x072000UL) /* 36572 bytes */
#define UI0902_BTN_LANG_CN1_W 223
#define UI0902_BTN_LANG_CN1_H 82
#define UI0902_BTN_LANG_CN2_ADDR (UI0902_RES_BASE + 0x06B000UL) /* 3332 bytes */
#define UI0902_BTN_LANG_CN2_W 49
#define UI0902_BTN_LANG_CN2_H 34
#define UI0902_BTN_LANG_CN2_ADDR (UI0902_RES_BASE + 0x07B000UL) /* 36572 bytes */
#define UI0902_BTN_LANG_CN2_W 223
#define UI0902_BTN_LANG_CN2_H 82
#define UI0902_BTN_LANG_EN_ADDR (UI0902_RES_BASE + 0x06C000UL) /* 3332 bytes */
#define UI0902_BTN_LANG_EN_W 49
#define UI0902_BTN_LANG_EN_H 34
#define UI0902_BTN_LANG_EN_ADDR (UI0902_RES_BASE + 0x084000UL) /* 36572 bytes */
#define UI0902_BTN_LANG_EN_W 223
#define UI0902_BTN_LANG_EN_H 82
#define UI0902_BTN_CANCEL_SM_ADDR (UI0902_RES_BASE + 0x06D000UL) /* 3430 bytes */
#define UI0902_BTN_LANG_EN_ON_ADDR (UI0902_RES_BASE + 0x08D000UL) /* 36572 bytes */
#define UI0902_BTN_LANG_EN_ON_W 223
#define UI0902_BTN_LANG_EN_ON_H 82
#define UI0902_ROW_HUB_MIXER_ADDR (UI0902_RES_BASE + 0x096000UL) /* 29436 bytes */
#define UI0902_ROW_HUB_MIXER_W 223
#define UI0902_ROW_HUB_MIXER_H 66
#define UI0902_ROW_HUB_LANG_ADDR (UI0902_RES_BASE + 0x09E000UL) /* 29436 bytes */
#define UI0902_ROW_HUB_LANG_W 223
#define UI0902_ROW_HUB_LANG_H 66
#define UI0902_ROW_HUB_SYSTEM_ADDR (UI0902_RES_BASE + 0x0A6000UL) /* 29436 bytes */
#define UI0902_ROW_HUB_SYSTEM_W 223
#define UI0902_ROW_HUB_SYSTEM_H 66
#define UI0902_TXT_USB_CONFIRM_ADDR (UI0902_RES_BASE + 0x0AE000UL) /* 153600 bytes */
#define UI0902_TXT_USB_CONFIRM_W 240
#define UI0902_TXT_USB_CONFIRM_H 320
#define UI0902_BTN_USB_CANCEL_DARK_ADDR (UI0902_RES_BASE + 0x0D4000UL) /* 13184 bytes */
#define UI0902_BTN_USB_CANCEL_DARK_W 103
#define UI0902_BTN_USB_CANCEL_DARK_H 64
#define UI0902_BTN_USB_CONFIRM_BLUE_ADDR (UI0902_RES_BASE + 0x0D8000UL) /* 13184 bytes */
#define UI0902_BTN_USB_CONFIRM_BLUE_W 103
#define UI0902_BTN_USB_CONFIRM_BLUE_H 64
#define UI0902_BTN_USB_CANCEL_BLUE_ADDR (UI0902_RES_BASE + 0x0DC000UL) /* 13312 bytes */
#define UI0902_BTN_USB_CANCEL_BLUE_W 104
#define UI0902_BTN_USB_CANCEL_BLUE_H 64
#define UI0902_BTN_CANCEL_SM_ADDR (UI0902_RES_BASE + 0x0E0000UL) /* 3430 bytes */
#define UI0902_BTN_CANCEL_SM_W 49
#define UI0902_BTN_CANCEL_SM_H 35
#define UI0902_BTN_CONFIRM_SM_ADDR (UI0902_RES_BASE + 0x06E000UL) /* 3360 bytes */
#define UI0902_BTN_CONFIRM_SM_ADDR (UI0902_RES_BASE + 0x0E1000UL) /* 3360 bytes */
#define UI0902_BTN_CONFIRM_SM_W 48
#define UI0902_BTN_CONFIRM_SM_H 35
#define UI0902_BTN_CANCEL_SM2_ADDR (UI0902_RES_BASE + 0x06F000UL) /* 3430 bytes */
#define UI0902_BTN_CANCEL_SM2_ADDR (UI0902_RES_BASE + 0x0E2000UL) /* 3430 bytes */
#define UI0902_BTN_CANCEL_SM2_W 49
#define UI0902_BTN_CANCEL_SM2_H 35
#define UI0902_BTN_CONFIRM_SM2_ADDR (UI0902_RES_BASE + 0x070000UL) /* 3430 bytes */
#define UI0902_BTN_CONFIRM_SM2_ADDR (UI0902_RES_BASE + 0x0E3000UL) /* 3430 bytes */
#define UI0902_BTN_CONFIRM_SM2_W 49
#define UI0902_BTN_CONFIRM_SM2_H 35
#define UI0902_BTN_CONFIRM_BIG_ADDR (UI0902_RES_BASE + 0x071000UL) /* 11872 bytes */
#define UI0902_BTN_CONFIRM_BIG_ADDR (UI0902_RES_BASE + 0x0E4000UL) /* 11872 bytes */
#define UI0902_BTN_CONFIRM_BIG_W 106
#define UI0902_BTN_CONFIRM_BIG_H 56
#define UI0902_MIXER_KNOB_ADDR (UI0902_RES_BASE + 0x074000UL) /* 1440 bytes */
#define UI0902_MIXER_KNOB_ADDR (UI0902_RES_BASE + 0x0E7000UL) /* 1440 bytes */
#define UI0902_MIXER_KNOB_W 30
#define UI0902_MIXER_KNOB_H 24
#define UI0902_MIXER_KNOB2_ADDR (UI0902_RES_BASE + 0x075000UL) /* 1104 bytes */
#define UI0902_MIXER_KNOB2_ADDR (UI0902_RES_BASE + 0x0E8000UL) /* 1104 bytes */
#define UI0902_MIXER_KNOB2_W 24
#define UI0902_MIXER_KNOB2_H 23
#define UI0902_MIXER_TRACK_ADDR (UI0902_RES_BASE + 0x076000UL) /* 13330 bytes */
#define UI0902_MIXER_TRACK_ADDR (UI0902_RES_BASE + 0x0E9000UL) /* 13330 bytes */
#define UI0902_MIXER_TRACK_W 31
#define UI0902_MIXER_TRACK_H 215
#define UI0902_TXT_MIXER_BAND_ADDR (UI0902_RES_BASE + 0x07A000UL) /* 700 bytes */
#define UI0902_TXT_MIXER_BAND_ADDR (UI0902_RES_BASE + 0x0ED000UL) /* 700 bytes */
#define UI0902_TXT_MIXER_BAND_W 25
#define UI0902_TXT_MIXER_BAND_H 14
#define UI0902_TXT_MIXER_GUITAR_ADDR (UI0902_RES_BASE + 0x07B000UL) /* 336 bytes */
#define UI0902_TXT_MIXER_GUITAR_ADDR (UI0902_RES_BASE + 0x0EE000UL) /* 336 bytes */
#define UI0902_TXT_MIXER_GUITAR_W 12
#define UI0902_TXT_MIXER_GUITAR_H 14
#define UI0902_TXT_MIXER_MIC_ADDR (UI0902_RES_BASE + 0x07C000UL) /* 338 bytes */
#define UI0902_TXT_MIXER_MIC_ADDR (UI0902_RES_BASE + 0x0EF000UL) /* 338 bytes */
#define UI0902_TXT_MIXER_MIC_W 13
#define UI0902_TXT_MIXER_MIC_H 13
#define UI0902_TXT_MIXER_VOCALFX_ADDR (UI0902_RES_BASE + 0x07D000UL) /* 1036 bytes */
#define UI0902_TXT_MIXER_VOCALFX_ADDR (UI0902_RES_BASE + 0x0F0000UL) /* 1036 bytes */
#define UI0902_TXT_MIXER_VOCALFX_W 37
#define UI0902_TXT_MIXER_VOCALFX_H 14
#define UI0902_TXT_MIXER_GUITARFX_ADDR (UI0902_RES_BASE + 0x07E000UL) /* 962 bytes */
#define UI0902_TXT_MIXER_GUITARFX_ADDR (UI0902_RES_BASE + 0x0F1000UL) /* 962 bytes */
#define UI0902_TXT_MIXER_GUITARFX_W 37
#define UI0902_TXT_MIXER_GUITARFX_H 13
#define UI0902_TXT_EFFECT_AMOUNT_ADDR (UI0902_RES_BASE + 0x07F000UL) /* 576 bytes */
#define UI0902_TXT_EFFECT_AMOUNT_ADDR (UI0902_RES_BASE + 0x0F2000UL) /* 576 bytes */
#define UI0902_TXT_EFFECT_AMOUNT_W 32
#define UI0902_TXT_EFFECT_AMOUNT_H 9
#define UI0902_TXT_BAND_VOLUME_ADDR (UI0902_RES_BASE + 0x080000UL) /* 702 bytes */
#define UI0902_TXT_BAND_VOLUME_ADDR (UI0902_RES_BASE + 0x0F3000UL) /* 702 bytes */
#define UI0902_TXT_BAND_VOLUME_W 39
#define UI0902_TXT_BAND_VOLUME_H 9
#define UI0902_TXT_MIC_VOLUME_ADDR (UI0902_RES_BASE + 0x081000UL) /* 576 bytes */
#define UI0902_TXT_MIC_VOLUME_ADDR (UI0902_RES_BASE + 0x0F4000UL) /* 576 bytes */
#define UI0902_TXT_MIC_VOLUME_W 32
#define UI0902_TXT_MIC_VOLUME_H 9
#define UI0902_TXT_RESTORE_V1_ADDR (UI0902_RES_BASE + 0x082000UL) /* 1680 bytes */
#define UI0902_TXT_RESTORE_V1_ADDR (UI0902_RES_BASE + 0x0F5000UL) /* 1680 bytes */
#define UI0902_TXT_RESTORE_V1_W 21
#define UI0902_TXT_RESTORE_V1_H 40
#define UI0902_TXT_RESTORE_V2_ADDR (UI0902_RES_BASE + 0x083000UL) /* 1680 bytes */
#define UI0902_TXT_RESTORE_V2_ADDR (UI0902_RES_BASE + 0x0F6000UL) /* 1680 bytes */
#define UI0902_TXT_RESTORE_V2_W 21
#define UI0902_TXT_RESTORE_V2_H 40
#define UI0902_TXT_RESTORE_H_ADDR (UI0902_RES_BASE + 0x084000UL) /* 1128 bytes */
#define UI0902_TXT_RESTORE_H_ADDR (UI0902_RES_BASE + 0x0F7000UL) /* 1128 bytes */
#define UI0902_TXT_RESTORE_H_W 47
#define UI0902_TXT_RESTORE_H_H 12
#define UI0902_TXT_RESTORE_CONFIRM_ADDR (UI0902_RES_BASE + 0x085000UL) /* 1988 bytes */
#define UI0902_TXT_RESTORE_CONFIRM_ADDR (UI0902_RES_BASE + 0x0F8000UL) /* 1988 bytes */
#define UI0902_TXT_RESTORE_CONFIRM_W 71
#define UI0902_TXT_RESTORE_CONFIRM_H 14
#define UI0902_BOOT_LOGO_ADDR (UI0902_RES_BASE + 0x086000UL) /* 153600 bytes */
#define UI0902_BOOT_LOGO_ADDR (UI0902_RES_BASE + 0x0F9000UL) /* 153600 bytes */
#define UI0902_BOOT_LOGO_W 240
#define UI0902_BOOT_LOGO_H 320
#define UI0902_CHARGE_SCREEN_ADDR (UI0902_RES_BASE + 0x0AC000UL) /* 153600 bytes */
#define UI0902_CHARGE_SCREEN_ADDR (UI0902_RES_BASE + 0x11F000UL) /* 153600 bytes */
#define UI0902_CHARGE_SCREEN_W 240
#define UI0902_CHARGE_SCREEN_H 320
#define UI0902_FLASH_MODE_ADDR (UI0902_RES_BASE + 0x0D2000UL) /* 153600 bytes */
#define UI0902_FLASH_MODE_ADDR (UI0902_RES_BASE + 0x145000UL) /* 153600 bytes */
#define UI0902_FLASH_MODE_W 240
#define UI0902_FLASH_MODE_H 320
#define UI0902_BTN_CANCEL_BIG_ADDR (UI0902_RES_BASE + 0x0F8000UL) /* 11872 bytes */
#define UI0902_LOWBAT_TIP_ADDR (UI0902_RES_BASE + 0x16B000UL) /* 153600 bytes */
#define UI0902_LOWBAT_TIP_W 240
#define UI0902_LOWBAT_TIP_H 320
#define UI0902_BTN_CANCEL_BIG_ADDR (UI0902_RES_BASE + 0x191000UL) /* 11872 bytes */
#define UI0902_BTN_CANCEL_BIG_W 106
#define UI0902_BTN_CANCEL_BIG_H 56

View File

@ -37,6 +37,7 @@
#include "Drv_ILI9341_Lcd_Image.h"
#include "Drv_ILI9341_Lcd_Image_UI0902.h"
#include "Drv_ILI9341_Lcd_Image_ChargePct.h"
#include "Drv_ILI9341_Lcd_Image_SysSet.h"
#include "UI0902_Res_Addr.h"
#include "ExtFlash_Tone_Addr.h"
#include "LocalSongNames.h"
@ -74,6 +75,8 @@
#include "UI_Setting.h"
#include "UI_SystemSet.h"
#include "UI_Mixer.h"
#include "UI_Language.h"
#include "UI_UsbModeConfirm.h"
#include "app.h"
#include "app_tm1629.h"

View File

@ -9,6 +9,9 @@
void USART2_SendData(uint8_t *data, uint16_t len);
void USART4_SendData(uint8_t *data, uint16_t len);
/* 等待 UART4 发送环形缓冲排空(供关机 ACK 等场景) */
void USART4_WaitTxIdle(uint32_t timeout_ms);
/* 接收出队:返回 1=取到数据,0=队列空 */
uint8_t USART2_RxPop(uint8_t *c);
uint8_t UART4_RxPop(uint8_t *c);

View File

@ -61,7 +61,8 @@ extern "C" {
void wk_i2c1_init(void);
/* add user code begin exported functions */
/* Probe I2C1 7-bit addresses 0x08..0x77 (address-only, no data write). */
uint8_t wk_i2c1_scan(uint8_t *found, uint8_t max_found);
/* add user code end exported functions */
#ifdef __cplusplus

View File

@ -41,6 +41,9 @@ void wk_tmr6_1ms_init(void);
void wk_tmr6_1ms_tick(void);
uint32_t wk_tmr6_tick_get(void);
/* TMR7 1ms:关机键看门狗(优先级高于 TMR6,主循环卡死仍可关) */
void wk_tmr7_pwrkey_init(void);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,9 @@
/* private includes ----------------------------------------------------------*/
/* add user code begin private includes */
/* 关机键看门狗:与 Global.c 解耦声明,避免 int.c 拉全量 includes */
void Power_Key_IsrTick(void);
void Power_Key_FaultLoop(void);
/* add user code end private includes */
/* private typedef -----------------------------------------------------------*/
@ -110,16 +112,7 @@ void NMI_Handler(void)
*/
void MemManage_Handler(void)
{
/* add user code begin MemoryManagement_IRQ 0 */
/* add user code end MemoryManagement_IRQ 0 */
/* go to infinite loop when memory manage exception occurs */
while (1)
{
/* add user code begin W1_MemoryManagement_IRQ 0 */
/* add user code end W1_MemoryManagement_IRQ 0 */
}
Power_Key_FaultLoop();
}
/**
@ -129,16 +122,7 @@ void MemManage_Handler(void)
*/
void BusFault_Handler(void)
{
/* add user code begin BusFault_IRQ 0 */
/* add user code end BusFault_IRQ 0 */
/* go to infinite loop when bus fault exception occurs */
while (1)
{
/* add user code begin W1_BusFault_IRQ 0 */
/* add user code end W1_BusFault_IRQ 0 */
}
Power_Key_FaultLoop();
}
/**
@ -148,16 +132,7 @@ void BusFault_Handler(void)
*/
void UsageFault_Handler(void)
{
/* add user code begin UsageFault_IRQ 0 */
/* add user code end UsageFault_IRQ 0 */
/* go to infinite loop when usage fault exception occurs */
while (1)
{
/* add user code begin W1_UsageFault_IRQ 0 */
/* add user code end W1_UsageFault_IRQ 0 */
}
Power_Key_FaultLoop();
}
/**
@ -241,6 +216,15 @@ void TMR6_GLOBAL_IRQHandler(void)
//rt_os_tick_callback();
}
/**
* @brief TMR7:关机键看门狗(先于伴奏 TMR6 响应,主循环死锁仍可关)
*/
void TMR7_GLOBAL_IRQHandler(void)
{
tmr_flag_clear(TMR7, TMR_OVF_FLAG);
Power_Key_IsrTick();
}
/* add user code begin 1 */
/* add user code end 1 */

View File

@ -88,9 +88,15 @@ int main(void)
drv_nvm_init();
TaskInit();
timer_init();
/* 关机键看门狗:TMR7 + HardFault hook,与主循环/伴奏 ISR 解耦 */
Power_Key_WatchdogInit();
InitMenuUI();
BSP_HT7178PowerEnable (1);
/* GPIO 默认会拉高蓝牙和 12V。关机充电前先全部关掉,只留主电给屏幕 */
BSP_DreamCorePowerEnable(0);
BSP_HT7178PowerEnable(0);
BSP_BlueToothPowerEnable(0);
BSP_ChargerEnable(1);
Power_LogRails("boot");
CurrUIProcress = IdleProcess;
LOG_I("BOOT", "main init done ui=Idle");
/* add user code end 2 */
@ -104,7 +110,11 @@ int main(void)
}
/* add user code begin 3 */
Power_Key_Scan();
System_AudioBringUp_Poll();
Power_ChargeIdle_LogPoll();
AutoPowerOff_Scan();
System_PowerOff_Poll();
System_LowBat_Poll();
LCD_Dump_Poll();
#if !DEBUG_LCD_DUMP
app_log_poll();

View File

@ -3,14 +3,14 @@
#define BUFF_SIZE 512
/* 纯比较宏:参数必须是普通局部变量(非 volatile),
避免同一表达式多次访问 volatile 触发 Pa082 且逻辑不稳 */
/* ?????????????????????????????? volatile????
?????????????????? volatile ???? Pa082 ????????? */
#define IS_FULL(head, tail) ((((head) + 1) % BUFF_SIZE) == (tail))
#define IS_EMPTY(head, tail) ((head) == (tail))
/* ==================== 环形队列结构体 ==================== */
/* ==================== ???????????? ==================== */
/* 一个串口实例的环形队列(收发各一) */
/* ????????????????????????????? */
typedef struct
{
uint8_t rx_buff[BUFF_SIZE];
@ -21,14 +21,14 @@ typedef struct
volatile uint16_t tx_head;
volatile uint16_t tx_tail;
usart_type *usart; /* 关联的串口外设(USART2 / UART4) */
usart_type *usart; /* ??????????????USART2 / UART4?? */
} uart_ring_t;
/* USART2 和 UART4 各一个实例 */
/* USART2 ?? UART4 ???????? */
static uart_ring_t uart2;
static uart_ring_t uart4;
/* 初始化:关联串口外设(由 wk_usart2_init / wk_uart4_init 调用) */
/* ?????????????????????? wk_usart2_init / wk_uart4_init ????? */
void uart_ring_usart2_init(void)
{
uart2.usart = USART2;
@ -39,19 +39,19 @@ void uart_ring_uart4_init(void)
uart4.usart = UART4;
}
/* ==================== 通用入队/出队(带实例参数) ==================== */
/* ==================== ??????/???????????????? ==================== */
/* 入队(ISR 调用)。先快照 volatile 值再操作,避免 Pa082 */
/* ????ISR ???????????? volatile ???????????? Pa082 */
static void ring_rx_push(uart_ring_t *rb, uint8_t c)
{
uint16_t h = rb->rx_head;
uint16_t t = rb->rx_tail;
if(IS_FULL(h, t)) return; /* 满则丢,防止覆盖未读数据 */
if(IS_FULL(h, t)) return; /* ???????????????????? */
rb->rx_buff[h] = c;
rb->rx_head = (h + 1) % BUFF_SIZE;
}
/* 出队(业务线程调用) */
/* ??????????????? */
static uint8_t ring_rx_pop(uart_ring_t *rb, uint8_t *c)
{
uint16_t h = rb->rx_head;
@ -62,65 +62,81 @@ static uint8_t ring_rx_pop(uart_ring_t *rb, uint8_t *c)
return 1;
}
/* 写入 tx 队列(调用前应已关中断,防止 ISR 同时读) */
/* ???? tx ??????????????????????? ISR ?????? */
static void ring_tx_write(uart_ring_t *rb, uint8_t *data, uint16_t len)
{
uint16_t h = rb->tx_head;
uint16_t t = rb->tx_tail;
for(uint16_t i = 0; i < len; i++)
{
if(IS_FULL(h, t)) break; /* 用 tx 判满 */
if(IS_FULL(h, t)) break; /* ?? tx ???? */
rb->tx_buff[h] = data[i];
h = (h + 1) % BUFF_SIZE;
}
rb->tx_head = h; /* 最后一次性写回 volatile */
rb->tx_head = h; /* ???????????? volatile */
}
/* ==================== 发送接口(带串口参数) ==================== */
/* ==================== ?????????????????? ==================== */
/* 通用发送:关中断 → 写队列 → 开 TDBE 中断触发发送 */
/* ?????????????? ?? ?????? ?? ?? TDBE ??????????? */
static void uart_ring_send(uart_ring_t *rb, uint8_t *data, uint16_t len)
{
rt_base_t level = rt_hw_interrupt_disable();
ring_tx_write(rb, data, len);
usart_interrupt_enable(rb->usart, USART_TDBE_INT, TRUE); /* 开发送中断 */
usart_interrupt_enable(rb->usart, USART_TDBE_INT, TRUE); /* ?????????? */
rt_hw_interrupt_enable(level);
}
/* USART2 发送(对外,midi_send.c 等在用) */
/* USART2 ?????????midi_send.c ??????? */
void USART2_SendData(uint8_t *data, uint16_t len)
{
uart_ring_send(&uart2, data, len);
}
/* UART4 发送(对外) */
/* UART4 ????????? */
void USART4_SendData(uint8_t *data, uint16_t len)
{
uart_ring_send(&uart4, data, len);
}
/* USART2 接收出队(对外) */
void USART4_WaitTxIdle(uint32_t timeout_ms)
{
uint32_t t0 = rt_tick_get();
while ((rt_tick_get() - t0) < rt_tick_from_millisecond(timeout_ms ? timeout_ms : 1))
{
uint16_t h = uart4.tx_head;
uint16_t t = uart4.tx_tail;
if (IS_EMPTY(h, t))
{
/* <20><><EFBFBD><EFBFBD>պ<EFBFBD><D5BA>ٵ<EFBFBD><D9B5><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
if (usart_flag_get(uart4.usart, USART_TDC_FLAG) == SET)
return;
}
rt_thread_mdelay(1);
}
}
/* USART2 ???????????? */
uint8_t USART2_RxPop(uint8_t *c)
{
return ring_rx_pop(&uart2, c);
}
/* UART4 接收出队(对外) */
/* UART4 ???????????? */
uint8_t UART4_RxPop(uint8_t *c)
{
return ring_rx_pop(&uart4, c);
}
/* ==================== 串口中断 ==================== */
/* ==================== ???????? ==================== */
static void uart_ring_isr(uart_ring_t *rb)
{
/* 接收:收到字节 → 入 rx 队列 */
if(usart_flag_get(rb->usart, USART_RDBF_FLAG) == SET)
{
uint8_t data = usart_data_receive(rb->usart); /* 读数据(自动清 RDBF) */
uint8_t data = usart_data_receive(rb->usart);
ring_rx_push(rb, data);
if(rb->usart == UART4)
{
@ -128,7 +144,6 @@ static void uart_ring_isr(uart_ring_t *rb)
}
}
/* 发送:tx 队列有数据 → 发一个字节;发完 → 关 TDBE 中断 */
if(usart_flag_get(rb->usart, USART_TDBE_FLAG) == SET)
{
uint16_t h = rb->tx_head;
@ -140,11 +155,10 @@ static void uart_ring_isr(uart_ring_t *rb)
}
else
{
usart_interrupt_enable(rb->usart, USART_TDBE_INT, FALSE); /* 发完关中断 */
usart_interrupt_enable(rb->usart, USART_TDBE_INT, FALSE);
}
}
/* 错误处理:清溢出标志,防止反复进中断卡死 */
if(usart_flag_get(rb->usart, USART_ROERR_FLAG) == SET)
usart_flag_clear(rb->usart, USART_ROERR_FLAG);
}

View File

@ -84,5 +84,66 @@ void wk_i2c1_init(void)
}
/* add user code begin 1 */
#include "i2c_application.h"
#define I2C_SCAN_ADDR_MIN 0x08U
#define I2C_SCAN_ADDR_MAX 0x77U
#define I2C_SCAN_TIMEOUT 8000U
extern i2c_status_type i2c_master_write_addr(i2c_handle_type *hi2c, uint16_t address, uint32_t timeout);
static void wk_i2c1_recover(void)
{
i2c_reset(I2C1);
wk_i2c1_init();
}
/* Address-only probe: START + 8-bit write address + STOP. No register write. */
static uint8_t wk_i2c1_probe(uint8_t addr7)
{
i2c_handle_type hi2c;
i2c_status_type status;
uint16_t addr8;
memset(&hi2c, 0, sizeof(hi2c));
hi2c.i2cx = I2C1;
addr8 = (uint16_t)((uint16_t)addr7 << 1);
if (i2c_wait_flag(&hi2c, I2C_BUSYF_FLAG, I2C_EVENT_CHECK_NONE, I2C_SCAN_TIMEOUT) != I2C_OK) {
wk_i2c1_recover();
return 0U;
}
status = i2c_master_write_addr(&hi2c, addr8, I2C_SCAN_TIMEOUT);
if (status == I2C_OK) {
i2c_flag_clear(I2C1, I2C_ADDR7F_FLAG);
i2c_stop_generate(I2C1);
(void)i2c_wait_flag(&hi2c, I2C_BUSYF_FLAG, I2C_EVENT_CHECK_NONE, I2C_SCAN_TIMEOUT);
return 1U;
}
i2c_stop_generate(I2C1);
wk_i2c1_recover();
return 0U;
}
uint8_t wk_i2c1_scan(uint8_t *found, uint8_t max_found)
{
uint8_t n = 0U;
uint8_t addr;
wk_i2c1_init();
for (addr = I2C_SCAN_ADDR_MIN; addr <= I2C_SCAN_ADDR_MAX; addr++) {
if (wk_i2c1_probe(addr) != 0U) {
if (found != 0 && n < max_found) {
found[n] = addr;
}
n++;
}
}
wk_i2c1_init();
return n;
}
/* add user code end 1 */

View File

@ -132,7 +132,8 @@ volatile uint32_t tmr6_ticks;
*/
__WEAK void wk_tmr6_1ms_tick(void)
{
AutoBandTop1_Metronome_External_1msTick();
if (Band_TickGate)
AutoBandTop1_Metronome_External_1msTick();
}
/**
@ -174,3 +175,16 @@ void wk_tmr6_1ms_init(void)
tmr_counter_enable(TMR6, TRUE);
}
/**
* @brief TMR7 1ms:仅扫关机键(抢占优先级 1,高于 TMR6=5 / 伴奏库)
*/
void wk_tmr7_pwrkey_init(void)
{
crm_periph_clock_enable(CRM_TMR7_PERIPH_CLOCK, TRUE);
tmr_base_init(TMR7, 999, 239);
tmr_flag_clear(TMR7, TMR_OVF_FLAG);
tmr_interrupt_enable(TMR7, TMR_OVF_INT, TRUE);
nvic_irq_enable(TMR7_GLOBAL_IRQn, 1, 0);
tmr_counter_enable(TMR7, TRUE);
}

View File

@ -1,4 +1,5 @@
#include "includes.h"
#include "git_user_fw_ver.h"
// Э<><D0AD>֡ͷ/֡β
@ -25,7 +26,7 @@ typedef enum
UART4_RCV_BUFF_MIDIEND
} UART4_RCV_StatusType;
#define UART4_PROCESS_BUFF_SIZE 32
#define UART4_PROCESS_BUFF_SIZE 64 /* 02 04 full chord-map frame is 47 bytes */
// UART4<54><34><EFBFBD><EFBFBD>ȫ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD>
static UART4_RCV_StatusType UART4_RCV_Status = UART4_RCV_BUFF_IDLE;
@ -48,22 +49,25 @@ typedef struct
// ==============================
// ָ<><EFBFBD><EEB4A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><C8AB> static<69><63>
// ==============================
//static void handleDevDisconnect(uint8_t *data);
//static void handleDevConnect(uint8_t *data);
//static void handleDevName(uint8_t *data);
//static void handleFwMainVer(uint8_t *data);
//static void handleSoundVer(uint8_t *data);
//static void handleUIVer(uint8_t *data);
//static void handleOtherInfo(uint8_t *data);
//static void handleDevCode(uint8_t *data);
//static void handleAutoPowerOff(uint8_t *data);
static void handleDevDisconnect(uint8_t *data);
static void handleDevConnect(uint8_t *data);
static void handleDevName(uint8_t *data);
static void handleFwMainVer(uint8_t *data);
static void handleSoundVer(uint8_t *data);
static void handleUIVer(uint8_t *data);
static void handleOtherInfo(uint8_t *data);
static void handleDevCode(uint8_t *data);
static void handleAutoPowerOff(uint8_t *data);
static void handleUserFwVer(uint8_t *data);
static void handleAutoPowerOffSet(uint8_t *data);
static void handleFwCode(uint8_t *data);
static void handleReadRhythmMap(uint8_t *data);
static void handlePitchOffset(uint8_t *data);
static void handleChordOffset(uint8_t *data);
//static void handleResetChordMap(uint8_t *data);
static void handleResetChordMap(uint8_t *data);
//static void handleRhythmStyle(uint8_t *data);
static void handleRhythmStyle(uint8_t *data);
static void handleStringTimbre(uint8_t *data);
static void handleBPM(uint8_t *data);
static void handleTranspose(uint8_t *data);
@ -75,9 +79,8 @@ static void handleLED3(uint8_t *data);
static void handleLED4(uint8_t *data);
static void handleLED5(uint8_t *data);
static void handleLED6(uint8_t *data);
//static void handleStopPlay(uint8_t *data);
//static void handleDeviceReset(uint8_t *data);
static void handleDeviceReset(uint8_t *data);
static void handleIntro(uint8_t *data);
static void handleInterlude(uint8_t *data);
@ -88,6 +91,9 @@ static void handleSectionB(uint8_t *data);
static void handleSectionC(uint8_t *data);
static void handleSectionD(uint8_t *data);
static void handleAmpRamRead(uint8_t *data);
static void handleAmpRamWrite(uint8_t *data);
@ -98,52 +104,58 @@ static void handleSectionD(uint8_t *data);
*************************************************/
static const BLE_SysExCmdItem bleSysExCmdTable[] =
{
// //======== 1. <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ 0x01 ========
// {{0x01, 0x00}, handleDevDisconnect}, // <20>Ͽ<EFBFBD><CFBF>豸
// {{0x01, 0x01}, handleDevConnect}, // <20><><EFBFBD><EFBFBD><EFBFBD>豸
// {{0x01, 0x02}, handleDevName}, // <20><>ȡ<EFBFBD>豸<EFBFBD><E8B1B8>
// {{0x01, 0x03}, handleFwMainVer}, // <20>̼<EFBFBD><CCBC><EFBFBD><EFBFBD>汾
// {{0x01, 0x04}, handleSoundVer}, // <20><>Դ<EFBFBD>汾
// {{0x01, 0x05}, handleUIVer}, // UI<55>汾
// {{0x01, 0x06}, handleOtherInfo}, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
// {{0x01, 0x07}, handleDevCode}, // <20>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD>
// {{0x01, 0x0A}, handleAutoPowerOff}, // <20>Զ<EFBFBD><D4B6>ػ<EFBFBD>
//
// //======== 2. ӳ<><D3B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0x02 ========
{{0x02, 0x01}, handleReadRhythmMap}, // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD>
{{0x02, 0x02}, handlePitchOffset}, // Pitchƫ<68><C6AB>
{{0x02, 0x03}, handleChordOffset}, // Chordƫ<64><C6AB>
// {{0x02, 0x04}, handleResetChordMap}, // <20><><EFBFBD>ú<EFBFBD><C3BA><EFBFBD>ӳ<EFBFBD><D3B3>Ĭ<EFBFBD><C4AC>ֵ
/*======== 1. device info 0x01 ========*/
{{0x01, 0x00}, handleDevDisconnect}, /* disconnect */
{{0x01, 0x01}, handleDevConnect}, /* connect */
{{0x01, 0x02}, handleDevName}, /* device name */
{{0x01, 0x03}, handleFwMainVer}, /* fw main version */
{{0x01, 0x04}, handleSoundVer}, /* sound version */
{{0x01, 0x05}, handleUIVer}, /* UI version */
{{0x01, 0x06}, handleOtherInfo}, /* other info */
{{0x01, 0x07}, handleDevCode}, /* device code (96bit UID) */
{{0x01, 0x0A}, handleAutoPowerOff}, /* auto power-off read (minutes) */
{{0x01, 0x0C}, handleUserFwVer}, /* user fw version */
{{0x01, 0x11}, handleAutoPowerOffSet}, /* auto power-off set (minutes) */
{{0x01, 0x0F}, handleFwCode}, /* fw code (MIDI/BLE-safe; replaces 01 FF) */
{{0x01, 0xFF}, handleFwCode}, /* fw code alias (raw UART only; 0xFF illegal in BLE-MIDI SysEx) */
//======== 3. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д 0x03 ========
// {{0x03, 0x04}, handleRhythmStyle}, // <20><>ȡ/<2F><><EFBFBD>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD>
{{0x03, 0x05}, handleStringTimbre}, // <20><>ȡ/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
{{0x03, 0x06}, handleBPM}, // <20><>ȡ/<2F><><EFBFBD><EFBFBD>BPM
{{0x03, 0x07}, handleTranspose}, // <20><>ȡ/<2F><><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD>
/*======== 2. chord map 0x02 ========*/
{{0x02, 0x01}, handleReadRhythmMap}, /* read chord/pitch map */
{{0x02, 0x02}, handlePitchOffset}, /* pitch offset */
{{0x02, 0x03}, handleChordOffset}, /* chord offset */
{{0x02, 0x04}, handleResetChordMap}, /* write whole map (default reset) */
//======== 4. <20><><EFBFBD><EFBFBD>/LED<45><44><EFBFBD><EFBFBD> 0x04 ========
{{0x04, 0x00}, handleLED0}, // <20><>1<EFBFBD><31>LED
{{0x04, 0x01}, handleLED1}, // <20><>2<EFBFBD><32>LED
{{0x04, 0x02}, handleLED2}, // <20><>3<EFBFBD><33>LED
{{0x04, 0x03}, handleLED3}, // <20><>4<EFBFBD><34>LED
{{0x04, 0x04}, handleLED4}, // <20><>5<EFBFBD><35>LED
{{0x04, 0x05}, handleLED5}, // <20><>6<EFBFBD><36>LED
{{0x04, 0x06}, handleLED6}, // <20><>7<EFBFBD><37>LED
// {{0x04, 0x07}, handleStopPlay}, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/*======== 3. guitar params 0x03 ========*/
{{0x03, 0x04}, handleRhythmStyle}, /* rhythm style r/w + user list */
{{0x03, 0x05}, handleStringTimbre}, /* string timbre r/w */
{{0x03, 0x06}, handleBPM}, /* BPM r/w */
{{0x03, 0x07}, handleTranspose}, /* transpose r/w */
// //======== 5. <20><>λ/<2F>ػ<EFBFBD> 0x05 ========
// {{0x05, 0x00}, handleDeviceReset}, // <20>豸<EFBFBD><E8B1B8>λ
//
// //======== 6. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת 0x06 ========
{{0x06, 0x01}, handleIntro}, // ǰ<><C7B0>
{{0x06, 0x02}, handleInterlude}, // <20><><EFBFBD><EFBFBD>
{{0x06, 0x03}, handleOutro}, // β<><CEB2>
{{0x04, 0x07}, handleEnd}, // end
{{0x06, 0x05}, handleSectionA}, // A<><41>
{{0x06, 0x06}, handleSectionB}, // B<><42>
{{0x06, 0x07}, handleSectionC}, // C<><43>
{{0x06, 0x08}, handleSectionD}, // D<><44>
/*======== 4. play / LED 0x04 ========*/
{{0x04, 0x00}, handleLED0}, /* LED 1 */
{{0x04, 0x01}, handleLED1}, /* LED 2 */
{{0x04, 0x02}, handleLED2}, /* LED 3 */
{{0x04, 0x03}, handleLED3}, /* LED 4 */
{{0x04, 0x04}, handleLED4}, /* LED 5 */
{{0x04, 0x05}, handleLED5}, /* LED 6 */
{{0x04, 0x06}, handleLED6}, /* LED 7 */
{{0x04, 0x07}, handleEnd}, /* end / stop play */
/*======== 5. reset / power off 0x05 ========*/
{{0x05, 0x00}, handleDeviceReset}, /* device reset -> soft power off */
/*======== 6. section jump 0x06 ========*/
{{0x06, 0x01}, handleIntro}, /* intro */
{{0x06, 0x02}, handleInterlude}, /* interlude */
{{0x06, 0x03}, handleOutro}, /* outro */
{{0x06, 0x05}, handleSectionA}, /* section A */
{{0x06, 0x06}, handleSectionB}, /* section B */
{{0x06, 0x07}, handleSectionC}, /* section C */
{{0x06, 0x08}, handleSectionD}, /* section D */
/*======== 7. amp RAM (AD85050 CH2 EQ16/17/18) 0x07 ========*/
{{0x07, 0x00}, handleAmpRamRead}, /* read 24-bit coeff 0xA0..0xAE */
{{0x07, 0x01}, handleAmpRamWrite}, /* write 24-bit coeff 0xA0..0xAE */
};
// ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
@ -158,14 +170,16 @@ static const BLE_SysExCmdItem bleSysExCmdTable[] =
*/
void processBLESysEXData(uint8_t* data, uint8_t cnt)
{
//ResetAutoPowerCount();
// <20><><EFBFBD><EFBFBD>֡У<D6A1><D0A3>
// ֡У<D6A1><D0A3>
if (data[0] != FRAME_SYS_HEAD || data[cnt - 1] != FRAME_SYS_TAIL || cnt > UART4_PROCESS_BUFF_SIZE || data[1] != 0x60)
{
return;
}
/* App/BLE 活动视为用户操作,避免测协议时静置触发自动关机 */
ResetAutoPowerCount();
LOG_I("BLE", "sysex ok len=%u cmd=%02X %02X", (unsigned)cnt, data[2], data[3]);
// <20><>ȡ <20><>ָ<EFBFBD><D6B8> + <20><>ָ<EFBFBD><D6B8>
// ȡ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD> + <20><>ָ<EFBFBD><D6B8>
uint8_t cmd[2] = {data[2], data[3]};
// <20><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>ƥ<EFBFBD><C6A5>
@ -195,6 +209,7 @@ void UART4_Data_Process(volatile uint8_t* data)
last_tick = now;
memset(UART4_Process_Buff, 0, sizeof(UART4_Process_Buff));
UART4_RCV_cnt = 0;
UART4_RCV_Status = UART4_RCV_BUFF_IDLE;
}
switch (UART4_RCV_Status)
@ -251,7 +266,6 @@ void UART4_Data_Process(volatile uint8_t* data)
}
else
{
// <20>Ƿ<EFBFBD><C7B7>ֽڣ<D6BD><DAA3><EFBFBD>λ
UART4_RCV_Status = UART4_RCV_BUFF_IDLE;
}
break;
@ -315,15 +329,18 @@ static void handleStringTimbre(uint8_t *data)
uint8_t new_val = data[6]; // <20>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>ɫֵ
// <20><><EFBFBD>ֵû<D6B5>䣬ֱ<E4A3AC><D6B1><EFBFBD>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD>ˢ<EFBFBD><CBA2>
if (new_val > mGuiData[GUI_TIMBRE_SELECT].Max)
{
return;
}
if (new_val == mGuiData[GUI_TIMBRE_SELECT].Current)
{
return;
}
mGuiData[GUI_TIMBRE_SELECT].Current = new_val;
if(mGuiData[GUI_TAB_INDEX].Current != 3)
{
//Refresh_StringTimbre(last_value, &UI_Label[GUI_TIMBRE_SELECT], &mGuiData[GUI_TIMBRE_SELECT]);
}
/* LCD 刷新转到 UI 任务执行:TaskBTRecv 栈仅 768B,
直接绘制易栈溢出并与 UI 任务并发访问 LCD(死机/花屏) */
MainTask_Sendmsg(MSG_ID_BLE_UI_REFRESH, GUI_TIMBRE_SELECT, 0, 0);
if(nvm->param.Timbre != mGuiData[GUI_TIMBRE_SELECT].Current)
{
nvm->param.Timbre = mGuiData[GUI_TIMBRE_SELECT].Current;
@ -346,8 +363,9 @@ static void handleTranspose(uint8_t *data)
{
case 0:
{
uint8_t ReturnTranspose[8] = {0xF0,0x60,0x03,0x07,0x00,0x00,0x00,0xF7};
ReturnTranspose[5] = mGuiData[GUI_TRANSPOSE].Current;
/* doc: F0 60 03 07 00 <val> F7 (7 bytes total) */
uint8_t ReturnTranspose[7] = {0xF0,0x60,0x03,0x07,0x00,0x00,0xF7};
ReturnTranspose[5] = (uint8_t)mGuiData[GUI_TRANSPOSE].Current;
USART4_SendData(ReturnTranspose,sizeof(ReturnTranspose));
}
break;
@ -362,10 +380,7 @@ static void handleTranspose(uint8_t *data)
return;
}
mGuiData[GUI_TRANSPOSE].Current = new_val;
if(mGuiData[GUI_TAB_INDEX].Current != 3)
{
Refresh_Transpose(&UI_Label[GUI_TRANSPOSE], &mGuiData[GUI_TRANSPOSE]);
}
MainTask_Sendmsg(MSG_ID_BLE_UI_REFRESH, GUI_TRANSPOSE, 0, 0);
if(nvm->param.Transpose != mGuiData[GUI_TRANSPOSE].Current)
{
nvm->param.Transpose = mGuiData[GUI_TRANSPOSE].Current;
@ -415,7 +430,6 @@ static void handleBPM(uint8_t *data)
case 1:
{
NvmParam_Type * nvm = drv_nvm_param_ptr();
uint16_t new_val = Calc_BPM(data[5],data[6]);
// <20><><EFBFBD>ֵû<D6B5>䣬ֱ<E4A3AC><D6B1><EFBFBD>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD>ˢ<EFBFBD><CBA2>
@ -424,15 +438,8 @@ static void handleBPM(uint8_t *data)
return;
}
mGuiData[GUI_SPEED].Current = new_val;
if(mGuiData[GUI_TAB_INDEX].Current != 3)
{
Refresh_Transpose(&UI_Label[GUI_SPEED], &mGuiData[GUI_SPEED]);
}
if(nvm->param.BPM != mGuiData[GUI_SPEED].Current)
{
nvm->param.BPM = mGuiData[GUI_SPEED].Current;
drv_nvm_save_to_flash();
}
MainTask_Sendmsg(MSG_ID_BLE_UI_REFRESH, GUI_SPEED, 0, 0);
/* 手调 BPM 不写入下次开机 */
AutoBandTop1_ChangeBPM(mGuiData[GUI_SPEED].Current);
}
break;
@ -472,25 +479,42 @@ static void handleLED6(uint8_t *data)
static void handlePitchOffset(uint8_t *data)
{
BL_Sendmsg(MSG_ID_PITCH_OFFSET, data[4]+1, data[5], 0);
uint8_t key = (uint8_t)(data[4] + 1u);
if (key < 1u || key > 21u)
return;
BL_Sendmsg(MSG_ID_PITCH_OFFSET, key, data[5], 0);
}
static void handleChordOffset(uint8_t *data)
{
BL_Sendmsg(MSG_ID_CHORD_OFFSET, data[4]+1, data[5], 0);
uint8_t key = (uint8_t)(data[4] + 1u);
if (key < 1u || key > 21u)
return;
BL_Sendmsg(MSG_ID_CHORD_OFFSET, key, data[5], 0);
}
extern CHORD_TYPE_INDEX chord_type_index_map[22];
static void handleReadRhythmMap(uint8_t *data)
{
uint8_t ReadChordMap[47] = {0xF0, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7};
/* 静态缓冲:禁止在 TaskBTRecv 小栈上再开 47B */
static uint8_t ReadChordMap[47];
uint8_t chord_map = 0;
for(uint8_t i = 1;i < 22;i ++)
uint8_t i;
(void)data;
memset(ReadChordMap, 0, sizeof(ReadChordMap));
ReadChordMap[0] = 0xF0;
ReadChordMap[1] = 0x60;
ReadChordMap[2] = 0x02;
ReadChordMap[3] = 0x01;
ReadChordMap[46] = 0xF7;
for (i = 1; i < 22; i++)
{
ReadChordMap[3+i] = chord_type_index_map[i].PitchOffset;
ReadChordMap[3 + i] = chord_type_index_map[i].PitchOffset;
}
for(uint8_t i = 25;i < 46;i ++)
for (i = 25; i < 46; i++)
{
switch(chord_type_index_map[i-24].type)
switch (chord_type_index_map[i - 24].type)
{
case 0:
chord_map = 0;
@ -499,30 +523,33 @@ static void handleReadRhythmMap(uint8_t *data)
chord_map = 8;
break;
case 2:
chord_map = 2;
chord_map = 10; /* m7 -> 0x0A */
break;
case 3:
chord_map = 13;
chord_map = 13; /* 7 -> 0x0D */
break;
case 4:
chord_map = 10;
chord_map = 2; /* M7 -> 0x02 */
break;
case 5:
chord_map = 31;
chord_map = 4; /* ad9 -> 0x04 */
break;
case 6:
chord_map = 30;
chord_map = 11; /* m7-5 -> 0x0B */
break;
case 7:
chord_map = 4;
chord_map = 31; /* sus2 -> 0x1F */
break;
case 8:
chord_map = 11;
chord_map = 30; /* sus4 -> 0x1E */
break;
default:
chord_map = 0;
break;
}
ReadChordMap[i] = chord_map;
}
USART4_SendData(ReadChordMap,sizeof(ReadChordMap));
USART4_SendData(ReadChordMap, sizeof(ReadChordMap));
}
static void handleIntro(uint8_t *data)
@ -546,7 +573,7 @@ static void handleEnd(uint8_t *data)
// TM1629D_AllLedOn(LED_COLOR_G);
// TM1629D_UpdateDisplay(0);
// osMutexRelease(Tm1629Mutex);
BL_Sendmsg(MSG_ID_ADCIN1KEY, 1, 0, 0);
BL_Sendmsg(MSG_ID_ADCIN1KEY, 2, 0, 0); /* End -> Postamble(1), distinct from Outro(key=1) */
}
static void handleSectionA(uint8_t *data)
@ -570,3 +597,402 @@ static void BL_Sendmsg(uint16_t Data1, uint16_t Data2, uint16_t Data3, uint16_t
{
BLTask_Sendmsg(Data1, Data2, Data3, Data4);
}
/* ======================================================================
* Appended protocol handlers (per Doc/指令测试.docx)
* ==================================================================== */
/*-------- 1. device info 0x01 --------*/
#define AT32_UID_BASE 0x1FFFF7E8UL /* 96-bit unique device ID */
/* 01 04 音源版本:YY.M.D = 音色资源日期(Dream 无版本查询,发版时手改)
* 26.10.8 → 2026-10-08(Doc/音色文件/1008) */
static const uint8_t SOUND_VER[4] = {26, 10, 8, 0x01};
/* 01 05 UI 资源/界面日期:YY.M.D(与 MCU 逻辑版本 Version[] 分开维护) */
static const uint8_t UI_VER[4] = {26, 9, 9, 0x01};
static void handleDevDisconnect(uint8_t *data)
{
uint8_t resp[6] = {0xF0, 0x60, 0x01, 0x00, 0x01, 0xF7};
(void)data;
AppNeckLed_ClearGuide();
USART4_SendData(resp, sizeof(resp));
}
static void handleDevConnect(uint8_t *data)
{
uint8_t resp[6] = {0xF0, 0x60, 0x01, 0x01, 0x01, 0xF7};
(void)data;
ResetAutoPowerCount();
USART4_SendData(resp, sizeof(resp));
}
static void handleDevName(uint8_t *data)
{
static char name[BLE_DEVICE_NAME_LEN + 1];
static uint8_t resp[4 + BLE_DEVICE_NAME_LEN + 1]; /* head4 + name + F7 */
(void)data;
BleBuildDeviceName(name);
resp[0] = 0xF0; resp[1] = 0x60; resp[2] = 0x01; resp[3] = 0x02;
memcpy(&resp[4], name, BLE_DEVICE_NAME_LEN);
resp[4 + BLE_DEVICE_NAME_LEN] = 0xF7;
USART4_SendData(resp, (uint16_t)sizeof(resp));
}
static void handleFwMainVer(uint8_t *data)
{
uint8_t resp[9] = {0xF0, 0x60, 0x01, 0x03, Version[0], Version[1], Version[2], 0x01, 0xF7};
(void)data;
USART4_SendData(resp, sizeof(resp));
}
static void handleSoundVer(uint8_t *data)
{
uint8_t resp[9] = {0xF0, 0x60, 0x01, 0x04, SOUND_VER[0], SOUND_VER[1], SOUND_VER[2], SOUND_VER[3], 0xF7};
(void)data;
USART4_SendData(resp, sizeof(resp));
}
static void handleUIVer(uint8_t *data)
{
uint8_t resp[9] = {0xF0, 0x60, 0x01, 0x05, UI_VER[0], UI_VER[1], UI_VER[2], UI_VER[3], 0xF7};
(void)data;
USART4_SendData(resp, sizeof(resp));
}
static void handleOtherInfo(uint8_t *data)
{
/* 01 06: reserved — keep 8 zero bytes until product defines fields */
uint8_t resp[13] = {0xF0, 0x60, 0x01, 0x06, 0, 0, 0, 0, 0, 0, 0, 0, 0xF7};
(void)data;
USART4_SendData(resp, sizeof(resp));
}
static void handleDevCode(uint8_t *data)
{
/* 96-bit UID as 24 hex ASCII — SysEx data must stay 7-bit for BLE-MIDI */
static const char hex[] = "0123456789ABCDEF";
uint8_t resp[29];
const uint8_t *uid = (const uint8_t *)AT32_UID_BASE;
uint8_t i;
(void)data;
resp[0] = 0xF0;
resp[1] = 0x60;
resp[2] = 0x01;
resp[3] = 0x07;
for (i = 0; i < 12u; i++)
{
resp[4u + 2u * i] = (uint8_t)hex[uid[i] >> 4];
resp[4u + 2u * i + 1u] = (uint8_t)hex[uid[i] & 0x0Fu];
}
resp[28] = 0xF7;
USART4_SendData(resp, sizeof(resp));
}
static void handleAutoPowerOff(uint8_t *data)
{
uint8_t resp[6] = {0xF0, 0x60, 0x01, 0x0A, 0x00, 0xF7};
(void)data;
resp[4] = AutoCloseTime;
USART4_SendData(resp, sizeof(resp));
}
static void handleUserFwVer(uint8_t *data)
{
/* 用户固件版本 = "{branch}_{short6}"[+ '*'],如 develop_0aedb4(ASCII,BLE-MIDI 安全) */
uint8_t resp[4u + GIT_BUILD_ID_LEN + 1u];
(void)data;
resp[0] = 0xF0;
resp[1] = 0x60;
resp[2] = 0x01;
resp[3] = 0x0C;
memcpy(&resp[4], GIT_BUILD_ID, GIT_BUILD_ID_LEN);
resp[4u + GIT_BUILD_ID_LEN] = 0xF7;
USART4_SendData(resp, (uint16_t)sizeof(resp));
}
/* F0 60 01 11 <minutes> F7 : set auto power-off, 0 = disable */
static void handleAutoPowerOffSet(uint8_t *data)
{
NvmParam_Type *nvm = drv_nvm_param_ptr();
uint8_t resp[6] = {0xF0, 0x60, 0x01, 0x11, 0x00, 0xF7};
AutoCloseTime = data[4];
if (nvm->param.AutoCloseTime != AutoCloseTime)
{
nvm->param.AutoCloseTime = AutoCloseTime;
drv_nvm_save_to_flash();
}
ResetAutoPowerCount();
resp[4] = AutoCloseTime;
USART4_SendData(resp, sizeof(resp));
}
static void handleFwCode(uint8_t *data)
{
/* 固件编码: 请求 01 0F(推荐)或 01 FF(仅裸串口);应答统一 01 0F + ASCII,避免 BLE-MIDI 吃掉 0xFF */
uint8_t resp[16];
uint8_t len = (uint8_t)strlen(fwname);
(void)data;
if (len > 10u)
len = 10u;
resp[0] = 0xF0;
resp[1] = 0x60;
resp[2] = 0x01;
resp[3] = 0x0F;
memcpy(&resp[4], fwname, len);
resp[4 + len] = 0xF7;
USART4_SendData(resp, (uint16_t)(4u + len + 1u));
}
/*-------- 2. chord map 0x02 --------*/
/* F0 60 02 04 <21B pitch> <21B chord> F7 : write whole map; reply in 02 01 format */
static void handleResetChordMap(uint8_t *data)
{
uint8_t key;
for (key = 1; key <= 21; key++)
{
BT_Pitch_offset_map(key, data[3 + key]); /* data[4..24] pitch offsets */
BT_Chord_offset_map(key, data[24 + key]); /* data[25..45] chord types */
}
handleReadRhythmMap(data);
}
/*-------- 3. rhythm style 0x03 0x04 --------*/
static void handleRhythmStyle(uint8_t *data)
{
switch (data[4])
{
case 0: /* read current style: F0 60 03 04 00 <src> <idHi> <idLo> F7 */
{
uint8_t resp[9] = {0xF0, 0x60, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0xF7};
uint8_t src = (uint8_t)(mGuiData[GUI_AUTOBAND_SW].Current ? 1 : 0);
uint16_t id = src ? ParamGuiData[EXPRESS_MODE_PARAM].Current
: ParamGuiData[SONG_MODE_PARAM].Current;
resp[5] = src;
resp[6] = (uint8_t)(id / 128);
resp[7] = (uint8_t)(id % 128);
USART4_SendData(resp, sizeof(resp));
}
break;
case 1: /* set style: F0 60 03 04 01 <src:0 sys/1 user> <idHi> <idLo> F7, reply BPM */
{
uint8_t src = (data[5] != 0) ? 1 : 0;
uint16_t id = (uint16_t)data[6] * 128 + data[7];
GUI_SWITCH *slot = src ? &ParamGuiData[EXPRESS_MODE_PARAM]
: &ParamGuiData[SONG_MODE_PARAM];
uint8_t resp[7] = {0xF0, 0x60, 0x03, 0x04, 0x01, 0x00, 0xF7};
if (src)
slot->Max = (LOCAL_SONG_COUNT > 0) ? (uint16_t)(LOCAL_SONG_COUNT - 1) : 0;
if (id > slot->Max)
id = slot->Max;
mGuiData[GUI_AUTOBAND_SW].Current = src;
slot->Current = id;
/* 停伴奏+换库+LCD 刷新全部转到 UI 任务执行(MSG_ID_BLE_STYLE_SET):
TaskBTRecv 栈仅 768B,ReloadTone 深调用链在此溢出导致 hardfault */
MainTask_Sendmsg(MSG_ID_BLE_STYLE_SET, 0, 0, 0);
/* 与本地切换一致同步 NVM 参数(本地路径同样不立即写 flash) */
{
NvmParam_Type *nvm = drv_nvm_param_ptr();
if (src)
nvm->param.Param2 = ParamGuiData[EXPRESS_MODE_PARAM].Current;
else
nvm->param.Param1 = ParamGuiData[SONG_MODE_PARAM].Current;
}
/* 回复用新曲目的默认 BPM。键留给 UI 任务换库后再提交,避免屏上不刷新 */
{
uint16_t track_bpm = TrackBpm_Peek();
mGuiData[GUI_SPEED].Current = track_bpm;
}
/* doc: single-byte bpm; clamp >127 (App should read exact bpm via 03 06) */
resp[5] = (mGuiData[GUI_SPEED].Current > 0x7F)
? 0x7F : (uint8_t)mGuiData[GUI_SPEED].Current;
USART4_SendData(resp, sizeof(resp));
/* boot / song-entry special: F0 60 03 04 01 00 00 00 F7
doc: also push current BPM as active report F0 51 03 <hi> <lo> F7 */
if (data[5] == 0 && data[6] == 0 && data[7] == 0)
{
uint8_t bpmr[6] = {0xF0, 0x51, 0x03, 0x00, 0x00, 0xF7};
bpmr[3] = (uint8_t)(mGuiData[GUI_SPEED].Current / 128);
bpmr[4] = (uint8_t)(mGuiData[GUI_SPEED].Current % 128);
USART4_SendData(bpmr, sizeof(bpmr));
}
}
break;
case 2: /* user style list page: F0 60 03 04 02 <from3B> <to3B> F7
reply: F0 60 03 04 02 <cntHi> <cntLo> [<idHi> <idLo> <code 4B ascii> ...] F7 */
{
uint8_t resp[64];
uint32_t from = 0, to = LOCAL_SONG_COUNT;
uint16_t i, n = 0, len;
/* from/to: 24-bit big-endian, optional (doc example: 00 00 00 07) */
if (data[5] || data[6] || data[7])
{
from = ((uint32_t)data[5] << 16) | ((uint32_t)data[6] << 8) | data[7];
to = ((uint32_t)data[8] << 16) | ((uint32_t)data[9] << 8) | data[10];
}
if (from > LOCAL_SONG_COUNT) from = LOCAL_SONG_COUNT;
if (to > LOCAL_SONG_COUNT || to <= from) to = LOCAL_SONG_COUNT;
resp[0] = 0xF0; resp[1] = 0x60; resp[2] = 0x03; resp[3] = 0x04; resp[4] = 0x02;
len = 7; /* count filled after loop */
for (i = (uint16_t)from; i < to; i++)
{
if (len + 6 + 1 > sizeof(resp)) break;
resp[len++] = (uint8_t)(i / 128);
resp[len++] = (uint8_t)(i % 128);
memcpy(&resp[len], LocalSongCode[i], 4);
len += 4;
n++;
}
resp[5] = (uint8_t)(n / 128);
resp[6] = (uint8_t)(n % 128);
resp[len++] = 0xF7;
USART4_SendData(resp, len);
}
break;
case 3: /* user style total: reply F0 60 03 04 00 <total 3B BE> F7 (doc: 00 00 1E) */
{
uint8_t resp[9] = {0xF0, 0x60, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0xF7};
resp[5] = (uint8_t)((LOCAL_SONG_COUNT >> 16) & 0xFF);
resp[6] = (uint8_t)((LOCAL_SONG_COUNT >> 8) & 0xFF);
resp[7] = (uint8_t)(LOCAL_SONG_COUNT & 0xFF);
USART4_SendData(resp, sizeof(resp));
}
break;
default:
break;
}
}
/*-------- 7. amp RAM 0x07 : AD85050 Channel-2 EQ16/17/18 (0xA0..0xAE) --------
* BLE-MIDI SysEx 数据必须 <0x80,地址/24bit 值用半字节拆开:
* 0xA0 -> 0A 00
* 0x200000 -> 02 00 00 00 00 00
* 读: F0 60 07 00 <regH> <regL> F7
* 回: F0 60 07 00 <regH> <regL> <6 nibbles> F7
* 写: F0 60 07 01 <regH> <regL> <6 nibbles> F7
* 回: 同写帧;失败 F0 60 07 xx <regH> <regL> 7F F7
*/
#define AMP_RAM_BANK_CH2 1U
static uint8_t amp_parse_reg(const uint8_t *data, uint8_t *reg_out)
{
uint8_t hi = data[4];
uint8_t lo = data[5];
uint8_t reg;
if (hi > 0x0FU || lo > 0x0FU)
return 0U;
reg = (uint8_t)((hi << 4) | lo);
if (reg < AD85020B_RAM_CH2_EQ16_A1 || reg > AD85020B_RAM_CH2_EQ18_A0)
return 0U;
*reg_out = reg;
return 1U;
}
static uint8_t amp_parse_u24(const uint8_t *nib, uint32_t *val_out)
{
uint8_t i;
uint32_t v = 0;
for (i = 0U; i < 6U; i++)
{
if (nib[i] > 0x0FU)
return 0U;
v = (v << 4) | (uint32_t)nib[i];
}
*val_out = v;
return 1U;
}
static void amp_put_reg_nibbles(uint8_t *dst, uint8_t reg)
{
dst[0] = (uint8_t)((reg >> 4) & 0x0FU);
dst[1] = (uint8_t)(reg & 0x0FU);
}
static void amp_put_u24_nibbles(uint8_t *dst, uint32_t value)
{
dst[0] = (uint8_t)((value >> 20) & 0x0FU);
dst[1] = (uint8_t)((value >> 16) & 0x0FU);
dst[2] = (uint8_t)((value >> 12) & 0x0FU);
dst[3] = (uint8_t)((value >> 8) & 0x0FU);
dst[4] = (uint8_t)((value >> 4) & 0x0FU);
dst[5] = (uint8_t)(value & 0x0FU);
}
static void amp_send_fail(uint8_t sub, uint8_t reg)
{
uint8_t resp[8] = {0xF0, 0x60, 0x07, 0x00, 0x00, 0x00, 0x7F, 0xF7};
resp[3] = sub;
amp_put_reg_nibbles(&resp[4], reg);
USART4_SendData(resp, sizeof(resp));
}
static void amp_send_ok(uint8_t sub, uint8_t reg, uint32_t value)
{
uint8_t resp[13] = {0xF0, 0x60, 0x07, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0xF7};
resp[3] = sub;
amp_put_reg_nibbles(&resp[4], reg);
amp_put_u24_nibbles(&resp[6], value);
USART4_SendData(resp, sizeof(resp));
}
static void handleAmpRamRead(uint8_t *data)
{
uint8_t reg = 0;
uint32_t value = 0;
if (amp_parse_reg(data, &reg) == 0U)
{
amp_send_fail(0x00, (uint8_t)(((data[4] & 0x0FU) << 4) | (data[5] & 0x0FU)));
return;
}
if (AD85020B_RamRead24(reg, AMP_RAM_BANK_CH2, &value) != AD85020B_OK)
{
amp_send_fail(0x00, reg);
return;
}
LOG_I("AMP", "rd 0x%02X = 0x%06lX", (unsigned)reg, (unsigned long)value);
amp_send_ok(0x00, reg, value);
}
static void handleAmpRamWrite(uint8_t *data)
{
uint8_t reg = 0;
uint32_t value = 0;
if (amp_parse_reg(data, &reg) == 0U || amp_parse_u24(&data[6], &value) == 0U)
{
amp_send_fail(0x01, (uint8_t)(((data[4] & 0x0FU) << 4) | (data[5] & 0x0FU)));
return;
}
if (AD85020B_RamWrite24(reg, AMP_RAM_BANK_CH2, value) != AD85020B_OK)
{
amp_send_fail(0x01, reg);
return;
}
value = 0;
if (AD85020B_RamRead24(reg, AMP_RAM_BANK_CH2, &value) != AD85020B_OK)
{
amp_send_fail(0x01, reg);
return;
}
LOG_I("AMP", "wr 0x%02X = 0x%06lX", (unsigned)reg, (unsigned long)value);
amp_send_ok(0x01, reg, value);
}
/*-------- 5. reset / power off 0x05 --------*/
/* F0 60 05 00 F7 : ack then soft power off (executed in main-loop context) */
static void handleDeviceReset(uint8_t *data)
{
uint8_t resp[6] = {0xF0, 0x60, 0x05, 0x00, 0x01, 0xF7};
(void)data;
LOG_I("BLE", "05 00 ack then soft power off");
USART4_SendData(resp, sizeof(resp));
/* Soft-off cuts BT power immediately in PowerOff(); give UART4 + ATS2853
time to push the ACK Notify before requesting power-off. */
USART4_WaitTxIdle(50);
rt_thread_mdelay(120);
System_RequestPowerOff();
}

View File

@ -0,0 +1,16 @@
/* Auto-generated by tools/gen_git_user_fw_ver.py — do not edit.
* git HEAD (dirty): 80faaa4f9f5b55b49d395f5fac852364b8e13ad6
* branch: develop → develop
* 01 0C wire: develop_80faaa*
*/
#ifndef GIT_USER_FW_VER_H
#define GIT_USER_FW_VER_H
#define GIT_COMMIT_ID_FULL "80faaa4f9f5b55b49d395f5fac852364b8e13ad6"
#define GIT_BRANCH_NAME "develop"
#define GIT_COMMIT_SHORT6 "80faaa"
#define GIT_DIRTY (1)
#define GIT_BUILD_ID "develop_80faaa*"
#define GIT_BUILD_ID_LEN 15u
#endif /* GIT_USER_FW_VER_H */

8
run_k1_harness.bat Normal file
View File

@ -0,0 +1,8 @@
@echo off
REM Launch K1 HIL harness from repo root or any cwd.
REM Usage: run_k1_harness.bat selftest
REM run_k1_harness.bat run --suite all --profile nightly
setlocal
cd /d "%~dp0tools"
python -m k1_harness %*
exit /b %ERRORLEVEL%

18
run_k1_harness.py Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Repo-root launcher: python run_k1_harness.py ... (same as cd tools && python -m k1_harness ...)"""
from __future__ import annotations
import os
import sys
ROOT = os.path.dirname(os.path.abspath(__file__))
TOOLS = os.path.join(ROOT, "tools")
if TOOLS not in sys.path:
sys.path.insert(0, TOOLS)
os.chdir(TOOLS)
from k1_harness.cli import main # noqa: E402
if __name__ == "__main__":
main()

View File

@ -13,7 +13,7 @@ ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskUIThread_Stack[2048];
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskTouchThread_Stack[1536];
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskMainThread_Stack[512];
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskBTTHandlehread_Stack[512];
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskBTRecvThread_Stack[512];
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskBTRecvThread_Stack[768];
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t TaskAutobandThread_Stack[512];
@ -36,6 +36,55 @@ void TaskUIThread_entry(void* parameter)
{
if(rt_mq_recv(UITask_msg, &xEvent, sizeof(DisplayTaskMessage_Type), RT_WAITING_FOREVER) == RT_EOK)
{
/* BLE 写节奏风格:停伴奏+换库在任何页面都要执行,且必须在 UI 任务上下文
(TaskBTRecv 栈仅 768B,ReloadTone 深调用链会溢出;本地触控路径同在此任务) */
if (xEvent.MessageType == MSG_ID_BLE_STYLE_SET)
{
StartFlag = 0;
UI_ReloadTonePreset(); /* 内含 Stop_AutoBand */
}
/* 低电量提示:任意页面全屏覆盖;倒计时期间吞掉其它 UI 刷新,避免盖住提示 */
if (xEvent.MessageType == MSG_ID_LOW_BAT_TIP)
{
uint8_t peek[4];
LCD_WR_REG(0x29);
LCD_BLK_Set();
LCD_FillByColor(0, 0, 240, 320, BLACK);
W25Q128_Read(peek, UI0902_LOWBAT_TIP_ADDR, 4);
if (peek[0] != 0xFF || peek[1] != 0xFF)
{
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_LOWBAT_TIP_W, UI0902_LOWBAT_TIP_H,
UI0902_LOWBAT_TIP_ADDR);
}
else
{
LOG_W("UI", "lowbat flash empty @0x%08lX — flash ui0902",
(unsigned long)UI0902_LOWBAT_TIP_ADDR);
}
continue;
}
if (System_LowBat_IsActive())
continue;
if (UI_IsSettingsPage() &&
(xEvent.MessageType == MSG_ID_TAP_SPEED ||
xEvent.MessageType == MSG_ID_BP_TRANSPOSE))
{
UI_ApplyModeKeysOnSettings(xEvent);
continue;
}
/* 任意页面的用户交互统一复位自动关机;避免各 Process 漏调/early-return 漏调 */
switch (xEvent.MessageType)
{
case MSG_ID_TOUCH:
case MSG_ID_TOUCH_LONG_REPEAT:
case MSG_ID_EC_VOL:
case MSG_ID_TAP_SPEED:
case MSG_ID_BP_TRANSPOSE:
ResetAutoPowerCount();
break;
default:
break;
}
CurrUIProcress(xEvent);
}
}
@ -75,17 +124,44 @@ void TaskMainThread_entry(void* parameter)
switch(xEvent.MessageType)
{
case MSG_ID_POWER_ON : UITask_Sendmsg(MSG_ID_POWER_ON, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break;
case MSG_ID_HEAVY_BOOT : UITask_Sendmsg(MSG_ID_HEAVY_BOOT, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break;
case MSG_ID_POWER_OFF : break;
//case MSG_ID_ADCIN1KEY : ADC_IN1_KEY_Handle(xEvent.ID);break;
case MSG_ID_BP_KEY : Pick_Handle(); break;
case MSG_ID_LOOP_LIGHT : Loop_Light_Handle(xEvent.ID); break;
case MSG_ID_BP_KEY:
if (!System_LowBat_IsActive() && InModeFlag)
Pick_Handle();
break;
case MSG_ID_STOP_BAND:
/* 停止键/偶拍收束:MainTask 串行硬停(已撤销软停) */
if (!System_LowBat_IsActive())
Stop_AutoBand();
break;
case MSG_ID_START_FOLLOWUP:
/* 软停补发路径已撤销;保留 case 以免旧固件消息号撞车 */
break;
case MSG_ID_LOOP_LIGHT:
if (!System_LowBat_IsActive())
Loop_Light_Handle(xEvent.ID);
break;
case MSG_ID_TM1629_KEY : break;
case MSG_ID_TM1617_KEY : break;
case MSG_ID_EC_VOL:
/* 任意页面都先下发主音量,避免 UI 未处理导致屏显与实际脱节 */
Send_volume((uint8_t)xEvent.ID);
if (!System_LowBat_IsActive())
Send_volume((uint8_t)xEvent.ID);
UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte);
break;
case MSG_ID_LOW_BAT_TIP:
/* 立即停声并切掉音源/12V/蓝牙,避免提示的 10s 里继续把电池拉过保护电压 */
Stop_AutoBand();
Send_volume(0);
Audio_AbortIfNotReady();
BSP_DreamCorePowerEnable(0);
BSP_HT7178PowerEnable(0);
BSP_BlueToothPowerEnable(0);
System_LowBat_Arm();
UITask_Sendmsg(MSG_ID_LOW_BAT_TIP, xEvent.ID, xEvent.HiByte, xEvent.LoByte);
break;
case MSG_ID_TOUCH:
case MSG_ID_CHARG:
case MSG_ID_TAP_SPEED:
@ -93,6 +169,8 @@ void TaskMainThread_entry(void* parameter)
case MSG_ID_POWOFF_CHARG:
case MSG_ID_BATTERY_VALUE:
case MSG_ID_TOUCH_LONG_REPEAT:
case MSG_ID_BLE_UI_REFRESH:
case MSG_ID_BLE_STYLE_SET:
/* 业务消息:先做业务处理,再转发 UI 刷新 */
UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte);
break;
@ -115,6 +193,15 @@ void TaskBTHandleThread_entry(void* parameter)
case MSG_ID_LIGHT_LED : BL_Set_led(xEvent.ID,xEvent.HiByte); break;
case MSG_ID_PITCH_OFFSET : BT_Pitch_offset_map(xEvent.ID,xEvent.HiByte); break;
case MSG_ID_CHORD_OFFSET : BT_Chord_offset_map(xEvent.ID,xEvent.HiByte); break;
/* BLE section / intro-outro-end commands (06 xx, 04 07) */
case MSG_ID_ADCIN1KEY:
if (InModeFlag)
ADC_IN1_KEY_Handle((uint8_t)xEvent.ID, true);
break;
case MSG_ID_KEY_1617:
if (InModeFlag)
TM1617_Handle((uint8_t)xEvent.ID);
break;
}
}
}
@ -124,27 +211,47 @@ void TaskBTRecvThread_entry(void* parameter)
{
uint8_t c;
while(1)
{
if(rt_sem_take(UART4_sem,RT_WAITING_FOREVER) == RT_EOK)
{
if(rt_sem_take(UART4_sem, RT_WAITING_FOREVER) == RT_EOK)
{
while(UART4_RxPop(&c))
{
//解析函数
UART4_Data_Process(&c);
}
}
}
}
extern void App_Auto_LogHeldNotes(void);
void TaskAutobandThread_entry(void* parameter)
{
for(;;)
{
while(!mymidififo_IsQueueEmpty(&m_MidiSendFifo))
int guard = mymidififo_GetQueueLength(&m_MidiSendFifo);
uint16_t now = (uint16_t)wk_timebase_get();
while (guard-- > 0 && !mymidififo_IsQueueEmpty(&m_MidiSendFifo))
{
MidiFifoItem_t* pitem = mymidififo_DeQueue(&m_MidiSendFifo);
SendMidiDataToDreamDSP(pitem->msg, pitem->msglen);
//ResetAutoPowerCount();
MidiFifoItem_t* peek = mymidififo_TryDeQueue(&m_MidiSendFifo);
MidiFifoItem_t item;
uint16_t due;
uint16_t ahead;
if (peek == 0)
break;
item = *peek;
due = item.delayCounter;
ahead = (uint16_t)(due - now);
/* delayCounter==0 立即发送;未到点的音挪到队尾,避免挡住鼓和低音 */
if (due != 0u && ahead != 0u && ahead < 0x8000u)
{
mymidififo_DeQueue(&m_MidiSendFifo);
mymidififo_InQueue(&m_MidiSendFifo, &item);
continue;
}
mymidififo_DeQueue(&m_MidiSendFifo);
SendMidiDataToDreamDSP(item.msg, item.msglen);
if (due != 0u)
App_Auto_LogHeldNotes();
}
rt_thread_mdelay(1);
}
@ -238,6 +345,35 @@ void StartTask(void)
/* 扫描任务可能已由 StartScanTask 拉起;重复 startup 会被 RT-Thread 忽略 */
StartScanTask();
/* Soft-off(StopFullTask) 会 detach 下列线程;开机须能重建,否则 UI/消息永久失效 */
if ((TaskMainThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
{
rt_thread_init(&TaskMainThread,
"TaskMainThread",
TaskMainThread_entry,
RT_NULL,
&TaskMainThread_Stack,
sizeof(TaskMainThread_Stack),
5,
20);
}
if ((TaskMainThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT)
rt_thread_startup(&TaskMainThread);
if ((TaskUIThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
{
rt_thread_init(&TaskUIThread,
"TaskUIThread",
TaskUIThread_entry,
RT_NULL,
&TaskUIThread_Stack,
sizeof(TaskUIThread_Stack),
5,
20);
}
if ((TaskUIThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT)
rt_thread_startup(&TaskUIThread);
if ((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
{
rt_thread_init(&TaskBTHandleThread,
@ -334,18 +470,12 @@ void StopFullTask(void)
LOG_I("TASK", "stop ScanThread");
rt_thread_detach(&TaskScanThread);
}
if((TaskUIThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
LOG_I("TASK", "stop UIThread");
rt_thread_detach(&TaskUIThread);
}
/* 软关机 = 系统关闭:停触摸/扫描/BT/伴奏。
Main/UI 保留:Type-C 时要画 Charging Image,长按开机要收 POWER_ON。 */
if((TaskTouchThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
LOG_I("TASK", "stop TouchThread");
rt_thread_detach(&TaskTouchThread);
}
if((TaskMainThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
LOG_I("TASK", "stop MainThread");
rt_thread_detach(&TaskMainThread);
}
if((TaskBTHandleThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
LOG_I("TASK", "stop BTHandleThread");
rt_thread_detach(&TaskBTHandleThread);
@ -354,8 +484,12 @@ void StopFullTask(void)
LOG_I("TASK", "stop BTRecvThread");
rt_thread_detach(&TaskBTRecvThread);
}
if((TaskAutobandThread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE) {
LOG_I("TASK", "stop AutobandThread");
rt_thread_detach(&TaskAutobandThread);
}
LOG_I("TASK", "StopFullTask done");
}
}
static void OutTime_Stop_timer_callback(void *parameter)

View File

@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
"""Systematic BLE channel matrix for Smart Guitar MIDI App SysEx."""
from __future__ import annotations
import asyncio
import time
from bleak import BleakClient, BleakScanner
NAME = "Smart Guitar MIDI"
MIDI = "7772e5db-3868-4112-a1a9-f2669d106bf3"
UARTW = "e49a25e0-f69a-11e8-8eb2-f2801f1b9fd1"
UARTN = "e49a28e1-f69a-11e8-8eb2-f2801f1b9fd1"
EFF2 = "0000eff2-0000-1000-8000-00805f9b34fb"
SYSEX = bytes.fromhex("F0600101F7")
FRAMED = bytes.fromhex("8080F0600101F7")
FRAMED_TSF7 = bytes.fromhex("8080F060010180F7")
def hx(b: bytes) -> str:
return " ".join(f"{x:02X}" for x in b) if b else "(none)"
async def find(timeout=60.0):
t0 = time.time()
while time.time() - t0 < timeout:
d = await BleakScanner.find_device_by_filter(
lambda d, a: d.name and NAME.lower() in d.name.lower(), timeout=8
)
if d:
return d
print("waiting advertise...")
return None
async def unpair_if_needed(addr: str):
try:
c = BleakClient(addr, timeout=15)
await c.connect()
try:
await c.unpair()
print("unpaired")
except Exception as e:
print("unpair skip:", e)
try:
await c.disconnect()
except Exception:
pass
await asyncio.sleep(1.5)
except Exception as e:
print("unpair session:", e)
async def one_session(tag: str, write_uuid: str, payload: bytes, notify_uuids, settle=2.5):
d = await find(45)
if not d:
print(f"[{tag}] NO DEVICE")
return {"tag": tag, "ok": False, "err": "no device", "notifs": []}
print(f"\n=== {tag} === write {write_uuid[:8]} {hx(payload)}")
notifs = []
err = None
connected_end = False
try:
async with BleakClient(d, timeout=25) as c:
print("connected", c.is_connected)
def cb(sender, data):
b = bytes(data)
notifs.append(b)
print(f" NOTIFY {hx(b)}")
for u in notify_uuids:
try:
await c.start_notify(u, cb)
print(" notify on", u[:8])
except Exception as e:
print(" notify fail", u[:8], e)
await asyncio.sleep(0.3)
try:
await c.write_gatt_char(write_uuid, payload, response=False)
print(" write ok")
except Exception as e:
err = f"write: {e}"
print(" write fail", e)
await asyncio.sleep(settle)
connected_end = c.is_connected
print(" end conn=", connected_end, "notifs=", len(notifs))
except Exception as e:
err = str(e)
print(" session err", e)
return {
"tag": tag,
"ok": any(b[:3] == b"\xF0\x60\x01" or b[:4] == b"\x80\x80\xF0\x60" for b in notifs),
"notifs": [hx(b) for b in notifs],
"conn_end": connected_end,
"err": err,
}
async def main():
d = await find(60)
if not d:
print("FATAL: device not advertising")
return
print("found", d.name, d.address)
await unpair_if_needed(d.address)
await asyncio.sleep(2)
results = []
# matrix: do NOT put uartw first if it kills radio; do midi first
cases = [
("midi-framed", MIDI, FRAMED, [MIDI, UARTN, EFF2]),
("midi-framed-tsF7", MIDI, FRAMED_TSF7, [MIDI]),
("midi-raw", MIDI, SYSEX, [MIDI]),
("eff2-raw", EFF2, SYSEX, [EFF2, MIDI, UARTN]),
("eff2-framed", EFF2, FRAMED, [EFF2, MIDI]),
("uartw-raw", UARTW, SYSEX, [UARTN, MIDI, EFF2]),
("uartw-framed", UARTW, FRAMED, [UARTN, MIDI]),
]
for tag, wu, payload, nus in cases:
r = await one_session(tag, wu, payload, nus)
results.append(r)
# if uart killed advertising, wait/reset hint
if not r.get("conn_end", True):
print("link dropped; waiting re-advertise...")
await asyncio.sleep(3)
if not await find(30):
print("device gone after drop — stop matrix (need JLink reset)")
break
else:
await asyncio.sleep(1)
print("\n===== MATRIX SUMMARY =====")
for r in results:
status = "PASS" if r["ok"] else "FAIL"
print(f"{status:4} {r['tag']:18} conn_end={r.get('conn_end')} notifs={r['notifs'] or ['(none)']} err={r.get('err')}")
if __name__ == "__main__":
asyncio.run(main())

126
tools/_probe_ble_rtt.py Normal file
View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
"""Probe: RTT log + BLE uartw write to see if MCU gets F0 60."""
import asyncio
import threading
import time
import pylink
from bleak import BleakScanner, BleakClient
UARTW = "e49a25e0-f69a-11e8-8eb2-f2801f1b9fd1"
UARTN = "e49a28e1-f69a-11e8-8eb2-f2801f1b9fd1"
MIDI = "7772e5db-3868-4112-a1a9-f2669d106bf3"
def open_jlink():
j = pylink.JLink()
j.open()
try:
j.exec_command("HideDeviceSelection = 1")
except Exception:
pass
j.set_tif(pylink.enums.JLinkInterfaces.SWD)
last = None
for dev in ("Cortex-M4", "AT32F403AC", "AT32F403A"):
try:
try:
j.exec_command(f"Device = {dev}")
except Exception:
pass
j.connect(dev)
print("JLink connected", dev, flush=True)
try:
j.restart(halt=False)
except Exception:
try:
j.go()
except Exception:
pass
return j
except Exception as e:
last = e
raise SystemExit(f"JLink connect failed: {last}")
async def find_dev(timeout=60):
t0 = time.time()
while time.time() - t0 < timeout:
d = await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "Smart Guitar" in d.name, timeout=8
)
if d:
return d
print("waiting BLE...", flush=True)
return None
async def main():
j = open_jlink()
j.rtt_start()
stop = False
lines = []
def reader():
while not stop:
try:
data = j.rtt_read(0, 4096)
if data:
s = bytes(data).decode("utf-8", "replace")
lines.append(s)
print("RTT>", s, end="" if s.endswith("\n") else "\n", flush=True)
except Exception as e:
print("rtt err", e, flush=True)
break
time.sleep(0.03)
th = threading.Thread(target=reader, daemon=True)
th.start()
print("collect boot logs 3s...", flush=True)
await asyncio.sleep(3)
d = await find_dev(90)
if not d:
print("NO BLE DEVICE", flush=True)
stop = True
j.close()
return
print("BLE", d.name, d.address, flush=True)
try:
async with BleakClient(d, timeout=30) as c:
print("connected", flush=True)
notifs = []
def cb(_s, data):
notifs.append(bytes(data))
print("NOTIFY", data.hex(), flush=True)
for u in (UARTN, MIDI):
try:
await c.start_notify(u, cb)
print("notify ok", u[:8], flush=True)
except Exception as e:
print("notify fail", u[:8], e, flush=True)
await asyncio.sleep(0.5)
print("WRITE uartw F0 60 01 01 F7", flush=True)
try:
await c.write_gatt_char(UARTW, bytes.fromhex("F0600101F7"), response=False)
print("write returned", flush=True)
except Exception as e:
print("write err", e, flush=True)
await asyncio.sleep(4)
print("notifs", len(notifs), "conn", c.is_connected, flush=True)
except Exception as e:
print("BLE session err", e, flush=True)
await asyncio.sleep(1)
stop = True
time.sleep(0.3)
j.close()
print("RTT total chunks", len(lines), flush=True)
ble_hits = [x for x in lines if "BLE" in x or "sysex" in x]
print("BLE-related RTT lines:", ble_hits, flush=True)
if __name__ == "__main__":
asyncio.run(main())

193
tools/_rtt_ble_diagnose.py Normal file
View File

@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
"""Flash is separate; this attaches RTT then writes BLE SysEx and prints MCU logs."""
from __future__ import annotations
import asyncio
import sys
import threading
import time
import pylink
from bleak import BleakClient, BleakScanner
NAME = "Smart Guitar MIDI"
MIDI = "7772e5db-3868-4112-a1a9-f2669d106bf3"
UARTW = "e49a25e0-f69a-11e8-8eb2-f2801f1b9fd1"
UARTN = "e49a28e1-f69a-11e8-8eb2-f2801f1b9fd1"
EFF2 = "0000eff2-0000-1000-8000-00805f9b34fb"
def open_jlink():
j = pylink.JLink()
j.open()
try:
j.exec_command("HideDeviceSelection = 1")
except Exception:
pass
j.set_tif(pylink.enums.JLinkInterfaces.SWD)
last = None
for dev in ("Cortex-M4", "AT32F403AC", "AT32F403A"):
try:
try:
j.exec_command(f"Device = {dev}")
except Exception:
pass
j.connect(dev)
print("JLink OK", dev, flush=True)
try:
j.restart(halt=False)
except Exception:
try:
j.go()
except Exception:
pass
return j
except Exception as e:
last = e
raise SystemExit(f"JLink fail: {last}")
async def find_dev(timeout=45.0):
t0 = time.time()
while time.time() - t0 < timeout:
d = await BleakScanner.find_device_by_filter(
lambda d, a: d.name and NAME.lower() in d.name.lower(), timeout=8
)
if d:
return d
print("wait BLE...", flush=True)
return None
async def ble_write(tag, write_uuid, payload, notify_uuids):
d = await find_dev()
if not d:
print("NO BLE", flush=True)
return
print(f"BLE {d.address} write {tag} {payload.hex()}", flush=True)
try:
c = BleakClient(d.address, timeout=20)
await c.connect()
try:
await c.unpair()
except Exception:
pass
await c.disconnect()
except Exception:
pass
await asyncio.sleep(1.0)
d = await find_dev() or d
notifs = []
async with BleakClient(d, timeout=25) as c:
def cb(_s, data):
notifs.append(bytes(data))
print("GATT NOTIFY", data.hex(), flush=True)
for u in notify_uuids:
try:
await c.start_notify(u, cb)
except Exception as e:
print("notify fail", u[:8], e, flush=True)
await asyncio.sleep(0.2)
try:
await c.write_gatt_char(write_uuid, payload, response=False)
print("GATT write ok, conn", c.is_connected, flush=True)
except Exception as e:
print("GATT write fail", e, flush=True)
await asyncio.sleep(3.0)
print("GATT notifs", len(notifs), "conn", c.is_connected, flush=True)
async def main():
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
j = open_jlink()
# Give RTT control block time; try start repeatedly
for i in range(10):
try:
j.rtt_start(block_address=0x20016D68)
st = j.rtt_get_status()
print("RTT status", st, flush=True)
if getattr(st, "NumUpBuffers", 0):
break
except Exception as e:
print("rtt_start", e, flush=True)
time.sleep(0.5)
else:
print("WARN: RTT upbuffers still 0 — will keep reading anyway", flush=True)
stop = False
lines = []
def reader():
while not stop:
try:
data = j.rtt_read(0, 4096)
if data:
s = bytes(data).decode("utf-8", "replace")
lines.append(s)
print("RTT>", s, end="" if s.endswith("\n") else "\n", flush=True)
except Exception as e:
print("rtt read err", e, flush=True)
break
time.sleep(0.03)
th = threading.Thread(target=reader, daemon=True)
th.start()
print("collect 4s boot/idle logs...", flush=True)
await asyncio.sleep(4.0)
if not lines:
print("WARNING: no RTT yet — touch screen or wait; continuing BLE test", flush=True)
# 1) BLE-MIDI framed (stable path)
await ble_write(
"midi-framed",
MIDI,
bytes.fromhex("8080F0600101F7"),
[MIDI, UARTN, EFF2],
)
await asyncio.sleep(2.0)
# E49A raw write often drops link / stops advertising — skip by default
if "--with-uartw" in sys.argv:
await ble_write(
"uartw-raw",
UARTW,
bytes.fromhex("F0600101F7"),
[UARTN, MIDI, EFF2],
)
await asyncio.sleep(2.0)
stop = True
time.sleep(0.4)
j.close()
text = "".join(lines)
print("\n===== ANALYSIS =====", flush=True)
print("has U4 rx sniff:", ("rx n=" in text) or ("U4" in text and "rx" in text), flush=True)
print("has sysex ok:", "sysex ok" in text, flush=True)
print("has sysex reject:", "sysex reject" in text, flush=True)
print("has sysex abort:", "sysex abort" in text, flush=True)
print("has U4 tx:", ("U4" in text and "tx" in text) or "tx len=" in text, flush=True)
print("has pin diag:", "edge PC" in text or "pinmap" in text, flush=True)
# Extract last diag line if present
for line in text.splitlines():
if "edge PC10=" in line:
print("diag:", line.strip(), flush=True)
if "sysex ok" in text and "tx len=" in text:
print("VERDICT: MCU got cmd and replied on UART4 → GATT notify path broken in BLE module", flush=True)
elif "rx n=" in text and "sysex ok" not in text:
print("VERDICT: UART4 got bytes but frame not accepted → protocol/framing", flush=True)
elif "edge PC12=" in text and "isr_rx=0" in text:
# SCH puts B_UART4_RX on PC12; FW UART4 RX is PC11
print("VERDICT: activity on PC12 while UART4 ISR idle → driver pinmap vs SCH (MCU底层)", flush=True)
elif "edge PC11=" in text and "isr_rx=0" in text:
print("VERDICT: edges on PC11 but no UART ISR → baud/noise or not UART framing", flush=True)
elif "isr_rx=0" in text and "edge PC10=0" in text and "edge PC11=0" in text and "edge PC12=0" in text:
print("VERDICT: no GPIO edges + no UART ISR → ATS2853 did not drive UART (模组固件/桥接)", flush=True)
elif "U4" not in text and "rx" not in text:
print("VERDICT: no UART4 activity → BLE module did not forward GATT write to UART4 (or RTT dead)", flush=True)
else:
print("VERDICT: inconclusive — see RTT dump above", flush=True)
if __name__ == "__main__":
asyncio.run(main())

View File

@ -0,0 +1,66 @@
"""One-off: expert rhythm (1.bin) piece mode ends after the piece window;
press fretboard only (no pick) after it stops -> must restart (trigger=fret + PITCH)."""
import os
import sys
import time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import rtt_pitch_reg_test as R
def main() -> int:
R.import_deps()
jlink = R.connect_jlink("AT32F403AC") # same default as rtt_pitch_reg_test
try:
cb = R.find_rtt_control_block(jlink)
if cb is None:
print("FAIL: RTT CB not found")
return 1
print(f"RTT CB @ 0x{cb:08X}", flush=True)
jlink.rtt_start(cb)
R.wait_rtt_ready(jlink)
sess = R.RttSession(jlink)
sess.pump(0.3)
sess.cmd("log clear", 0.3)
sess.cmd("tone bin1 0", 1.2) # expert + rhythm 1.bin (piece 0..1920ms)
sess.cmd("tone start", 0.8) # pick start, piece plays then stops
print(">> playing window (piece ~2s) ...", flush=True)
sess.pump(4.0) # wait until piece ended, PlayTick frozen
base = len(sess.lines)
sess.cmd("chord key 0", 0.4)
sess.cmd("chord key 8", 0.2) # fretboard only, no pick
sess.pump(3.0) # capture restart
new = sess.lines[base:]
joined = "\n".join(new)
trig = [l for l in new if "trigger=fret" in l]
change = [l for l in new if "expert/fret change" in l]
pitch = [l for l in new if "[PITCH] on" in l]
print("---- full session ----", flush=True)
for l in sess.lines:
print(l, flush=True)
print("---- captured after fret-only press ----", flush=True)
for l in new:
print(l, flush=True)
print("---- verdict ----", flush=True)
handled = trig or change
if handled and pitch:
path = "restart" if trig else "note_on-change"
print(f"PASS fret-only continue: path={path}, PITCH on x{len(pitch)}")
return 0
print("FAIL: no handler log or no pitch")
return 1
finally:
try:
sess.cmd("chord key 23", 0.3) # stop band, leave device quiet
sess.pump(0.3)
except Exception:
pass
jlink.close()
if __name__ == "__main__":
raise SystemExit(main())

181
tools/_test_normal_pick.py Normal file
View File

@ -0,0 +1,181 @@
#!/usr/bin/env python3
"""RTT verify normal-mode: hold pad + pick sounds; release stops.
Uses real physical pad hold (inject is cleared by TM1629 scan within one tick).
"""
from __future__ import annotations
import struct
import sys
import time
sys.path.insert(0, ".")
from rtt_pitch_reg_test import ( # noqa: E402
RttSession,
connect_jlink,
find_rtt_control_block,
wait_rtt_ready,
)
SPEED_TAIL = struct.pack("<HHH", 40, 260, 1)
GUI_SWITCH_SIZE = 8
TAB_INDEX = 5
def count_pitch(lines: list[str]) -> int:
return sum(1 for L in lines if "[PITCH]" in L and " on " in L)
def parse_tab(lines: list[str]) -> int | None:
for L in reversed(lines):
if "TONE tab=" not in L:
continue
try:
return int(L.split("tab=")[1].split()[0])
except Exception:
continue
return None
def with_halt(jlink, fn):
was = jlink.halted()
if not was:
jlink.halt()
try:
return fn()
finally:
if not was:
if hasattr(jlink, "restart"):
jlink.restart()
else:
jlink.go()
time.sleep(0.02)
def find_pattern(jlink, needle: bytes, ram_base=0x20000000, ram_size=0x18000) -> int | None:
def _find():
chunk = 0x1000
for off in range(0, ram_size, chunk):
data = bytes(jlink.memory_read8(ram_base + off, min(chunk, ram_size - off)))
idx = data.find(needle)
if idx >= 0:
return ram_base + off + idx
return None
return with_halt(jlink, _find)
def mem_write(jlink, addr: int, data: bytes) -> None:
with_halt(jlink, lambda: jlink.memory_write8(addr, list(data)))
def mem_read(jlink, addr: int, n: int) -> bytes:
return with_halt(jlink, lambda: bytes(jlink.memory_read8(addr, n)))
def force_tab_normal(jlink) -> bool:
hit = find_pattern(jlink, SPEED_TAIL)
if hit is None:
print("!! GUI_SPEED row not found", flush=True)
return False
base = (hit - 2) - GUI_SWITCH_SIZE
tab_addr = base + TAB_INDEX * GUI_SWITCH_SIZE
mem_write(jlink, tab_addr, struct.pack("<H", 2))
got = struct.unpack("<H", mem_read(jlink, tab_addr, 2))[0]
print(f"mGuiData @ 0x{base:08X} forced TAB={got}", flush=True)
return got == 2
def wait_enter(msg: str, seconds: float) -> None:
print(f"\n>>> {msg}", flush=True)
print(f" ({seconds:.0f}s countdown)", flush=True)
for left in range(int(seconds), 0, -1):
print(f" {left}...", flush=True)
time.sleep(1.0)
def main() -> int:
j = connect_jlink("Cortex-M4")
cb = find_rtt_control_block(j)
if not cb:
raise SystemExit("RTT CB not found")
print(f"RTT CB @ 0x{cb:08X}", flush=True)
j.rtt_start(cb)
wait_rtt_ready(j)
sess = RttSession(j)
print("\n=== Setup: 1.bin + TAB=普通(2) ===", flush=True)
sess.cmd("log clear", 0.2)
sess.cmd_ack("tone bin1 0", "TONE_BIN1", timeout_s=4.0, retries=4)
if not force_tab_normal(j):
j.rtt_stop()
j.close()
return 3
sess.cmd_ack("tone status", "TONE tab=", timeout_s=3.0, retries=4)
print(f"tab={parse_tab(sess.lines)}", flush=True)
# Stop any leftover
sess.cmd_ack("chord key 23", "CHORD_KEY_OK", timeout_s=2.0, retries=3)
force_tab_normal(j)
print("\n=== TEST1: pick with NO pad hold (expect silence) ===", flush=True)
print("请双手离开指板。", flush=True)
wait_enter("双手离开指板后等待自动拨片测试", 3)
force_tab_normal(j)
sess.cmd("log clear", 0.2)
sess.cmd_ack("tone start", "TONE_START_DONE", timeout_s=3.0, retries=5)
n1 = count_pitch(sess.pump(1.5))
print(f"TEST1 PITCH on={n1} (expect 0)", flush=True)
print("\n=== TEST2: hold pad + pick (expect sound) ===", flush=True)
wait_enter("请按住指板任意和弦键不放(建议按住第2排中部)", 5)
force_tab_normal(j)
sess.cmd("log clear", 0.2)
# keep KEY from physical hold; tone start without clearing if we use 'k'
# But we don't know KEY — physical hold already set KEY_ID+PressFlag via scan.
# tone start WITHOUT k clears KEY_ID! Must use tone start k — but then KEY kept.
# If user is holding, KEY_ID is set; PressFlag is set. tone start sets StartFlag=0
# then clears KEY unless k. Use: don't clear — need tone start k AND physical KEY already set.
sess.cmd_ack("tone start k", "TONE_START_DONE", timeout_s=3.0, retries=5)
play = sess.pump(2.5)
n2 = count_pitch(play)
print(f"TEST2 PITCH on={n2} (expect >0) — keep holding!", flush=True)
for L in play:
if "[PITCH]" in L:
print(" ", L, flush=True)
break
print("\n=== TEST3: release pad (expect stop) ===", flush=True)
wait_enter("请松开指板(松手)", 3)
force_tab_normal(j)
sess.cmd("log clear", 0.15)
post = sess.pump(2.0)
n3 = count_pitch(post)
print(f"TEST3 PITCH on after release={n3} (expect 0)", flush=True)
print("\n=== TEST4: hold again + pick (expect sound) ===", flush=True)
wait_enter("请再次按住指板和弦键不放", 5)
force_tab_normal(j)
sess.cmd("log clear", 0.2)
sess.cmd_ack("tone start k", "TONE_START_DONE", timeout_s=3.0, retries=5)
n4 = count_pitch(sess.pump(2.0))
print(f"TEST4 PITCH on={n4} (expect >0)", flush=True)
print("可松开指板。", flush=True)
time.sleep(1.0)
sess.cmd_ack("chord key 23", "CHORD_KEY_OK", timeout_s=2.0, retries=3)
t1, t2, t3, t4 = (n1 == 0), (n2 >= 1), (n3 == 0), (n4 >= 1)
print("\n======== RESULT ========", flush=True)
print(f"TEST1 no-hold silence: {'PASS' if t1 else 'FAIL'} (n={n1})", flush=True)
print(f"TEST2 hold+pick sound: {'PASS' if t2 else 'FAIL'} (n={n2})", flush=True)
print(f"TEST3 release stop: {'PASS' if t3 else 'FAIL'} (n={n3})", flush=True)
print(f"TEST4 re-trigger: {'PASS' if t4 else 'FAIL'} (n={n4})", flush=True)
ok_all = t1 and t2 and t3 and t4
print("OVERALL:", "PASS" if ok_all else "FAIL", flush=True)
j.rtt_stop()
j.close()
return 0 if ok_all else 1
if __name__ == "__main__":
raise SystemExit(main())

View File

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
"""Quick USB MIDI (SAM5704) SysEx probe for App F0 60 frames."""
from __future__ import annotations
import ctypes
import ctypes.wintypes as w
import sys
import time
winmm = ctypes.WinDLL("winmm")
CALLBACK_FUNCTION = 0x30000
MIM_DATA, MIM_LONGDATA = 0x3C3, 0x3C4
MHDR_DONE = 0x01
class MIDIINCAPS(ctypes.Structure):
_fields_ = [
("wMid", w.WORD), ("wPid", w.WORD), ("vDriverVersion", w.DWORD),
("szPname", ctypes.c_char * 32), ("dwSupport", w.DWORD),
]
class MIDIOUTCAPS(ctypes.Structure):
_fields_ = [
("wMid", w.WORD), ("wPid", w.WORD), ("vDriverVersion", w.DWORD),
("szPname", ctypes.c_char * 32), ("wTechnology", w.WORD),
("wVoices", w.WORD), ("wNotes", w.WORD), ("wChannelMask", w.WORD),
("dwSupport", w.DWORD),
]
class MIDIHDR(ctypes.Structure):
_fields_ = [
("lpData", ctypes.c_void_p),
("dwBufferLength", w.DWORD),
("dwBytesRecorded", w.DWORD),
("dwUser", ctypes.c_void_p),
("dwFlags", w.DWORD),
("lpNext", ctypes.c_void_p),
("reserved", ctypes.c_void_p),
("dwOffset", w.DWORD),
("dwReserved", ctypes.c_size_t * 8),
]
def find_sam(kind: str):
n = winmm.midiInGetNumDevs() if kind == "in" else winmm.midiOutGetNumDevs()
for i in range(n):
if kind == "in":
c = MIDIINCAPS()
winmm.midiInGetDevCapsA(i, ctypes.byref(c), ctypes.sizeof(c))
else:
c = MIDIOUTCAPS()
winmm.midiOutGetDevCapsA(i, ctypes.byref(c), ctypes.sizeof(c))
name = c.szPname.decode("mbcs", "replace")
if "SAM5704" in name:
return i, name
return None, None
def hx(b: bytes) -> str:
return " ".join(f"{x:02X}" for x in b)
def main() -> int:
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
in_i, in_n = find_sam("in")
out_i, out_n = find_sam("out")
print(f"IN={in_i} {in_n} OUT={out_i} {out_n}", flush=True)
if in_i is None or out_i is None:
print("SAM5704 not found")
return 1
received: list[bytes] = []
keep = [] # keep buffer refs alive
MidiInProc = ctypes.WINFUNCTYPE(
None, w.HANDLE, w.UINT, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_size_t
)
@MidiInProc
def on_midi_in(h, msg, _inst, p1, p2):
if msg == MIM_LONGDATA:
hdr = ctypes.cast(p1, ctypes.POINTER(MIDIHDR)).contents
n = hdr.dwBytesRecorded
if n and hdr.lpData:
data = ctypes.string_at(hdr.lpData, n)
received.append(data)
print("RX", hx(data), flush=True)
winmm.midiInAddBuffer(h, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
elif msg == MIM_DATA:
print(
f"RX SHORT {(p1 & 0xFF):02X} {((p1 >> 8) & 0xFF):02X} {((p1 >> 16) & 0xFF):02X}",
flush=True,
)
h_in = w.HANDLE()
r = winmm.midiInOpen(ctypes.byref(h_in), in_i, on_midi_in, 0, CALLBACK_FUNCTION)
print("midiInOpen", r, flush=True)
if r != 0:
return r
for _ in range(4):
buf = ctypes.create_string_buffer(1024)
hdr = MIDIHDR()
hdr.lpData = ctypes.cast(buf, ctypes.c_void_p)
hdr.dwBufferLength = 1024
keep.append((buf, hdr))
winmm.midiInPrepareHeader(h_in, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
winmm.midiInAddBuffer(h_in, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
winmm.midiInStart(h_in)
h_out = w.HANDLE()
r = winmm.midiOutOpen(ctypes.byref(h_out), out_i, 0, 0, 0)
print("midiOutOpen", r, flush=True)
if r != 0:
return r
def send_sysex(msg: bytes):
buf = ctypes.create_string_buffer(msg)
hdr = MIDIHDR()
hdr.lpData = ctypes.cast(buf, ctypes.c_void_p)
hdr.dwBufferLength = len(msg)
keep.append((buf, hdr))
winmm.midiOutPrepareHeader(h_out, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
print("TX", hx(msg), flush=True)
winmm.midiOutLongMsg(h_out, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
t0 = time.time()
while not (hdr.dwFlags & MHDR_DONE) and time.time() - t0 < 2:
time.sleep(0.01)
winmm.midiOutUnprepareHeader(h_out, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
for label, msg in [
("01 01", bytes.fromhex("F0600101F7")),
("01 02", bytes.fromhex("F0600102F7")),
("01 03", bytes.fromhex("F0600103F7")),
]:
print("---", label, flush=True)
n0 = len(received)
send_sysex(msg)
time.sleep(1.2)
print(" new rx", len(received) - n0, flush=True)
print("TOTAL RX", len(received), flush=True)
app_like = [x for x in received if len(x) >= 2 and x[0] == 0xF0 and x[1] == 0x60]
print("F0 60 replies", len(app_like), flush=True)
winmm.midiInStop(h_in)
winmm.midiInReset(h_in)
for buf, hdr in keep[:4]:
winmm.midiInUnprepareHeader(h_in, ctypes.byref(hdr), ctypes.sizeof(MIDIHDR))
winmm.midiInClose(h_in)
winmm.midiOutClose(h_out)
return 0
if __name__ == "__main__":
raise SystemExit(main())

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 416 B

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

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