From 8101d2c3a063a74cddc0407e9740c63ef2d765dd Mon Sep 17 00:00:00 2001 From: Robofish <1683502971@qq.com> Date: Fri, 19 Dec 2025 22:43:01 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=B8=8D=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 8196 -> 8196 bytes BUILD_GUIDE.md | 131 +++ MRobot.iss | 7 +- app/__pycache__/__init__.cpython-39.pyc | Bin 137 -> 137 bytes .../about_interface.cpython-39.pyc | Bin 11162 -> 13368 bytes app/__pycache__/ai_interface.cpython-39.pyc | Bin 5288 -> 5288 bytes .../batch_export_dialog.cpython-39.pyc | Bin 0 -> 5878 bytes .../category_management_dialog.cpython-39.pyc | Bin 0 -> 8529 bytes ...ode_configuration_interface.cpython-39.pyc | Bin 6263 -> 6263 bytes .../code_generate_interface.cpython-39.pyc | Bin 11359 -> 11421 bytes app/__pycache__/data_interface.cpython-39.pyc | Bin 21715 -> 22236 bytes .../finance_interface.cpython-39.pyc | Bin 0 -> 34247 bytes .../function_fit_interface.cpython-39.pyc | Bin 7765 -> 7765 bytes app/__pycache__/home_interface.cpython-39.pyc | Bin 2070 -> 2070 bytes app/__pycache__/main_window.cpython-39.pyc | Bin 3759 -> 4599 bytes .../mini_tool_interface.cpython-39.pyc | Bin 3763 -> 3763 bytes .../part_library_interface.cpython-39.pyc | Bin 6960 -> 6960 bytes .../serial_terminal_interface.cpython-39.pyc | Bin 5838 -> 5838 bytes .../__pycache__/bsp_interface.cpython-39.pyc | Bin 37841 -> 36084 bytes app/data_interface.py | 14 + .../__pycache__/analyzing_ioc.cpython-39.pyc | Bin 6849 -> 6849 bytes .../__pycache__/auto_updater.cpython-39.pyc | Bin 12432 -> 12388 bytes .../__pycache__/check_update.cpython-39.pyc | Bin 2419 -> 2419 bytes .../__pycache__/code_generator.cpython-39.pyc | Bin 4007 -> 16633 bytes .../code_task_config.cpython-39.pyc | Bin 8495 -> 8495 bytes .../finance_manager.cpython-39.pyc | Bin 0 -> 20849 bytes .../__pycache__/part_download.cpython-39.pyc | Bin 1710 -> 1710 bytes .../update_check_thread.cpython-39.pyc | Bin 1244 -> 1244 bytes .../__pycache__/update_code.cpython-39.pyc | Bin 2384 -> 3213 bytes app/tools/code_generator.py | 39 +- app/tools/update_code.py | 64 +- .../metadata.json | 8 + assets/User_code/config.csv | 2 +- assets/User_code/device/config.yaml | 21 +- assets/User_code/device/lcd_driver/lcd.c | 743 ++++++++++++++++++ assets/User_code/device/lcd_driver/lcd.h | 156 ++++ assets/User_code/device/lcd_driver/lcd_lib.h | 621 +++++++++++++++ assets/User_code/device/oid.c | 467 +++++++++++ assets/User_code/device/oid.h | 269 +++++++ assets/User_code/module/cmd/cmd.c | 265 +++++++ assets/User_code/module/cmd/cmd.h | 172 ++++ assets/User_code/module/cmd/cmd_adapter.c | 184 +++++ assets/User_code/module/cmd/cmd_adapter.h | 111 +++ assets/User_code/module/cmd/cmd_behavior.c | 172 ++++ assets/User_code/module/cmd/cmd_behavior.h | 69 ++ assets/User_code/module/cmd/cmd_example.c | 144 ++++ assets/User_code/module/cmd/cmd_types.h | 196 +++++ build.bat | 51 ++ build.sh | 52 ++ 49 files changed, 3926 insertions(+), 32 deletions(-) create mode 100644 BUILD_GUIDE.md create mode 100644 app/__pycache__/batch_export_dialog.cpython-39.pyc create mode 100644 app/__pycache__/category_management_dialog.cpython-39.pyc create mode 100644 app/__pycache__/finance_interface.cpython-39.pyc create mode 100644 app/tools/__pycache__/finance_manager.cpython-39.pyc create mode 100644 assets/Finance_Data/accounts/06266d34-8789-45e9-aff0-e42549c238ba/metadata.json create mode 100644 assets/User_code/device/lcd_driver/lcd.c create mode 100644 assets/User_code/device/lcd_driver/lcd.h create mode 100644 assets/User_code/device/lcd_driver/lcd_lib.h create mode 100644 assets/User_code/device/oid.c create mode 100644 assets/User_code/device/oid.h create mode 100644 assets/User_code/module/cmd/cmd.c create mode 100644 assets/User_code/module/cmd/cmd.h create mode 100644 assets/User_code/module/cmd/cmd_adapter.c create mode 100644 assets/User_code/module/cmd/cmd_adapter.h create mode 100644 assets/User_code/module/cmd/cmd_behavior.c create mode 100644 assets/User_code/module/cmd/cmd_behavior.h create mode 100644 assets/User_code/module/cmd/cmd_example.c create mode 100644 assets/User_code/module/cmd/cmd_types.h create mode 100644 build.bat create mode 100755 build.sh diff --git a/.DS_Store b/.DS_Store index 683c4e52186d236511bd8c40a7516f200642c657..ff21cdc1aa3a85cae83f7ff4c21c7f4d923466b9 100644 GIT binary patch delta 54 xcmZp1XmOa}&&aniU^hP_-)0_xudI``#dIdui%pr_FJ3XR;oN3+iC<`9rvVK|6o3E# delta 436 zcmZp1XmOa}&nUDpU^hRb&}JTiudM2<3`q>744Di$3@M&D`N>H+`AG~63<5yBiGhK6 z-G4A(V3_<*R9}*XAqA+in4tt!CF7*Ya$<|?xfy&Jf*A6F=H)Y#Fz5l*6)>bSB%`Wj zVnQ|*Xp1n4E>DI$kogRWK=0A diff --git a/BUILD_GUIDE.md b/BUILD_GUIDE.md new file mode 100644 index 0000000..7e1bcfb --- /dev/null +++ b/BUILD_GUIDE.md @@ -0,0 +1,131 @@ +# MRobot 打包说明 + +## 问题原因 + +之前使用 `--onefile` 模式和 `--add-data` 添加 assets 导致的问题: +1. `--onefile` 将所有文件打包进 exe,运行时解压到临时目录 `sys._MEIPASS` +2. 更新代码时下载到 `exe目录/assets` +3. 但读取时从 `sys._MEIPASS/assets` 读取(每次都是打包时的原始文件) +4. 结果:更新成功但读不到新文件 + +## 解决方案:使用 `--onedir` 模式 + +### 方法一:使用提供的脚本(推荐) + +**macOS/Linux:** +```bash +./build.sh +``` + +**Windows:** +```cmd +build.bat +``` + +### 方法二:手动执行命令 + +```bash +# 清理旧文件 +rm -rf build dist *.spec + +# 打包(不要添加 --add-data) +pyinstaller MRobot.py \ + --onedir \ + --windowed \ + --icon=assets/logo/M.ico \ + --name=MRobot \ + --clean +``` + +### 创建安装程序 + +打包完成后,使用 Inno Setup 编译 `MRobot.iss` 创建安装程序。 + +## 打包模式对比 + +### `--onedir` 模式(推荐)✅ +- **优点:** + - assets 文件夹在 exe 同级目录,可以被更新覆盖 + - 更新代码库后能正确读取新文件 + - 文件结构清晰,便于调试 +- **缺点:** + - 需要分发整个文件夹(但可以用 Inno Setup 打包成单个安装程序) + +### `--onefile` 模式(不推荐)❌ +- **优点:** + - 单个 exe 文件 +- **缺点:** + - 外部资源文件无法更新(因为每次都从 exe 内部解压) + - 启动较慢(需要解压) + - 不适合需要更新资源的应用 + +## 文件结构 + +### 打包后(onedir 模式) +``` +dist/MRobot/ +├── MRobot.exe # 主程序 +├── _internal/ # PyInstaller 依赖库 +└── assets/ # 由 Inno Setup 安装时复制 + ├── logo/ + ├── User_code/ + └── mech_lib/ +``` + +### 安装后 +``` +%APPDATA%\MRobot\ # 或 {userappdata}\MRobot +├── MRobot.exe +├── _internal/ +└── assets/ # 可以被更新覆盖 + ├── logo/ + ├── User_code/ # 👈 更新代码库会更新这里 + └── mech_lib/ +``` + +## 工作原理 + +1. **首次运行:** + - 代码检测到 `exe目录/assets` 不存在 + - 从 `sys._MEIPASS/assets` 复制初始资源(如果存在) + - 但在 onedir 模式下,Inno Setup 已经安装了 assets,所以直接使用 + +2. **更新代码库:** + - 下载最新代码到 `exe目录/assets/User_code` + - 清除缓存 + - 重新读取 `exe目录/assets/User_code`(能看到新模块如 oid) + +3. **重新打开软件:** + - 直接读取 `exe目录/assets`(包含更新后的文件) + +## 注意事项 + +1. **不要使用 `--add-data "assets;assets"`** + - 这会将 assets 打包进 exe,导致无法更新 + +2. **Inno Setup 负责安装 assets** + - ISS 文件会将 assets 复制到安装目录 + - 这样 assets 就在 exe 同级目录,可以被更新 + +3. **代码已经优化** + - `CodeGenerator.get_assets_dir()` 优先使用 `exe目录/assets` + - 更新和读取使用相同路径 + - 首次运行时自动初始化(如果需要) + +## 测试步骤 + +1. 运行 `build.bat` 或 `build.sh` 打包 +2. 使用 Inno Setup 编译 `MRobot.iss` 创建安装程序 +3. 安装并运行 MRobot +4. 点击"选择项目路径",选择一个 CubeMX 项目 +5. 点击"更新代码库" +6. 检查是否能看到新的模块(如 oid) +7. 关闭软件,重新打开 +8. 再次进入项目,确认新模块仍然存在 + +## 版本更新 + +修改 `MRobot.iss` 中的版本号: +```ini +AppVersion=1.0.9 ; 更新这里 +``` diff --git a/MRobot.iss b/MRobot.iss index f2ac647..8268548 100644 --- a/MRobot.iss +++ b/MRobot.iss @@ -1,17 +1,18 @@ [Setup] AppName=MRobot -AppVersion=1.0.1 +AppVersion=1.0.8 DefaultDirName={userappdata}\MRobot DefaultGroupName=MRobot OutputDir=. OutputBaseFilename=MRobotInstaller [Files] -Source: "dist\MRobot.exe"; DestDir: "{app}"; Flags: ignoreversion +; 复制整个 dist\MRobot 文件夹(onedir 模式生成的所有文件) +Source: "dist\MRobot\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs +; 复制 assets 资源文件到安装目录(支持后续更新) Source: "assets\logo\*"; DestDir: "{app}\assets\logo"; Flags: ignoreversion recursesubdirs Source: "assets\User_code\*"; DestDir: "{app}\assets\User_code"; Flags: ignoreversion recursesubdirs Source: "assets\mech_lib\*"; DestDir: "{app}\assets\mech_lib"; Flags: ignoreversion recursesubdirs -Source: "assets\logo\M.ico"; DestDir: "{app}\assets\logo"; Flags: ignoreversion [Icons] Name: "{group}\MRobot"; Filename: "{app}\MRobot.exe"; IconFilename: "{app}\assets\logo\M.ico" diff --git a/app/__pycache__/__init__.cpython-39.pyc b/app/__pycache__/__init__.cpython-39.pyc index 9dd2ee62372c23ecb3202b7712bdef17bb221f6e..121d291e926c8717e27d7e89001187ecb799ebe7 100644 GIT binary patch delta 24 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 IzObA851cL-8~^|S delta 2770 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 delta 2656 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 delta 2674 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 Vv7!N9n3xE*-s8ImW+x0+{a?{U02u%P literal 0 HcmV?d00001 diff --git a/app/__pycache__/function_fit_interface.cpython-39.pyc b/app/__pycache__/function_fit_interface.cpython-39.pyc index 886cba0e05d5bde3b130b40825b490f3824aa4ba..827a109e552f9300f93f0988ae32438909acdf20 100644 GIT binary patch delta 21 bcmca=bJd0?k(ZZ?0SMj|YGrQZ@stAqL_`J3 delta 21 bcmca=bJd0?k(ZZ?0SLNF?`Le}@stAqMS%t% diff --git a/app/__pycache__/home_interface.cpython-39.pyc b/app/__pycache__/home_interface.cpython-39.pyc index 311a7443d6f1770bedd21f1eddde03fa8f69edab..5c30dbde5191b4dac2e42f0ec3003c1724e5dbaa 100644 GIT binary patch delta 21 bcmbOxFin6bk(ZZ?0SMj|YGrQZ;o<-QGf)Jd delta 21 bcmbOxFin6bk(ZZ?0SLNF?`Le};o<-QG>ruG diff --git a/app/__pycache__/main_window.cpython-39.pyc b/app/__pycache__/main_window.cpython-39.pyc index 8e971ac8d207c48ed0c5b8677831aa278c6a7451..386b8f7059c2b24a1d1846267f4c5f1aed8ec636 100644 GIT binary patch delta 2480 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 O+Ib4lB%tosi2McK2x!Ov diff --git a/app/__pycache__/mini_tool_interface.cpython-39.pyc b/app/__pycache__/mini_tool_interface.cpython-39.pyc index 79f3a2aeb34bdabbf2a84f429fd0f01cf04ac0c4..624bef01a6cae34288ffa93cba120d2b020cfaef 100644 GIT binary patch delta 21 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 delta 13076 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 delta 4853 zcmb6dTaX-8wQqM%PwzZ>XJ%)g+1*SYBs-h1n@uo;mBfH45enA4V8dt}d*}8hGdnMC z_n2gy%>W4`ios2884yG#79jY*$6~}ns-*DCKYy&UiGC=3y%i^FbQ3hTvb&8t#{9=QkA^q0zIx)LJSZ zl9F8)-~09CI|NorDsJ~ZmAsQZe4JS(-B&tM%$H1RF*h_@Vg=Jl&zy2B+YL5nPPSlW zE=Kzoe@8YDZ4flDLH>cfhZua1vc_is0?6@2rpR(If#h`v3|{x;*SF^{61O9r&g4zo zPN$jBGK6d!d01N{N&dRlOGfzbwZZN&M0?BNNN|nvfdBFBn{a+309VVH#f+6_Hy~yW zVpOY;b=b`~UnaZw8~@kkh~Vl&(k%$q@ls$XN$}?b`@;Q*=mn6}*%<$KV4`myVm=MP zCDw9Pd~dLz-HXJD#l_&uaxjHsZzG%;ch}Q6KZ?LakO452)Yx6{b@g)IbkLu!W}mVh ztKj(8!*^cF$u;?kJg+!fjnovXQ1yZWbU#r1IX&0W2*4xu-JdW?n;MZ@zNHRjRQ&IMxcgm0wzjeFllH|<0vHH}7YmgcpZR`bvK z*fmfZZ7c0TrD97)BTQq+KP^%1kn{lZb)ojBB^pQV@a;Y?)pPNurDwFJ0$7UWfw2eY zo}gz4dl<02OIVoo0VN8ua#J=sEgb@x;$Bs9dKbv4YebsYiB#PLeBetkr{C$T>1PPa zc!u3C(YiLTpVrYrDn{F+ZNlE1^%$m)fd`Aa?BuNE}l|tGPNzDG#R0eZf>kr2={JP+0M*z?|Mvznk zpQQI#Vi?^Oj>#H{QZoG>!3^E}PDA2z$Iz%Q6h!M7O(COt;vV zRQwE=RRKsuBh|^uh<3~Yjb=18oM=L%9we3&)A1*`aio8o1*PaF$b1}T^a2~ zAjOmz`=TV(!DFt^n=WNZv4`mLl?BHyR@lE2?f*#T3nkT_LypOuZ1GqE%&9kv%-Gmi zb^WxN6?n*qNE4()^8m7?BJeOg!R#wRNqUFEh+$@^M)$RNu_l!&&bmqn@Lue^ef5#+ zPh71IwRvW<#jJhYqLV^%U7YRis=hTLtlM1;ZB2MpByZ8()tNnlZgseLeG}JJo}TkUw&>fk?ePMNcLrjqCJ-DFU(P#v8}kHr7W%H zO4%ZVt$M}HD{66=y8cY5ShO;Z+s(K2b=TQa4eLkl3WAde;DDi4lv%duxIP=*&ahaf zw1S9s3Hk=9;%#-ORmQ5q0 zNcAF~hWKMW{RgH1DaopAkcbjdVx))kC>mS>O%ACcH3C?j1mLFpf`3EePLSI6lbuS2#QLs352uey zDbTcd>Hj%g0#8wx#Gb{`^8j3p6@(4nMa&BTT8pDcQjyjH!G(6LqGPick?(s5zK>u~ z1aI3#>|21mZE?@~U8F9e=Lg6n3eeKx!j`rL>?LGrFYn#vl8Y^*S8-rfq6syof_8>w%Z{kR5Kfzcaph6ET^Ngy^U`LyoX=)V2WrSHk8b+x z%;!KsP0C5^h(mI6L&5PC!j4oU4s?><3>%>0c4%g_Q?TuMXo#uLV(^o2luXpyJNWyfi4B!bKs1|$ zm%e)a{KC7xe29GsnT{e@0Ki|_!pLoW%hn_5nAa2ZAxV_FBRCSz;YA#sMIee!`>KhT zB^yA(QwXjg5HW~_g<&9y`>yY~-U*Vn&+7)(|oWxE}sOG+2)W2uX_&P`Pe&^WQ zZoW diff --git a/app/tools/__pycache__/check_update.cpython-39.pyc b/app/tools/__pycache__/check_update.cpython-39.pyc index 8f378d91e9a6afc3c475c799e83bea8320bf4a0c..65d4b7a54141e8a2bbaec035b871f030e6c867a0 100644 GIT binary patch delta 223 zcmew?^jU}}k(ZZ?0SMj|YGrQZxyj6UYw7UZM?HQREU0RZH`H3t9y delta 223 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 B_O1W` diff --git a/app/tools/__pycache__/code_task_config.cpython-39.pyc b/app/tools/__pycache__/code_task_config.cpython-39.pyc index 6aba3321b6fcac0a746c15e0978f7fd67441fcc9..905248472626905e8647cce25785673bf3c63c40 100644 GIT binary patch delta 21 bcmZ4QwBCs)k(ZZ?0SMj|YGrQZQC0*1KJNu* delta 21 bcmZ4QwBCs)k(ZZ?0SLNF?`Le}QC0*1Kr98k diff --git a/app/tools/__pycache__/finance_manager.cpython-39.pyc b/app/tools/__pycache__/finance_manager.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfb545a1158d027e5c2cf4346caffcff587eac5a GIT binary patch literal 20849 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 literal 0 HcmV?d00001 diff --git a/app/tools/__pycache__/part_download.cpython-39.pyc b/app/tools/__pycache__/part_download.cpython-39.pyc index dc02841eba8a93174848745e07236bfbe9782e37..81d155ee829d952e453051b7bf4da03c3b5ea70a 100644 GIT binary patch delta 21 bcmZ3-yN;J9k(ZZ?0SMj|YGrQZS;PhaH_QcJ delta 21 bcmZ3-yN;J9k(ZZ?0SLNF?`Le}S;PhaISB={ diff --git a/app/tools/__pycache__/update_check_thread.cpython-39.pyc b/app/tools/__pycache__/update_check_thread.cpython-39.pyc index a77f0014cf191004f2d0c3612be33267cb395459..b46ec3c5b5e8ff2676483496b10a52f7f7ce10ec 100644 GIT binary patch delta 21 bcmcb^d54oHk(ZZ?0SMj|YGrQZxxfMdKE4It delta 21 bcmcb^d54oHk(ZZ?0SMmozscChbAbf_L%qeI^(LNN(A?P8eeltr+6d;q} zH{bg`BiYGhOo5M?J?TaU73DvI==^9v{1ATrGyq3&P);#}6PZZTs;SCTGc|eYrY_Hr z8Iot%49hcOMjYKy9qke_4F}CAW1&ajQ<=_+7(1WCfW+bVBK-U>bcl(nTIIN~%PDzO z)se#Vy6Wf+R1Hzh39-;k9Z74{ghw6O|rKVp0yqco@^#M9q zA7aU+VOdXC+h@w@1)piwRX@z2Qm``WM+8>wX5BT_k5Sz@w2CgGwtkv*JL;eUHa(IP zXJQsXuaYd@KwvWklA|o{^f~=kRV3=kNZq8+t*PWAk-alOpP(c4k%qF0pcbu~sif(X z^1JOXMGqV3LsAedr zrv5FF&6M&hHmg;8tB0z6>=01TR{NzzjP&_=t+v}Gf{c&yoct=_r?}C0%os|znt)XVwfVi&E2o!uiUgyE?LOs!xAEXO50R3vVJ^61I)SzM&9SKtxQuqh>6 z^UFSuEZV-LRL|#n(WZ-BU-Dc~1M7mF$2^A5<7|oAb2-ezvO_)(gOBWM4v*M#zO*qc zYu?Ra%i_kI?PFO4(s*T>epM=V%BTJpI;alR>?;Fd{Y#B__NgqG@hJo4i*#s2A^@krJyPz&&=D42sUImKeDZ!W7F_Du zIk$ox-fM|UayG@H=T^>JSOBi(Q!;j#hl@55c_!V$ya%3gIk8(jCHHBM)=DHNM`*@6 z#)mMEiiTRU%Mlobh+xK``R!!Pc(z1DfItuglcSI3JcuSyonXIc%6>~4Rm?=YZPK&Z zwR=k}co6fx8TY*s$zqFm9yMd_+aNlt3l7(1Z$n}}KKyG5MF%4nm`pV)M3QL+sNh20 z(CgqP-BHL%SlDl#%TCUov9q&3@$z_f%FCAWP>VnN%53mv%)+|Q%5|SD6&=xG`2rWq zJl;Wzf2jR`0#J~ysVJewP%r91DOF%GltO7O1u&&0fSW)%&_dn=SOVlaGC(@2f`+OC zG_-^Y)+naMP#76%57-H79bg|)Q5vPyQP50)S3~Png|*;@!D0_jL5!5h2KeHe0F6-< z{Gnbot%7XVDvVxGg>?#%m!O6*ZF+ioEJ`wflWqZy2yjdQ@%#|+P?He>o)JLU$Yyqc aQ^4cK^RUUK9DYIkvGUUZ42a(GRsRpQtq=GB delta 1304 zcmah}&yU+g6rS-oc48;a?_`tGWxK2@MXK6u)k9lxKopQbXoa+gRSPuA?znA2>rL%h zX*YUq)TR<#77UiEvIXG?4&2~?)B~u0K*fQx&um$#679J{h&PG*V^74H=Xsv*ee->9 z5^p#DC|R9c&LH^tZtv0Mlcg`M(QpPc6USK`-W^5=r#=%zP_A$`Vy+NMk437Wz0{cc z>Lk-ZFVT|dRaxJOTr*%VF=p6Z9IMVLh zMuQa3AeDv^4A7pf1r>G`pz6oYPy#-O{)`;Gu3Elvc=NklTvQw|1AvQOery)0{ zSaSih8OZShFK#Q8aN=9ZI%0h@u6r%Xy$Zf z>Lz+sDu0W73?DJS;1~T86fryDmnS6}6rhYQD=12d=Ago>;S;s85GdEuP?`X%&w*70 z))HWi*CcR=z&8SV?I~D+;_f6eEbNcWqz&tt4Uo@%1Pa&)X=(*csd$Z;%y?lL=hz0e zbpqQ^$2MF*PUbdW;(U>zCuI9a)c18N>8u4BYO469aS;Eb5AXi+@b=Gt{`&o2(T&Hy?d%4h@BZ-V z-o2l8@83Ez7e3X#Nx2kZ;cflHmDYT$U$R9<2sdWlmKQ7QUaa;z;&QC>uIqHJ+Oc78 z+G`u4vwFpj)!us7iBo;I>xfvhH@lwjV!gBKO-j=3_QmcMyWI}=(!P;-dvne1i|)D; z^2}L{dBSbYgpV^vim{HAZR9_1Bv!cbL8ISsZAVNWuXffx+33r8OzrT#@jg8jn&wjD zGZap!%Cd?@@nTszOABn4TH%g)j4I&+b0PfKoO|~S!dh%;X{nWQvACA5MptvWNczIxk|+ diff --git a/app/tools/code_generator.py b/app/tools/code_generator.py index 5549df1..654ccbd 100644 --- a/app/tools/code_generator.py +++ b/app/tools/code_generator.py @@ -100,26 +100,41 @@ class CodeGenerator: # 打包后的环境 print("检测到打包环境") - # 优先使用sys._MEIPASS(PyInstaller的临时解包目录) - if hasattr(sys, '_MEIPASS'): + # 优先使用可执行文件所在目录(支持更新后的文件) + exe_dir = os.path.dirname(sys.executable) + exe_assets = os.path.join(exe_dir, "assets") + + # 如果exe目录下不存在assets,但_MEIPASS中有,则首次复制过去 + if not os.path.exists(exe_assets) and hasattr(sys, '_MEIPASS'): + base_path = getattr(sys, '_MEIPASS') + meipass_assets = os.path.join(base_path, "assets") + if os.path.exists(meipass_assets): + try: + import shutil + print(f"首次运行:从 {meipass_assets} 复制到 {exe_assets}") + shutil.copytree(meipass_assets, exe_assets) + print("初始资源复制成功") + except Exception as e: + print(f"复制初始资源失败: {e}") + + # 优先使用exe目录下的assets(这样可以读取更新后的文件) + if os.path.exists(exe_assets): + assets_dir = exe_assets + print(f"使用可执行文件目录: {assets_dir}") + # 后备方案:使用PyInstaller的临时解包目录 + elif hasattr(sys, '_MEIPASS'): base_path = getattr(sys, '_MEIPASS') assets_dir = os.path.join(base_path, "assets") - print(f"使用PyInstaller临时目录: {assets_dir}") + print(f"后备:使用PyInstaller临时目录: {assets_dir}") + # 最后尝试工作目录 else: - # 后备方案:使用可执行文件所在目录 - exe_dir = os.path.dirname(sys.executable) - assets_dir = os.path.join(exe_dir, "assets") - print(f"使用可执行文件目录: {assets_dir}") - - # 如果都不存在,尝试其他可能的位置 - if not os.path.exists(assets_dir): - # 尝试从当前工作目录查找 cwd_assets = os.path.join(os.getcwd(), "assets") if os.path.exists(cwd_assets): assets_dir = cwd_assets print(f"从工作目录找到assets: {assets_dir}") else: - print(f"警告:无法找到assets目录,使用默认路径: {assets_dir}") + assets_dir = exe_assets # 即使不存在也使用exe目录,后续会创建 + print(f"使用默认路径(将创建): {assets_dir}") else: # 开发环境 current_dir = os.path.dirname(os.path.abspath(__file__)) diff --git a/app/tools/update_code.py b/app/tools/update_code.py index 283a53a..63b2ba5 100644 --- a/app/tools/update_code.py +++ b/app/tools/update_code.py @@ -10,21 +10,45 @@ import time def update_code(parent=None, info_callback=None, error_callback=None): url = "http://gitea.qutrobot.top/robofish/MRobot/archive/User_code.zip" - # 使用与CodeGenerator.get_assets_dir相同的逻辑确定assets目录 - if getattr(sys, 'frozen', False): - # 打包后的环境 - 使用可执行文件所在目录 - exe_dir = os.path.dirname(sys.executable) - assets_dir = os.path.join(exe_dir, "assets") - print(f"更新代码:打包环境,使用路径: {assets_dir}") - - # 如果exe_dir/assets不存在,尝试使用相对路径作为后备 - if not os.path.exists(assets_dir): - assets_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../assets") - print(f"更新代码:后备路径: {assets_dir}") - else: - # 开发环境 - assets_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../assets") - print(f"更新代码:开发环境,使用路径: {assets_dir}") + # 导入 CodeGenerator 以使用统一的路径获取逻辑 + try: + from app.tools.code_generator import CodeGenerator + # 直接使用 CodeGenerator 的路径获取方法,确保路径一致 + assets_dir = CodeGenerator.get_assets_dir("") + print(f"更新代码:使用 CodeGenerator 路径: {assets_dir}") + except Exception as e: + print(f"无法导入 CodeGenerator,使用后备路径逻辑: {e}") + # 后备方案:使用与CodeGenerator.get_assets_dir相同的逻辑确定assets目录 + if getattr(sys, 'frozen', False): + # 打包后的环境 + if hasattr(sys, '_MEIPASS'): + base_path = getattr(sys, '_MEIPASS') + assets_dir = os.path.join(base_path, "assets") + print(f"更新代码:使用PyInstaller临时目录: {assets_dir}") + else: + # 使用可执行文件所在目录 + exe_dir = os.path.dirname(sys.executable) + assets_dir = os.path.join(exe_dir, "assets") + print(f"更新代码:打包环境,使用路径: {assets_dir}") + + # 如果不存在,尝试工作目录 + if not os.path.exists(assets_dir): + cwd_assets = os.path.join(os.getcwd(), "assets") + if os.path.exists(cwd_assets): + assets_dir = cwd_assets + print(f"更新代码:使用工作目录: {assets_dir}") + else: + # 开发环境 + current_dir = os.path.dirname(os.path.abspath(__file__)) + while current_dir != os.path.dirname(current_dir): + if os.path.basename(current_dir) == 'MRobot': + break + parent_dir = os.path.dirname(current_dir) + if parent_dir == current_dir: + break + current_dir = parent_dir + assets_dir = os.path.join(current_dir, "assets") + print(f"更新代码:开发环境,使用路径: {assets_dir}") local_dir = os.path.join(assets_dir, "User_code") print(f"更新代码:最终目标目录: {local_dir}") @@ -93,6 +117,16 @@ def update_code(parent=None, info_callback=None, error_callback=None): if backup_dir and os.path.exists(backup_dir): shutil.rmtree(backup_dir, ignore_errors=True) + # 清除 CodeGenerator 的缓存,确保后续读取更新后的文件 + try: + from app.tools.code_generator import CodeGenerator + CodeGenerator._assets_dir_cache = None + CodeGenerator._assets_dir_initialized = False + CodeGenerator._template_dir_logged = False + print("已清除 CodeGenerator 缓存") + except Exception as e: + print(f"清除缓存失败(可忽略): {e}") + if info_callback: info_callback(parent) return True diff --git a/assets/Finance_Data/accounts/06266d34-8789-45e9-aff0-e42549c238ba/metadata.json b/assets/Finance_Data/accounts/06266d34-8789-45e9-aff0-e42549c238ba/metadata.json new file mode 100644 index 0000000..729b095 --- /dev/null +++ b/assets/Finance_Data/accounts/06266d34-8789-45e9-aff0-e42549c238ba/metadata.json @@ -0,0 +1,8 @@ +{ + "id": "06266d34-8789-45e9-aff0-e42549c238ba", + "name": "admin", + "description": "默认管理账户", + "categories": [], + "created_at": "2025-12-19T22:06:29.964929", + "updated_at": "2025-12-19T22:06:29.964938" +} \ No newline at end of file diff --git a/assets/User_code/config.csv b/assets/User_code/config.csv index 32290e1..d462c63 100644 --- a/assets/User_code/config.csv +++ b/assets/User_code/config.csv @@ -1,4 +1,4 @@ bsp,can,dwt,gpio,i2c,mm,spi,uart,pwm,time component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math -device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9 +device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9,oid,lcd_driver module,config, \ No newline at end of file diff --git a/assets/User_code/device/config.yaml b/assets/User_code/device/config.yaml index a24a6f6..e240946 100644 --- a/assets/User_code/device/config.yaml +++ b/assets/User_code/device/config.yaml @@ -224,4 +224,23 @@ devices: thread_signals: [] files: header: "vofa.h" - source: "vofa.c" \ No newline at end of file + source: "vofa.c" + oid: + name: "oid编码器" + description: "oid编码器驱动" + dependencies: + bsp: ["time", "can", "mm"] + component: ["user_math"] + thread_signals: [] + files: + header: "oid.h" + source: "oid.c" + lcd_driver: + name: "lcd显示屏" + description: "lcd驱动(SPI)" + dependencies: + bsp: ["gpio", "spi"] + thread_signals: [] + files: + header: "lcd.h" + source: "lcd.c" \ No newline at end of file diff --git a/assets/User_code/device/lcd_driver/lcd.c b/assets/User_code/device/lcd_driver/lcd.c new file mode 100644 index 0000000..afb6ed6 --- /dev/null +++ b/assets/User_code/device/lcd_driver/lcd.c @@ -0,0 +1,743 @@ +/* + LCD驱动 + +高效: +--------控制引脚配置,屏幕属性配置完成后即可使用 +可扩展: +--------添加你喜欢的颜色, +--------在lcd_library.h添加你的自定义点阵库-使用LCD_DrawBitmap驱动任意位图 +兼容: +--------LSB与MSB顺序的字表 + +所有绘制函数使用示例: +LCD_DrawPoint(0,0,BLUE); +LCD_DrawChar(10, 10, 'A', RED, WHITE); +LCD_DrawLine(10, 10, 100, 50, RED); +LCD_DrawRectangle(10,10,50,100,GREEN); +LCD_DrawHollowCircle(200,50,16,RED); +LCD_DrawSolidCircle(200,100,16,RED); +LCD_DrawString(0,0,"MR16",MEDIUMORCHID,32,LSB); + +extern const unsigned char logo_M[]; +LCD_DrawBitmap(logo_M,70,70,64,64,MEDIUMORCHID,MSB); + +*/ + +/* Includes ----------------------------------------------------------------- */ +#include "device/lcd_driver/lcd.h" +#include "device/device.h" +#include "device/lcd_driver/lcd_lib.h" +#include "bsp/spi.h" + +#include +#include +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ +/* Private define ----------------------------------------------------------- */ + +/* USER DEFINE BEGIN */ + +/* USER DEFINE END */ +/* Private macro ------------------------------------------------------------ */ +/* Private typedef ---------------------------------------------------------- */ +/* Private variables -------------------------------------------------------- */ +static LCD_Orientation_t lcd_orientation = LCD_ORIENTATION_PORTRAIT; // 当前屏幕方向 + +/* Private function -------------------------------------------------------- */ +/** + * 写命令到LCD + * + * @param cmd 要写入的命令 + * + * @note 此函数用于向LCD发送控制命令。通过设置数据/命令选择引脚为命令模式, + * 并通过SPI接口发送命令。 + */ +static int8_t LCD_WriteCommand(uint8_t cmd) { + LCD_DC_LOW(); // 设置数据/命令选择引脚为命令模式 + LCD_CS_LOW(); // 使能SPI片选 + BSP_SPI_Transmit(BSP_SPI_LCD, &cmd, 1, false); // 通过SPI发送命令 + LCD_CS_HIGH(); // 禁用SPI片选 + return DEVICE_OK; +} + +/** + * 写数据到LCD + * + * @param data 要写入的数据 + * + * @note 此函数用于向LCD发送数据。通过设置数据/命令选择引脚为数据模式, + * 并通过SPI接口发送数据。 + */ +static int8_t LCD_WriteData(uint8_t data) { + LCD_DC_HIGH(); // 设置数据/命令选择引脚为数据模式 + LCD_CS_LOW(); // 使能SPI片选 + BSP_SPI_Transmit(BSP_SPI_LCD, &data, 1, false); // 通过SPI发送数据 + LCD_CS_HIGH(); // 禁用SPI片选 + return DEVICE_OK; +} + +/** + * 使用 DMA 写多个数据到 LCD + * + * @param data 数据缓冲区指针 + * @param size 数据大小(字节数) + * + * @note 此函数用于通过DMA快速发送大量数据到LCD。适用于数据量较大的场景, + * 提高传输效率。 + */ +static int8_t LCD_WriteDataBuffer_DMA(uint8_t *data, uint16_t size) { + LCD_DC_HIGH(); // 设置数据/命令选择引脚为数据模式 + LCD_CS_LOW(); // 使能SPI片选 + BSP_SPI_Transmit(BSP_SPI_LCD, data, size, true); // 通过SPI发送数据 + while(BSP_SPI_GetState(BSP_SPI_LCD) != HAL_SPI_STATE_READY); // 等待SPI传输完成 + LCD_CS_HIGH(); // 禁用SPI片选 + return DEVICE_OK; +} + +/** + * 修改原来的 LCD_WriteDataBuffer,增加 DMA 支持 + * + * @param data 数据缓冲区指针 + * @param size 数据大小(字节数) + * + * @note 此函数根据数据量大小选择使用DMA或普通SPI传输。如果数据量大于64字节, + * 使用DMA传输,否则使用普通SPI传输。 + */ +static int8_t LCD_WriteDataBuffer(uint8_t *data, uint16_t size) { + if (size > 64) { // 如果数据量较大,使用 DMA + LCD_WriteDataBuffer_DMA(data, size); + } else { // 否则使用普通传输 + LCD_DC_HIGH(); // 设置数据/命令选择引脚为数据模式 + LCD_CS_LOW(); // 使能SPI片选 + BSP_SPI_Transmit(BSP_SPI_LCD, data, size, false); // 通过SPI发送数据 + LCD_CS_HIGH(); // 禁用SPI片选 + } + return DEVICE_OK; +} + +/** + * 根据屏幕方向映射坐标 + * + * @param x 输入的X坐标 + * @param y 输入的Y坐标 + * @param mx 映射后的X坐标(输出) + * @param my 映射后的Y坐标(输出) + * + * @note 此函数根据当前屏幕方向,将输入的坐标映射到实际的屏幕坐标。 + */ +static int8_t LCD_MapCoords(uint16_t x, uint16_t y, uint16_t *mx, uint16_t *my) { + switch (lcd_orientation) { + case LCD_ORIENTATION_PORTRAIT: // 0° + *mx = x; + *my = y; + break; + case LCD_ORIENTATION_LANDSCAPE: // 90°顺时针 + *mx = y; + *my = LCD_HEIGHT - 1 - x; + break; + case LCD_ORIENTATION_LANDSCAPE_INVERTED: // 90°逆时针 + *mx = LCD_WIDTH - 1 - y; + *my = x; + break; + case LCD_ORIENTATION_PORTRAIT_INVERTED: // 180° + *mx = LCD_WIDTH - 1 - x; + *my = LCD_HEIGHT - 1 - y; + break; + default: + *mx = x; + *my = y; + break; + } + return DEVICE_OK; +} + +/** + * 设置LCD绘图窗口 + * + * @param x 窗口起始X坐标 + * @param y 窗口起始Y坐标 + * @param w 窗口宽度 + * @param h 窗口高度 + * + * @note 此函数用于设置LCD的绘图窗口,指定后续绘图操作的区域。 + */ +static int8_t LCD_SetAddressWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + uint16_t x_start = x + X_OFFSET; // 计算窗口起始X坐标 + uint16_t x_end = x_start + w - 1; // 计算窗口结束X坐标 + uint16_t y_start = y + Y_OFFSET; // 计算窗口起始Y坐标 + uint16_t y_end = y_start + h - 1; // 计算窗口结束Y坐标 + + LCD_WriteCommand(0x2A); // 列地址设置 + uint8_t data_x[] = {x_start >> 8, x_start & 0xFF, x_end >> 8, x_end & 0xFF}; + LCD_WriteDataBuffer(data_x, sizeof(data_x)); + + LCD_WriteCommand(0x2B); // 行地址设置 + uint8_t data_y[] = {y_start >> 8, y_start & 0xFF, y_end >> 8, y_end & 0xFF}; + LCD_WriteDataBuffer(data_y, sizeof(data_y)); + + LCD_WriteCommand(0x2C); // 内存写入 + + return DEVICE_OK; +} +/* Exported functions ------------------------------------------------------- */ + +/** + * 初始化LCD + * + * @param orientation 屏幕方向(竖屏、横屏等) + * + * @note 此函数用于初始化LCD显示屏,设置屏幕方向、像素格式、伽马校正等参数。 + * 根据传入的屏幕方向参数,调整屏幕的显示方向。 + */ +int8_t LCD_Init(LCD_Orientation_t orientation) { + lcd_orientation = orientation; // 设置屏幕方向 + + LCD_RST_LOW(); // 复位引脚低电平 + HAL_Delay(50); // 延时 + LCD_RST_HIGH(); // 复位引脚高电平 + HAL_Delay(50); // 延时 + + LCD_WriteCommand(0x36); // 内存数据访问控制 + switch (orientation) { + case LCD_ORIENTATION_PORTRAIT: // 竖屏模式 + LCD_WriteData(0x08); // MY=1, MX=0, MV=0, ML=0, BGR=0 + break; + case LCD_ORIENTATION_LANDSCAPE: // 横屏模式(90°顺时针旋转) + LCD_WriteData(0x60); // MY=0, MX=1, MV=1, ML=0, BGR=0 + break; + case LCD_ORIENTATION_LANDSCAPE_INVERTED: // 横屏模式(90°逆时针旋转) + LCD_WriteData(0xA0); // MY=1, MX=1, MV=1, ML=0, BGR=0 + break; + case LCD_ORIENTATION_PORTRAIT_INVERTED: // 竖屏模式(180°旋转) + LCD_WriteData(0xC8); // MY=1, MX=1, MV=0, ML=0, BGR=0 + break; + default: + // LCD_WriteData(0x08); // 默认竖屏模式 + break; + } + + LCD_WriteCommand(0x3A); // 接口像素格式 + LCD_WriteData(0x05); // 16位色 + + LCD_WriteCommand(0xB2); // 前廊设置 + uint8_t porch[] = {0x0C, 0x0C, 0x00, 0x33, 0x33}; + LCD_WriteDataBuffer(porch, sizeof(porch)); + + LCD_WriteCommand(0xB7); // 门控设置 + LCD_WriteData(0x35); + + LCD_WriteCommand(0xBB); // VCOM设置 + LCD_WriteData(0x19); + + LCD_WriteCommand(0xC0); // LCM控制 + LCD_WriteData(0x2C); + + LCD_WriteCommand(0xC2); // VDV和VRH命令使能 + LCD_WriteData(0x01); + + LCD_WriteCommand(0xC3); // VRH设置 + LCD_WriteData(0x12); + + LCD_WriteCommand(0xC4); // VDV设置 + LCD_WriteData(0x20); + + LCD_WriteCommand(0xC6); // 帧率控制 + LCD_WriteData(0x0F); + + LCD_WriteCommand(0xD0); // 电源控制1 + LCD_WriteData(0xA4); + LCD_WriteData(0xA1); + + LCD_WriteCommand(0xE0); // 正电压伽马控制 + uint8_t gamma_pos[] = {0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23}; + LCD_WriteDataBuffer(gamma_pos, sizeof(gamma_pos)); + + LCD_WriteCommand(0xE1); // 负电压伽马控制 + uint8_t gamma_neg[] = {0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23}; + LCD_WriteDataBuffer(gamma_neg, sizeof(gamma_neg)); + + LCD_WriteCommand(0x21); // 显示反转开启 + LCD_WriteCommand(0x11); // 退出睡眠模式 + HAL_Delay(120); // 延时 + LCD_WriteCommand(0x29); // 显示开启 + + return DEVICE_OK; +} + +/** + * 清屏函数 + * + * @param color 清屏颜色(RGB565格式) + * + * @note 此函数用于将整个LCD屏幕填充为指定颜色。 + */ +int8_t LCD_Clear(uint16_t color) { + uint8_t color_data[] = {color >> 8, color & 0xFF}; // 将颜色转换为字节数组 + LCD_SetAddressWindow(0, 0, LCD_WIDTH, LCD_HEIGHT); // 设置整个屏幕为绘制窗口 + + // 创建一个缓冲区,用于存储一行的颜色数据 + uint32_t row_size = LCD_WIDTH * 2; // 每行像素占用 2 字节 + uint8_t *row_buffer = (uint8_t *)malloc(row_size); + if (row_buffer == NULL) return DEVICE_ERR_NULL; // 分配失败,直接返回 + + // 填充缓冲区为目标颜色 + for (uint32_t i = 0; i < row_size; i += 2) { + row_buffer[i] = color_data[0]; + row_buffer[i + 1] = color_data[1]; + } + + // 按行传输数据,覆盖整个屏幕 + for (uint32_t y = 0; y < LCD_HEIGHT; y++) { + LCD_WriteDataBuffer_DMA(row_buffer, row_size); + } + + free(row_buffer); // 释放缓冲区 + + return DEVICE_OK; +} + +/** + * 绘制单个像素点 + * + * @param x X坐标 + * @param y Y坐标 + * @param color 像素颜色(RGB565格式) + * + * @note 此函数用于在指定位置绘制一个像素点。 + */ +int8_t LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) { + uint16_t mx, my; + LCD_MapCoords(x, y, &mx, &my); // 根据屏幕方向映射坐标 + LCD_SetAddressWindow(mx, my, 1, 1); // 设置绘制窗口为单个像素 + uint8_t color_data[] = { (uint8_t)(color >> 8), (uint8_t)(color & 0xFF) }; // 将颜色转换为字节数组 + LCD_WriteDataBuffer(color_data, 2); // 写入像素数据 + + return DEVICE_OK; +} + +/** + * 绘制直线 + * + * @param x0 起始X坐标 + * @param y0 起始Y坐标 + * @param x1 终止X坐标 + * @param y1 终止Y坐标 + * @param color 直线颜色(RGB565格式) + * + * @note 此函数使用Bresenham算法绘制直线。 + */ +int8_t LCD_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { + int dx = x1 - x0; // 计算X方向增量 + int dy = y1 - y0; // 计算Y方向增量 + int sx = (dx >= 0) ? 1 : -1; // X方向步长 + int sy = (dy >= 0) ? 1 : -1; // Y方向步长 + dx = dx >= 0 ? dx : -dx; // 取绝对值 + dy = dy >= 0 ? dy : -dy; // 取绝对值 + + if (dx == 0 && dy == 0) { // 单点 + LCD_DrawPoint((uint16_t)x0, (uint16_t)y0, color); + return DEVICE_OK; + } + + if (dx > dy) { // X方向增量大于Y方向增量 + int err = dx / 2; // 初始化误差 + int x = x0; + int y = y0; + for (int i = 0; i <= dx; i++) { + LCD_DrawPoint((uint16_t)x, (uint16_t)y, color); // 绘制当前点 + x += sx; // 更新X坐标 + err -= dy; // 更新误差 + if (err < 0) { + y += sy; // 更新Y坐标 + err += dx; // 更新误差 + } + } + } else { // Y方向增量大于X方向增量 + int err = dy / 2; // 初始化误差 + int x = x0; + int y = y0; + for (int i = 0; i <= dy; i++) { + LCD_DrawPoint((uint16_t)x, (uint16_t)y, color); // 绘制当前点 + y += sy; // 更新Y坐标 + err -= dx; // 更新误差 + if (err < 0) { + x += sx; // 更新X坐标 + err += dy; // 更新误差 + } + } + } + return DEVICE_OK; +} + +/** + * 绘制矩形 + * + * @param x1 矩形左上角X坐标 + * @param y1 矩形左上角Y坐标 + * @param x2 矩形右下角X坐标 + * @param y2 矩形右下角Y坐标 + * @param color 矩形颜色(RGB565格式) + * + * @note 此函数通过绘制四条边来绘制矩形。 + */ +int8_t LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { + LCD_DrawLine(x1, y1, x2, y1, color); // 上边 + LCD_DrawLine(x1, y1, x1, y2, color); // 左边 + LCD_DrawLine(x1, y2, x2, y2, color); // 下边 + LCD_DrawLine(x2, y1, x2, y2, color); // 右边 + return DEVICE_OK; +} + +int8_t LCD_DrawSolidRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { + int8_t a; + if(y1>y2) a=1; + else a=-1; + while(y1!=y2) { + LCD_DrawLine(x1, y1, x2, y1, color); // 上边 + LCD_DrawLine(x1, y2, x2, y2, color); // 下边 + y1-=a;y2+=a; + } + return DEVICE_OK; +} +/** + * 绘制空心圆 + * + * @param x0 圆心X坐标 + * @param y0 圆心Y坐标 + * @param r 圆的半径 + * @param color 圆的颜色(RGB565格式) + * + * @note 此函数使用中点圆算法绘制空心圆。 + */ +int8_t LCD_DrawHollowCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) { + int a = 0; // X方向增量 + int b = r; // Y方向增量 + + while (a <= b) { + LCD_DrawPoint(x0 - b, y0 - a, color); // 第3象限 + LCD_DrawPoint(x0 + b, y0 - a, color); // 第0象限 + LCD_DrawPoint(x0 - a, y0 + b, color); // 第1象限 + LCD_DrawPoint(x0 - a, y0 - b, color); // 第2象限 + LCD_DrawPoint(x0 + b, y0 + a, color); // 第4象限 + LCD_DrawPoint(x0 + a, y0 - b, color); // 第5象限 + LCD_DrawPoint(x0 + a, y0 + b, color); // 第6象限 + LCD_DrawPoint(x0 - b, y0 + a, color); // 第7象限 + + a++; // 更新X方向增量 + if ((a * a + b * b) > (r * r)) { // 判断是否超出半径范围 + b--; // 更新Y方向增量 + } + } + return DEVICE_OK; +} + +/** + * 绘制实心圆 + * + * @param x0 圆心X坐标 + * @param y0 圆心Y坐标 + * @param r 圆的半径 + * @param color 圆的颜色(RGB565格式) + * + * @note 此函数使用中点圆算法绘制实心圆,通过填充水平线段实现。 + */ +int8_t LCD_DrawSolidCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) { + int a = 0; // X方向增量 + int b = r; // Y方向增量 + int r2 = r * r; // 预计算半径的平方 + + while (a <= b) { + // 绘制8个对称点并填充水平线段 + LCD_DrawLine(x0 - b, y0 - a, x0 + b, y0 - a, color); // 第3象限 + LCD_DrawLine(x0 - b, y0 + a, x0 + b, y0 + a, color); // 第4象限 + LCD_DrawLine(x0 - a, y0 - b, x0 + a, y0 - b, color); // 第2象限 + LCD_DrawLine(x0 - a, y0 + b, x0 + a, y0 + b, color); // 第6象限 + + a++; // 更新X方向增量 + if ((a * a + b * b) > r2) { // 判断是否超出半径范围 + b--; // 更新Y方向增量 + } + } + return DEVICE_OK; +} + +/** + * 绘制字符 + * + * @param x 字符起始X坐标 + * @param y 字符起始Y坐标 + * @param ch 要绘制的字符 + * @param color 字符颜色(RGB565格式) + * @param font_size 字体大小(12或32) + * @param bit_order 位顺序(LSB或MSB) + * + * @note 此函数根据字体大小和位顺序绘制单个字符。 + */ +int8_t LCD_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order) { + if (ch < ' ' || ch > '~') { // 检查字符是否在可打印范围内 + return DEVICE_ERR; + } + + uint8_t index = ch - ' '; // 计算字符索引 + + const uint8_t *font_data=NULL; + uint8_t char_width=0; + uint8_t char_height=0; + uint8_t bytesPerRow=0; + + switch (font_size) { + case 12:// 12x6 字体(ascii_1206,特殊位映射 bit5..bit0) + #ifdef ASCII_1206 + font_data = (const uint8_t *)ascii_1206[index]; + char_width = 6; + char_height = 12; + + for (uint8_t row = 0; row < char_height; row++) { + for (uint8_t col = 0; col < char_width; col++) { + uint16_t pixel_x = x + col; + uint16_t pixel_y = y + row; + uint8_t bit_value; + if (bit_order == MSB) { // MSB 优先,项目约定:6 位放在 bit5..bit0 + bit_value = (font_data[row] >> (5 - col)) & 0x01; + } else { // LSB 优先 + bit_value = (font_data[row] >> col) & 0x01; + } + if (bit_value) { + LCD_DrawPoint(pixel_x, pixel_y, color); + } + } + } + #endif + break; + case 16:// 16x8 字体(ascii_1608:按行存储,每行 1 字节,MSB-first 常规映射) + #ifdef ASCII_1608 + font_data = (const uint8_t *)ascii_1608[index]; + char_width = 8; + char_height = 16; + + for (uint8_t row = 0; row < char_height; row++) { + uint8_t row_byte = font_data[row]; + for (uint8_t col = 0; col < char_width; col++) { + uint16_t pixel_x = x + col; + uint16_t pixel_y = y + row; + uint8_t bit_value; + if (bit_order == MSB) { + bit_value = (row_byte >> (7 - col)) & 0x01; // MSB-first: bit7 -> col0 + } else { + bit_value = (row_byte >> col) & 0x01; // LSB-first + } + if (bit_value) { + LCD_DrawPoint(pixel_x, pixel_y, color); + } + } + } + #endif + break; + case 24:// 24x12 字体(ascii_2412:按行存储,每行 2 字节) + #ifdef ASCII_2412 + font_data = (const uint8_t *)ascii_2412[index]; + char_width = 12; + char_height = 24; + bytesPerRow = (char_width + 7) / 8; // =2 + + for (uint8_t row = 0; row < char_height; row++) { + for (uint8_t col = 0; col < char_width; col++) { + uint16_t pixel_x = x + col; + uint16_t pixel_y = y + row; + uint8_t byte_index = col / 8; + uint8_t b = font_data[row * bytesPerRow + byte_index]; + uint8_t bit_value; + if (bit_order == MSB) { + bit_value = (b >> (7 - (col % 8))) & 0x01; + } else { + bit_value = (b >> (col % 8)) & 0x01; + } + if (bit_value) { + LCD_DrawPoint(pixel_x, pixel_y, color); + } + } + } + #endif + break; + case 32:// 32x16 字体(ascii_3216:按行存储,每行 2 字节) + #ifdef ASCII_3216 + font_data = (const uint8_t *)ascii_3216[index]; + char_width = 16; + char_height = 32; + bytesPerRow = (char_width + 7) / 8; // =2 + + for (uint8_t row = 0; row < char_height; row++) { + for (uint8_t col = 0; col < char_width; col++) { + uint16_t pixel_x = x + col; + uint16_t pixel_y = y + row; + uint8_t byte_index = col / 8; + uint8_t b = font_data[row * bytesPerRow + byte_index]; + uint8_t bit_value; + if (bit_order == MSB) { + bit_value = (b >> (7 - (col % 8))) & 0x01; + } else { + bit_value = (b >> (col % 8)) & 0x01; + } + if (bit_value) { + LCD_DrawPoint(pixel_x, pixel_y, color); + } + } + } + #endif + break; + default: + return DEVICE_ERR; + } + + return DEVICE_OK; +} + +/** + * 绘制字符串 + * + * @param x 字符串起始X坐标 + * @param y 字符串起始Y坐标 + * @param str 要绘制的字符串 + * @param color 字符颜色(RGB565格式) + * @param font_size 字体大小(12或32) + * @param bit_order 位顺序(LSB或MSB) + * + * @note 此函数逐字符绘制字符串,支持换行。 + */ +int8_t LCD_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order) { + uint16_t cursor_x = x; + uint16_t cursor_y = y; + uint8_t char_width, char_height, x_spacing, y_spacing; + + switch (font_size) { + case 12: + #ifdef ASCII_1206 + char_width = 6; + char_height = 12; + x_spacing = 7; // 推荐间距:宽度+1 + y_spacing = 13; // 行间距:高度+1 + #endif + break; + case 16: + #ifdef ASCII_1608 + char_width = 8; + char_height = 16; + x_spacing = 9; + y_spacing = 17; + #endif + break; + case 24: + #ifdef ASCII_2412 + char_width = 12; + char_height = 24; + x_spacing = 13; + y_spacing = 25; + #endif + break; + case 32: + #ifdef ASCII_3216 + char_width = 16; + char_height = 32; + x_spacing = 17; + y_spacing = 33; + #endif + break; + default: + return DEVICE_ERR;// 不支持的字体大小 + } + + while (*str) { + if (*str == '\n') { + cursor_x = x; + cursor_y += y_spacing; + str++; + continue; + } + + LCD_DrawChar(cursor_x, cursor_y, *str, color, font_size, bit_order); + cursor_x += x_spacing; + str++; + } +} + +/** + * 绘制整数 + * + * @param x 起始X坐标 + * @param y 起始Y坐标 + * @param num 要绘制的整数 + * @param color 数字颜色(RGB565格式) + * @param font_size 字体大小(12或32) + * @param bit_order 位顺序(LSB或MSB) + * + * @note 此函数将整数转换为字符串后调用LCD_DrawString绘制。 + */ +int8_t LCD_DrawInteger(uint16_t x, uint16_t y, int32_t num, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order) { + char buffer[12]; // 缓冲区,足够存储32位整数的字符串表示 + snprintf(buffer, sizeof(buffer), "%d", num); // 将整数转换为字符串 + LCD_DrawString(x, y, buffer, color, font_size, bit_order); // 调用字符串绘制函数 + return DEVICE_OK; +} + +/** + * 绘制浮点数 + * + * @param x 起始X坐标 + * @param y 起始Y坐标 + * @param num 要绘制的浮点数 + * @param decimal_places 小数点后保留的位数 + * @param color 数字颜色(RGB565格式) + * @param font_size 字体大小(12或32) + * @param bit_order 位顺序(LSB或MSB) + * + * @note 此函数将浮点数转换为字符串后调用LCD_DrawString绘制。 + */ +int8_t LCD_DrawFloat(uint16_t x, uint16_t y, float num, uint8_t decimal_places, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order) { + char buffer[20]; // 缓冲区,足够存储浮点数的字符串表示 + snprintf(buffer, sizeof(buffer), "%.*f", decimal_places, num); // 将浮点数转换为字符串 + LCD_DrawString(x, y, buffer, color, font_size, bit_order); // 调用字符串绘制函数 + return DEVICE_OK; +} + +/** + * 绘制位图 + * + * @param bitmap 位图数据指针 + * @param x 位图起始X坐标 + * @param y 位图起始Y坐标 + * @param width 位图宽度(像素) + * @param height 位图高度(像素) + * @param color 绘制颜色(RGB565格式) + * + * @note 此函数逐像素绘制位图,适用于简单的位图显示。如果需要更高性能,可以优化为按行发送。 + */ +int8_t LCD_DrawBitmap(const uint8_t *bitmap, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, LCD_BitOrder_t bit_order) { + if (bitmap == NULL) return DEVICE_ERR_NULL; // 检查位图指针是否为空 + uint16_t bytesPerRow = (width + 7) / 8; // 每行的字节数 + + for (uint16_t row = 0; row < height; row++) { // 遍历每一行 + const uint8_t *row_ptr = bitmap + (uint32_t)row * bytesPerRow; // 当前行的起始指针 + for (uint16_t byte_i = 0; byte_i < bytesPerRow; byte_i++) { // 遍历每一行的字节 + uint8_t b = row_ptr[byte_i]; // 当前字节 + for (uint8_t bit = 0; bit < 8; bit++) { // 遍历每个字节的位 + uint16_t col = (uint16_t)byte_i * 8 + bit; // 计算当前像素的列坐标 + if (col >= width) break; // 如果超出宽度范围,跳过 + + uint8_t pixel_on = 0; + if (bit_order == MSB) { + // MSB-first:字节内最高位(0x80)对应当前字节块的最左像素 + pixel_on = (b & (0x80 >> bit)) ? 1 : 0; + } else { + // LSB-first:字节内最低位(0x01)对应当前字节块的最左像素 + pixel_on = (b & (1U << bit)) ? 1 : 0; + } + + if (pixel_on) { // 如果当前位为1,则绘制像素 + LCD_DrawPoint((uint16_t)(x + col), (uint16_t)(y + row), color); + } + } + } + } + return DEVICE_OK; +} \ No newline at end of file diff --git a/assets/User_code/device/lcd_driver/lcd.h b/assets/User_code/device/lcd_driver/lcd.h new file mode 100644 index 0000000..930fe66 --- /dev/null +++ b/assets/User_code/device/lcd_driver/lcd.h @@ -0,0 +1,156 @@ +#ifndef __LCD_H +#define __LCD_H + +/* Includes ----------------------------------------------------------------- */ +#include "device/device.h" +#include "bsp/spi.h" +#include "bsp/gpio.h" + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* USER DEFINE BEGIN */ + +/* USER DEFINE END */ + +/* Exported constants ------------------------------------------------------- */ +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ +/****************************************************************************** + 屏幕属性 +******************************************************************************/ +/* USER ATTRIBUTE BEGIN */ +#define LCD_WIDTH 135 +#define LCD_HEIGHT 240 + +#define X_OFFSET 52 +#define Y_OFFSET 40 +/* USER ATTRIBUTE END */ +/****************************************************************************** + 控制引脚 +******************************************************************************/ +/* USER PIN BEGIN */ +#define LCD_CS_LOW() HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET) +#define LCD_CS_HIGH() HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET) +#define LCD_DC_LOW() HAL_GPIO_WritePin(LCD_RS_GPIO_Port, LCD_RS_Pin, GPIO_PIN_RESET) +#define LCD_DC_HIGH() HAL_GPIO_WritePin(LCD_RS_GPIO_Port, LCD_RS_Pin, GPIO_PIN_SET) +#define LCD_RST_LOW() HAL_GPIO_WritePin(LCD_RES_GPIO_Port, LCD_RES_Pin, GPIO_PIN_RESET) +#define LCD_RST_HIGH() HAL_GPIO_WritePin(LCD_RES_GPIO_Port, LCD_RES_Pin, GPIO_PIN_SET) +/* USER PIN END */ +/****************************************************************************** + 常用颜色(RGB565) +******************************************************************************/ +/* USER COLOR BEGIN */ +#define ALICEBLUE 0xEFBF // 爱丽丝蓝 +#define ANTIQUEWHITE 0xF75A // 古董白 +#define AQUA 0x07FF // 水色 +#define AQUAMARINE 0x7FFA // 碧绿色 +#define AZURE 0xEFFF // 天蓝色 +#define BEIGE 0xF7BB // 米色 +#define BISQUE 0xFF18 // Bisque色 +#define BLACK 0x0000 // 黑色 +#define BLANCHEDALMOND 0xFF59 // 漂白的杏仁色 +#define BLUE 0x001F // 蓝色 +#define BROWN 0xA145 // 棕色 +#define BURLYWOOD 0xDDB0 // 木色 +#define CADETBLUE 0x64F3 // 军校蓝 +#define CHARTreuse 0x7FE0 // 鲜绿色 +#define CHOCOLATE 0xD344 // 巧克力色 +#define CORAL 0xFBEA // 珊瑚色 +#define CORNFLOWERBLUE 0x64BD // 矢车菊蓝 +#define CORNSILK 0xFFBB // 玉米丝色 +#define CRIMSON 0xD8A7 // 深红 +#define CYAN 0x07FF // 青色 +#define DARKBLUE 0x0011 // 深蓝色 +#define DARKCYAN 0x0451 // 深青色 +#define DARKGOLDENROD 0xB421 // 深金菊色 +#define DARKGRAY 0xAD55 // 深灰色 +#define DARKGREEN 0x0320 // 深绿色 +#define DARKGREY 0xAD55 // 深灰色(同DARKGRAY) +#define DARKOLIVEGREEN 0x5346 // 深橄榄绿 +#define DARKORANGE 0xFC60 // 深橙色 +#define DARKVIOLET 0x901A // 深紫罗兰色 +#define DEEPPINK 0xF8B2 // 深粉红色 +#define DEEPSKYBLUE 0x05FF // 深天蓝色 +#define DODGERBLUE 0x249F // 闪兰色 +#define FIREBRICK 0xB104 // 火砖色 +#define FUCHSIA 0xF81F // 紫红色 +#define GAINSBORO 0xDEDB // 增白 +#define GOLD 0xFEA0 // 金色 +#define GOLDENROD 0xDD24 // 金菊色 +#define GRAY 0x8410 // 灰色 +#define GREEN 0x0400 // 绿色 +#define GREENYELLOW 0xAFE6 // 绿黄色 +#define GREY 0x8410 // 灰色(同GRAY) +#define HONEYDEW 0xEFFD // 蜜色 +#define HOTPINK 0xFB56 // 热粉红色 +#define IVORY 0xFFFD // 象牙色 +#define KHAKI 0xEF31 // 卡其色 +#define LAVENDER 0xE73E // 淡紫色 +#define LIME 0x07E0 // 酸橙绿 +#define LIMEGREEN 0x3666 // 酸橙绿 +#define LINEN 0xF77C // 亚麻色 +#define MAGENTA 0xF81F // 洋红色 +#define MAROON 0x8000 // 褐红色 +#define MEDIUMAQUAMARINE 0x6675 // 中等碧绿色 +#define MEDIUMBLUE 0x0019 // 中等蓝色 +#define MEDIUMPURPLE 0x939b // 中等紫色 +#define MEDIUMSEAGREEN 0x3d8e // 中等海绿色 +#define MEDIUMSLATEBLUE 0x7b5d // 中等石板蓝 +#define MEDIUMSPRINGGREEN 0x07d3 // 中等春绿色 +#define MEDIUMTURQUOISE 0x4e99 // 中等青绿色 +#define MEDIUMVIOLETRED 0xC0B0 // 中等紫红色 +#define MIDNIGHTBLUE 0x18CE // 午夜蓝 +#define MINTCREAME 0xF7FE // 薄荷奶油色 +#define MISTYROSE 0xFF1B // 雾玫瑰色 +#define MOCCASIN 0xFF16 // 鹿皮色 +#define NAVAJOWHITE 0xFEF5 // Navajo白 +#define NAVY 0x0010 // 海军蓝 +#define OLDLACE 0xFFBC // 旧蕾丝色 +#define OLIVE 0x8400 // 橄榄色 +#define OLIVEDRAB 0x6C64 // 橄榄褐色 +#define ORANGE 0xFD20 // 橙色 +#define ORANGERED 0xFA20 // 橙红色 +#define ORCHID 0xDB9A // 兰花色 +#define PALE GOLDENROD 0xEF35 // 苍白金菊色 +#define PALEGREEN 0x97D2 // 苍白绿色 +#define MEDIUMORCHID 0xbaba // 中等紫罗兰色 +#define VIOLET 0xEC1D // 紫罗兰色 /--- *I LOVE VIOLET FOREVER!!T-T* ---/ +#define VIOLET_SOFT 0xE31F // 柔和的紫罗兰色 +/* USER COLOR END */ +/****************************************************************************** + end--常用颜色(RGB565) +******************************************************************************/ + +typedef enum { + LCD_ORIENTATION_PORTRAIT = 0, // 竖屏模式 + LCD_ORIENTATION_LANDSCAPE = 1, // 横屏模式(90°顺时针旋转) + LCD_ORIENTATION_LANDSCAPE_INVERTED = 2, // 横屏模式(90°逆时针旋转) + LCD_ORIENTATION_PORTRAIT_INVERTED = 3 // 竖屏模式(180°旋转) +} LCD_Orientation_t; + +typedef enum { + LSB=0, + MSB=1, +}LCD_BitOrder_t; + +/* Exported functions prototypes -------------------------------------------- */ +int8_t LCD_Init(LCD_Orientation_t orientation); +int8_t LCD_Clear(uint16_t color); + +int8_t LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color); +int8_t LCD_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color); +int8_t LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t color); +int8_t LCD_DrawHollowCircle(uint16_t x0,uint16_t y0,uint16_t r,uint16_t color); +int8_t LCD_DrawSolidCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color); +int8_t LCD_DrawChar(uint16_t x, uint16_t y, char ch, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order); +int8_t LCD_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order); +int8_t LCD_DrawInteger(uint16_t x, uint16_t y, int32_t num, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order); +int8_t LCD_DrawFloat(uint16_t x, uint16_t y, float num, uint8_t decimal_places, uint16_t color, uint8_t font_size, LCD_BitOrder_t bit_order); +int8_t LCD_DrawBitmap(const uint8_t *bitmap, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, LCD_BitOrder_t bit_order); + +/* USER FUNCTION BEGIN */ + +/* USER FUNCTION END */ +#endif // __LCD_H diff --git a/assets/User_code/device/lcd_driver/lcd_lib.h b/assets/User_code/device/lcd_driver/lcd_lib.h new file mode 100644 index 0000000..6d55836 --- /dev/null +++ b/assets/User_code/device/lcd_driver/lcd_lib.h @@ -0,0 +1,621 @@ +#pragma once + +#include + +// #define ASCII_1206 +#define ASCII_1608 +#define ASCII_2412 +#define ASCII_3216 +#define LOGO_M +// #define LOGO_R +// #define HUAJI + + +#ifdef ASCII_1206 +const unsigned char ascii_1206[][12]={ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ + {0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x04,0x00,0x00},/*"!",1*/ + {0x14,0x14,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/ + {0x00,0x00,0x0A,0x0A,0x1F,0x0A,0x0A,0x1F,0x0A,0x0A,0x00,0x00},/*"#",3*/ + {0x00,0x04,0x0E,0x15,0x05,0x06,0x0C,0x14,0x15,0x0E,0x04,0x00},/*"$",4*/ + {0x00,0x00,0x12,0x15,0x0D,0x15,0x2E,0x2C,0x2A,0x12,0x00,0x00},/*"%",5*/ + {0x00,0x00,0x04,0x0A,0x0A,0x36,0x15,0x15,0x29,0x16,0x00,0x00},/*"&",6*/ + {0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ + {0x10,0x08,0x08,0x04,0x04,0x04,0x04,0x04,0x08,0x08,0x10,0x00},/*"(",8*/ + {0x02,0x04,0x04,0x08,0x08,0x08,0x08,0x08,0x04,0x04,0x02,0x00},/*")",9*/ + {0x00,0x00,0x00,0x04,0x15,0x0E,0x0E,0x15,0x04,0x00,0x00,0x00},/*"*",10*/ + {0x00,0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00,0x00,0x00},/*"+",11*/ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01,0x00},/*",",12*/ + {0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00},/*"-",13*/ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00},/*".",14*/ + {0x00,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x00},/*"/",15*/ + {0x00,0x00,0x0E,0x11,0x11,0x11,0x11,0x11,0x11,0x0E,0x00,0x00},/*"0",16*/ + {0x00,0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x04,0x0E,0x00,0x00},/*"1",17*/ + {0x00,0x00,0x0E,0x11,0x11,0x08,0x04,0x02,0x01,0x1F,0x00,0x00},/*"2",18*/ + {0x00,0x00,0x0E,0x11,0x10,0x0C,0x10,0x10,0x11,0x0E,0x00,0x00},/*"3",19*/ + {0x00,0x00,0x08,0x0C,0x0C,0x0A,0x09,0x1F,0x08,0x1C,0x00,0x00},/*"4",20*/ + {0x00,0x00,0x1F,0x01,0x01,0x0F,0x11,0x10,0x11,0x0E,0x00,0x00},/*"5",21*/ + {0x00,0x00,0x0C,0x12,0x01,0x0D,0x13,0x11,0x11,0x0E,0x00,0x00},/*"6",22*/ + {0x00,0x00,0x1E,0x10,0x08,0x08,0x04,0x04,0x04,0x04,0x00,0x00},/*"7",23*/ + {0x00,0x00,0x0E,0x11,0x11,0x0E,0x11,0x11,0x11,0x0E,0x00,0x00},/*"8",24*/ + {0x00,0x00,0x0E,0x11,0x11,0x19,0x16,0x10,0x09,0x06,0x00,0x00},/*"9",25*/ + {0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x04,0x00,0x00},/*":",26*/ + {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x04,0x00},/*";",27*/ + {0x00,0x00,0x10,0x08,0x04,0x02,0x02,0x04,0x08,0x10,0x00,0x00},/*"<",28*/ + {0x00,0x00,0x00,0x00,0x3F,0x00,0x3F,0x00,0x00,0x00,0x00,0x00},/*"=",29*/ + {0x00,0x00,0x02,0x04,0x08,0x10,0x10,0x08,0x04,0x02,0x00,0x00},/*">",30*/ + {0x00,0x00,0x0E,0x11,0x11,0x08,0x04,0x04,0x00,0x04,0x00,0x00},/*"?",31*/ + {0x00,0x00,0x1C,0x22,0x29,0x2D,0x2D,0x1D,0x22,0x1C,0x00,0x00},/*"@",32*/ + {0x00,0x00,0x04,0x04,0x0C,0x0A,0x0A,0x1E,0x12,0x33,0x00,0x00},/*"A",33*/ + {0x00,0x00,0x0F,0x12,0x12,0x0E,0x12,0x12,0x12,0x0F,0x00,0x00},/*"B",34*/ + {0x00,0x00,0x1E,0x11,0x01,0x01,0x01,0x01,0x11,0x0E,0x00,0x00},/*"C",35*/ + {0x00,0x00,0x0F,0x12,0x12,0x12,0x12,0x12,0x12,0x0F,0x00,0x00},/*"D",36*/ + {0x00,0x00,0x1F,0x12,0x0A,0x0E,0x0A,0x02,0x12,0x1F,0x00,0x00},/*"E",37*/ + {0x00,0x00,0x1F,0x12,0x0A,0x0E,0x0A,0x02,0x02,0x07,0x00,0x00},/*"F",38*/ + {0x00,0x00,0x1C,0x12,0x01,0x01,0x39,0x11,0x12,0x0C,0x00,0x00},/*"G",39*/ + {0x00,0x00,0x33,0x12,0x12,0x1E,0x12,0x12,0x12,0x33,0x00,0x00},/*"H",40*/ + {0x00,0x00,0x1F,0x04,0x04,0x04,0x04,0x04,0x04,0x1F,0x00,0x00},/*"I",41*/ + {0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x09,0x07},/*"J",42*/ + {0x00,0x00,0x37,0x12,0x0A,0x06,0x0A,0x12,0x12,0x37,0x00,0x00},/*"K",43*/ + {0x00,0x00,0x07,0x02,0x02,0x02,0x02,0x02,0x22,0x3F,0x00,0x00},/*"L",44*/ + {0x00,0x00,0x3B,0x1B,0x1B,0x1B,0x15,0x15,0x15,0x35,0x00,0x00},/*"M",45*/ + {0x00,0x00,0x3B,0x12,0x16,0x16,0x1A,0x1A,0x12,0x17,0x00,0x00},/*"N",46*/ + {0x00,0x00,0x0E,0x11,0x11,0x11,0x11,0x11,0x11,0x0E,0x00,0x00},/*"O",47*/ + {0x00,0x00,0x0F,0x12,0x12,0x0E,0x02,0x02,0x02,0x07,0x00,0x00},/*"P",48*/ + {0x00,0x00,0x0E,0x11,0x11,0x11,0x11,0x17,0x19,0x0E,0x18,0x00},/*"Q",49*/ + {0x00,0x00,0x0F,0x12,0x12,0x0E,0x0A,0x12,0x12,0x37,0x00,0x00},/*"R",50*/ + {0x00,0x00,0x1E,0x11,0x01,0x06,0x08,0x10,0x11,0x0F,0x00,0x00},/*"S",51*/ + {0x00,0x00,0x1F,0x15,0x04,0x04,0x04,0x04,0x04,0x0E,0x00,0x00},/*"T",52*/ + {0x00,0x00,0x33,0x12,0x12,0x12,0x12,0x12,0x12,0x0C,0x00,0x00},/*"U",53*/ + {0x00,0x00,0x33,0x12,0x12,0x0A,0x0A,0x0C,0x04,0x04,0x00,0x00},/*"V",54*/ + {0x00,0x00,0x15,0x15,0x15,0x15,0x0E,0x0A,0x0A,0x0A,0x00,0x00},/*"W",55*/ + {0x00,0x00,0x1B,0x0A,0x0A,0x04,0x04,0x0A,0x0A,0x1B,0x00,0x00},/*"X",56*/ + {0x00,0x00,0x1B,0x0A,0x0A,0x0A,0x04,0x04,0x04,0x0E,0x00,0x00},/*"Y",57*/ + {0x00,0x00,0x1F,0x09,0x08,0x04,0x04,0x02,0x12,0x1F,0x00,0x00},/*"Z",58*/ + {0x1C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x1C,0x00},/*"[",59*/ + {0x00,0x02,0x02,0x04,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x00},/*"\",60*/ + {0x0E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x0E,0x00},/*"]",61*/ + {0x04,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F},/*"_",63*/ + {0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ + {0x00,0x00,0x00,0x00,0x00,0x0C,0x12,0x1C,0x12,0x3C,0x00,0x00},/*"a",65*/ + {0x00,0x03,0x02,0x02,0x02,0x0E,0x12,0x12,0x12,0x0E,0x00,0x00},/*"b",66*/ + {0x00,0x00,0x00,0x00,0x00,0x1C,0x12,0x02,0x12,0x0C,0x00,0x00},/*"c",67*/ + {0x00,0x18,0x10,0x10,0x10,0x1C,0x12,0x12,0x12,0x3C,0x00,0x00},/*"d",68*/ + {0x00,0x00,0x00,0x00,0x00,0x0C,0x12,0x1E,0x02,0x1C,0x00,0x00},/*"e",69*/ + {0x00,0x18,0x24,0x04,0x04,0x1E,0x04,0x04,0x04,0x1E,0x00,0x00},/*"f",70*/ + {0x00,0x00,0x00,0x00,0x00,0x3C,0x12,0x0C,0x02,0x1C,0x22,0x1C},/*"g",71*/ + {0x00,0x03,0x02,0x02,0x02,0x0E,0x12,0x12,0x12,0x37,0x00,0x00},/*"h",72*/ + {0x00,0x04,0x04,0x00,0x00,0x06,0x04,0x04,0x04,0x0E,0x00,0x00},/*"i",73*/ + {0x00,0x08,0x08,0x00,0x00,0x0C,0x08,0x08,0x08,0x08,0x08,0x07},/*"j",74*/ + {0x00,0x03,0x02,0x02,0x02,0x1A,0x0A,0x06,0x0A,0x13,0x00,0x00},/*"k",75*/ + {0x00,0x07,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x1F,0x00,0x00},/*"l",76*/ + {0x00,0x00,0x00,0x00,0x00,0x0F,0x15,0x15,0x15,0x15,0x00,0x00},/*"m",77*/ + {0x00,0x00,0x00,0x00,0x00,0x0F,0x12,0x12,0x12,0x37,0x00,0x00},/*"n",78*/ + {0x00,0x00,0x00,0x00,0x00,0x0C,0x12,0x12,0x12,0x0C,0x00,0x00},/*"o",79*/ + {0x00,0x00,0x00,0x00,0x00,0x0F,0x12,0x12,0x12,0x0E,0x02,0x07},/*"p",80*/ + {0x00,0x00,0x00,0x00,0x00,0x1C,0x12,0x12,0x12,0x1C,0x10,0x38},/*"q",81*/ + {0x00,0x00,0x00,0x00,0x00,0x1B,0x06,0x02,0x02,0x07,0x00,0x00},/*"r",82*/ + {0x00,0x00,0x00,0x00,0x00,0x1E,0x02,0x0C,0x10,0x1E,0x00,0x00},/*"s",83*/ + {0x00,0x00,0x00,0x04,0x04,0x1E,0x04,0x04,0x04,0x1C,0x00,0x00},/*"t",84*/ + {0x00,0x00,0x00,0x00,0x00,0x1B,0x12,0x12,0x12,0x3C,0x00,0x00},/*"u",85*/ + {0x00,0x00,0x00,0x00,0x00,0x1B,0x0A,0x0A,0x04,0x04,0x00,0x00},/*"v",86*/ + {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x0E,0x0A,0x0A,0x00,0x00},/*"w",87*/ + {0x00,0x00,0x00,0x00,0x00,0x1B,0x0A,0x04,0x0A,0x1B,0x00,0x00},/*"x",88*/ + {0x00,0x00,0x00,0x00,0x00,0x33,0x12,0x12,0x0C,0x08,0x04,0x03},/*"y",89*/ + {0x00,0x00,0x00,0x00,0x00,0x1E,0x08,0x04,0x04,0x1E,0x00,0x00},/*"z",90*/ + {0x18,0x08,0x08,0x08,0x08,0x0C,0x08,0x08,0x08,0x08,0x18,0x00},/*"{",91*/ + {0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08},/*"|",92*/ + {0x06,0x04,0x04,0x04,0x04,0x08,0x04,0x04,0x04,0x04,0x06,0x00},/*"}",93*/ + {0x16,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/ +}; +#endif // ASCII_1206 + +#ifdef ASCII_1608 +const unsigned char ascii_1608[][16]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ +{0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x18,0x18,0x00,0x00},/*"!",1*/ +{0x00,0x48,0x6C,0x24,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/ +{0x00,0x00,0x00,0x24,0x24,0x24,0x7F,0x12,0x12,0x12,0x7F,0x12,0x12,0x12,0x00,0x00},/*"#",3*/ +{0x00,0x00,0x08,0x1C,0x2A,0x2A,0x0A,0x0C,0x18,0x28,0x28,0x2A,0x2A,0x1C,0x08,0x08},/*"$",4*/ +{0x00,0x00,0x00,0x22,0x25,0x15,0x15,0x15,0x2A,0x58,0x54,0x54,0x54,0x22,0x00,0x00},/*"%",5*/ +{0x00,0x00,0x00,0x0C,0x12,0x12,0x12,0x0A,0x76,0x25,0x29,0x11,0x91,0x6E,0x00,0x00},/*"&",6*/ +{0x00,0x06,0x06,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ +{0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x40,0x00},/*"(",8*/ +{0x00,0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00},/*")",9*/ +{0x00,0x00,0x00,0x00,0x08,0x08,0x6B,0x1C,0x1C,0x6B,0x08,0x08,0x00,0x00,0x00,0x00},/*"*",10*/ +{0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x7F,0x08,0x08,0x08,0x08,0x00,0x00,0x00},/*"+",11*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x04,0x03},/*",",12*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"-",13*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x00,0x00},/*".",14*/ +{0x00,0x00,0x80,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x02,0x02,0x00},/*"/",15*/ +{0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x00,0x08,0x0E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},/*"1",17*/ +{0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x20,0x20,0x10,0x08,0x04,0x42,0x7E,0x00,0x00},/*"2",18*/ +{0x00,0x00,0x00,0x3C,0x42,0x42,0x20,0x18,0x20,0x40,0x40,0x42,0x22,0x1C,0x00,0x00},/*"3",19*/ +{0x00,0x00,0x00,0x20,0x30,0x28,0x24,0x24,0x22,0x22,0x7E,0x20,0x20,0x78,0x00,0x00},/*"4",20*/ +{0x00,0x00,0x00,0x7E,0x02,0x02,0x02,0x1A,0x26,0x40,0x40,0x42,0x22,0x1C,0x00,0x00},/*"5",21*/ +{0x00,0x00,0x00,0x38,0x24,0x02,0x02,0x1A,0x26,0x42,0x42,0x42,0x24,0x18,0x00,0x00},/*"6",22*/ +{0x00,0x00,0x00,0x7E,0x22,0x22,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00},/*"7",23*/ +{0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00},/*"8",24*/ +{0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x64,0x58,0x40,0x40,0x24,0x1C,0x00,0x00},/*"9",25*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00},/*":",26*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x04},/*";",27*/ +{0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00},/*"<",28*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00},/*">",30*/ +{0x00,0x00,0x00,0x3C,0x42,0x42,0x46,0x40,0x20,0x10,0x10,0x00,0x18,0x18,0x00,0x00},/*"?",31*/ +{0x00,0x00,0x00,0x1C,0x22,0x5A,0x55,0x55,0x55,0x55,0x2D,0x42,0x22,0x1C,0x00,0x00},/*"@",32*/ +{0x00,0x00,0x00,0x08,0x08,0x18,0x14,0x14,0x24,0x3C,0x22,0x42,0x42,0xE7,0x00,0x00},/*"A",33*/ +{0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x1E,0x22,0x42,0x42,0x42,0x22,0x1F,0x00,0x00},/*"B",34*/ +{0x00,0x00,0x00,0x7C,0x42,0x42,0x01,0x01,0x01,0x01,0x01,0x42,0x22,0x1C,0x00,0x00},/*"C",35*/ +{0x00,0x00,0x00,0x1F,0x22,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x22,0x1F,0x00,0x00},/*"D",36*/ +{0x00,0x00,0x00,0x3F,0x42,0x12,0x12,0x1E,0x12,0x12,0x02,0x42,0x42,0x3F,0x00,0x00},/*"E",37*/ +{0x00,0x00,0x00,0x3F,0x42,0x12,0x12,0x1E,0x12,0x12,0x02,0x02,0x02,0x07,0x00,0x00},/*"F",38*/ +{0x00,0x00,0x00,0x3C,0x22,0x22,0x01,0x01,0x01,0x71,0x21,0x22,0x22,0x1C,0x00,0x00},/*"G",39*/ +{0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0xE7,0x00,0x00},/*"H",40*/ +{0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},/*"I",41*/ +{0x00,0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x11,0x0F},/*"J",42*/ +{0x00,0x00,0x00,0x77,0x22,0x12,0x0A,0x0E,0x0A,0x12,0x12,0x22,0x22,0x77,0x00,0x00},/*"K",43*/ +{0x00,0x00,0x00,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x42,0x7F,0x00,0x00},/*"L",44*/ +{0x00,0x00,0x00,0x77,0x36,0x36,0x36,0x36,0x2A,0x2A,0x2A,0x2A,0x2A,0x6B,0x00,0x00},/*"M",45*/ +{0x00,0x00,0x00,0xE3,0x46,0x46,0x4A,0x4A,0x52,0x52,0x52,0x62,0x62,0x47,0x00,0x00},/*"N",46*/ +{0x00,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x22,0x1C,0x00,0x00},/*"O",47*/ +{0x00,0x00,0x00,0x3F,0x42,0x42,0x42,0x42,0x3E,0x02,0x02,0x02,0x02,0x07,0x00,0x00},/*"P",48*/ +{0x00,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x41,0x4D,0x53,0x32,0x1C,0x60,0x00},/*"Q",49*/ +{0x00,0x00,0x00,0x3F,0x42,0x42,0x42,0x3E,0x12,0x12,0x22,0x22,0x42,0xC7,0x00,0x00},/*"R",50*/ +{0x00,0x00,0x00,0x7C,0x42,0x42,0x02,0x04,0x18,0x20,0x40,0x42,0x42,0x3E,0x00,0x00},/*"S",51*/ +{0x00,0x00,0x00,0x7F,0x49,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00},/*"T",52*/ +{0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00},/*"U",53*/ +{0x00,0x00,0x00,0xE7,0x42,0x42,0x22,0x24,0x24,0x14,0x14,0x18,0x08,0x08,0x00,0x00},/*"V",54*/ +{0x00,0x00,0x00,0x6B,0x49,0x49,0x49,0x49,0x55,0x55,0x36,0x22,0x22,0x22,0x00,0x00},/*"W",55*/ +{0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,0x18,0x18,0x24,0x24,0x42,0xE7,0x00,0x00},/*"X",56*/ +{0x00,0x00,0x00,0x77,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00},/*"Y",57*/ +{0x00,0x00,0x00,0x7E,0x21,0x20,0x10,0x10,0x08,0x04,0x04,0x42,0x42,0x3F,0x00,0x00},/*"Z",58*/ +{0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78,0x00},/*"[",59*/ +{0x00,0x00,0x02,0x02,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x20,0x20,0x20,0x40,0x40},/*"\",60*/ +{0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1E,0x00},/*"]",61*/ +{0x00,0x38,0x44,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,0xFF},/*"_",63*/ +{0x00,0x06,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x78,0x44,0x42,0x42,0xFC,0x00,0x00},/*"a",65*/ +{0x00,0x00,0x00,0x03,0x02,0x02,0x02,0x1A,0x26,0x42,0x42,0x42,0x26,0x1A,0x00,0x00},/*"b",66*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x00,0x60,0x40,0x40,0x40,0x78,0x44,0x42,0x42,0x42,0x64,0xD8,0x00,0x00},/*"d",68*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x7E,0x02,0x02,0x42,0x3C,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x00,0xF0,0x88,0x08,0x08,0x7E,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},/*"f",70*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x22,0x22,0x1C,0x02,0x3C,0x42,0x42,0x3C},/*"g",71*/ +{0x00,0x00,0x00,0x03,0x02,0x02,0x02,0x3A,0x46,0x42,0x42,0x42,0x42,0xE7,0x00,0x00},/*"h",72*/ +{0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x0E,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},/*"i",73*/ +{0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x22,0x1E},/*"j",74*/ +{0x00,0x00,0x00,0x03,0x02,0x02,0x02,0x72,0x12,0x0A,0x16,0x12,0x22,0x77,0x00,0x00},/*"k",75*/ +{0x00,0x00,0x00,0x0E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},/*"l",76*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x92,0x92,0x92,0x92,0x92,0xB7,0x00,0x00},/*"m",77*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0x46,0x42,0x42,0x42,0x42,0xE7,0x00,0x00},/*"n",78*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00},/*"o",79*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1B,0x26,0x42,0x42,0x42,0x22,0x1E,0x02,0x07},/*"p",80*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x44,0x42,0x42,0x42,0x44,0x78,0x40,0xE0},/*"q",81*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x4C,0x04,0x04,0x04,0x04,0x1F,0x00,0x00},/*"r",82*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x42,0x02,0x3C,0x40,0x42,0x3E,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x08,0x08,0x08,0x30,0x00,0x00},/*"t",84*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x42,0x42,0x42,0x42,0x62,0xDC,0x00,0x00},/*"u",85*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x14,0x08,0x08,0x00,0x00},/*"v",86*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEB,0x49,0x49,0x55,0x55,0x22,0x22,0x00,0x00},/*"w",87*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x24,0x18,0x18,0x18,0x24,0x6E,0x00,0x00},/*"x",88*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x14,0x18,0x08,0x08,0x07},/*"y",89*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x22,0x10,0x08,0x08,0x44,0x7E,0x00,0x00},/*"z",90*/ +{0x00,0xC0,0x20,0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0xC0,0x00},/*"{",91*/ +{0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10},/*"|",92*/ +{0x00,0x06,0x08,0x08,0x08,0x08,0x08,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x06,0x00},/*"}",93*/ +{0x0C,0x32,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/ +}; +#endif + +#ifdef ASCII_2412 +const unsigned char ascii_2412[][48]={ +{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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ +{0x00,0x00,0x00,0x00,0x60,0x06,0x60,0x06,0x30,0x03,0x98,0x01,0x88,0x00,0x44,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,0x00},/*""",2*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x02,0x10,0x02,0x10,0x02,0x10,0x02,0xFE,0x07,0xFE,0x07,0x08,0x02,0x08,0x01,0x08,0x01,0x08,0x01,0x08,0x01,0xFE,0x07,0xFE,0x07,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"#",3*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0xF0,0x01,0x58,0x03,0x4C,0x03,0xCC,0x03,0x4C,0x00,0x58,0x00,0x70,0x00,0xE0,0x00,0xC0,0x01,0xC0,0x01,0x40,0x03,0x4C,0x03,0x5C,0x03,0x4C,0x03,0x48,0x01,0xF0,0x00,0x40,0x00,0x40,0x00,0x00,0x00},/*"$",4*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x01,0x0A,0x01,0x91,0x00,0x91,0x00,0x91,0x00,0x51,0x00,0x51,0x00,0x3A,0x00,0xAE,0x03,0xA0,0x02,0x50,0x04,0x50,0x04,0x48,0x04,0x48,0x04,0x48,0x04,0x84,0x02,0x84,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"%",5*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x6C,0x00,0x6C,0x00,0x6C,0x00,0x6C,0x00,0x6C,0x00,0x2C,0x00,0x98,0x07,0x1C,0x01,0x1A,0x01,0x33,0x01,0x33,0x01,0x63,0x01,0xE3,0x00,0xC3,0x08,0xC6,0x09,0x3C,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"&",6*/ +{0x00,0x00,0x00,0x00,0x0C,0x00,0x1C,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x04,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,0x00},/*"'",7*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x80,0x00,0x80,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x00},/*"(",8*/ +{0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x10,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,0x10,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0x00,0x00},/*")",9*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0xC0,0x00,0x40,0x00,0x46,0x0C,0x4E,0x0F,0xD0,0x01,0xF0,0x01,0x5E,0x0F,0x46,0x0C,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"*",10*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0xFE,0x0F,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x1C,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x04,0x00},/*",",12*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ +{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x06,0x00,0x02,0x00,0x03,0x00,0x01,0x00,0x01,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x60,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x06,0x00,0x02,0x00,0x00,0x00},/*"/",15*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x98,0x01,0x0C,0x03,0x0C,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x03,0x0C,0x03,0x98,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x7C,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x84,0x01,0x02,0x03,0x06,0x03,0x06,0x03,0x00,0x03,0x00,0x01,0x80,0x01,0xC0,0x00,0x60,0x00,0x20,0x00,0x10,0x00,0x08,0x02,0x04,0x02,0x06,0x02,0xFE,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0xC6,0x00,0x86,0x01,0x86,0x01,0x80,0x01,0x80,0x01,0xC0,0x00,0x70,0x00,0x80,0x01,0x00,0x01,0x00,0x03,0x00,0x03,0x06,0x03,0x06,0x03,0x86,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x80,0x01,0xC0,0x01,0xA0,0x01,0xA0,0x01,0x90,0x01,0x88,0x01,0x88,0x01,0x84,0x01,0x82,0x01,0xFE,0x0F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xE0,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"4",20*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x03,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0xF4,0x00,0x8C,0x01,0x04,0x03,0x00,0x03,0x00,0x03,0x06,0x03,0x06,0x03,0x82,0x01,0x84,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x18,0x03,0x0C,0x03,0x0C,0x00,0x04,0x00,0x06,0x00,0xE6,0x01,0x16,0x03,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x04,0x06,0x0C,0x02,0x18,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"6",22*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x07,0x0C,0x06,0x04,0x02,0x04,0x01,0x00,0x01,0x00,0x01,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"7",23*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x01,0x0C,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x02,0x1C,0x03,0xF0,0x00,0xC8,0x01,0x0C,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x03,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"8",24*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x0C,0x01,0x0C,0x03,0x06,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x8C,0x06,0x78,0x06,0x00,0x06,0x00,0x03,0x00,0x03,0x0C,0x01,0x8C,0x01,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"9",25*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0xE0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0xE0,0x00,0xE0,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,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x40,0x00,0x20,0x00,0x20,0x00},/*";",27*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x80,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},/*"<",28*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x80,0x00,0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*">",30*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x18,0x06,0x04,0x0C,0x04,0x0C,0x0C,0x0C,0x0C,0x0C,0x00,0x07,0x80,0x01,0x40,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0xE0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"?",31*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x18,0x03,0x0C,0x02,0xCC,0x05,0x64,0x05,0x66,0x05,0xA6,0x05,0xB6,0x04,0xB6,0x04,0xB6,0x04,0xB6,0x04,0xB6,0x02,0xE4,0x01,0x0C,0x04,0x0C,0x02,0x18,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"@",32*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x50,0x00,0xD0,0x00,0x90,0x00,0x90,0x00,0x88,0x00,0x88,0x01,0x08,0x01,0xF8,0x01,0x04,0x03,0x04,0x03,0x04,0x02,0x02,0x02,0x02,0x06,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00},/*"A",33*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x8C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x8C,0x01,0xFC,0x00,0x0C,0x03,0x0C,0x02,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x03,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"B",34*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x18,0x03,0x0C,0x06,0x0C,0x04,0x04,0x04,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x04,0x0C,0x04,0x0C,0x02,0x18,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"C",35*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x8C,0x01,0x0C,0x03,0x0C,0x03,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x03,0x0C,0x03,0x8C,0x01,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"D",36*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0x06,0x03,0x06,0x04,0x06,0x04,0x06,0x00,0x86,0x00,0x86,0x00,0xFE,0x00,0x86,0x00,0x86,0x00,0x86,0x00,0x06,0x00,0x06,0x04,0x06,0x04,0x06,0x02,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"E",37*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0x06,0x03,0x06,0x04,0x06,0x04,0x06,0x00,0x86,0x00,0x86,0x00,0xFE,0x00,0x86,0x00,0x86,0x00,0x86,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"F",38*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x18,0x01,0x0C,0x02,0x0C,0x02,0x04,0x02,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0xC6,0x0F,0x06,0x03,0x06,0x03,0x0C,0x03,0x0C,0x03,0x18,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"G",39*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0xFE,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00},/*"H",40*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x03,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x07,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC6,0x00,0x66,0x00,0x3C,0x00},/*"J",42*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCF,0x03,0x86,0x01,0xC6,0x00,0x46,0x00,0x26,0x00,0x16,0x00,0x36,0x00,0x2E,0x00,0x6E,0x00,0x46,0x00,0xC6,0x00,0x86,0x00,0x86,0x01,0x06,0x01,0x06,0x03,0x8F,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"K",43*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x04,0x06,0x04,0x06,0x02,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"L",44*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x86,0x03,0x86,0x03,0x8E,0x03,0x8E,0x03,0x4E,0x03,0x4E,0x03,0x4A,0x03,0x5A,0x03,0x5A,0x03,0x3A,0x03,0x32,0x03,0x32,0x03,0x32,0x03,0x12,0x03,0x87,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"M",45*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0x0F,0x0C,0x02,0x1C,0x02,0x1C,0x02,0x34,0x02,0x34,0x02,0x64,0x02,0x64,0x02,0x44,0x02,0xC4,0x02,0x84,0x02,0x84,0x03,0x84,0x03,0x04,0x03,0x04,0x03,0x1F,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"N",46*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x98,0x01,0x0C,0x03,0x0C,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x02,0x0C,0x03,0x98,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"O",47*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x06,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x86,0x03,0xFE,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"P",48*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x98,0x01,0x0C,0x03,0x0C,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x76,0x06,0x4C,0x02,0xCC,0x03,0x98,0x01,0xF0,0x00,0x80,0x07,0x00,0x03,0x00,0x00},/*"Q",49*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x01,0x06,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x03,0xFE,0x00,0x46,0x00,0xC6,0x00,0x86,0x00,0x86,0x01,0x06,0x03,0x06,0x03,0x06,0x06,0x0F,0x0E,0x00,0x00,0x00,0x00,0x00,0x00},/*"R",50*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x02,0x0C,0x03,0x06,0x02,0x06,0x02,0x06,0x00,0x0E,0x00,0x3C,0x00,0xF8,0x00,0xE0,0x03,0x80,0x03,0x00,0x07,0x02,0x06,0x02,0x06,0x06,0x06,0x0C,0x03,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"S",51*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x07,0x62,0x04,0x61,0x08,0x61,0x08,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xF8,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"T",52*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x07,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x0C,0x02,0x18,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"U",53*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x07,0x06,0x02,0x04,0x01,0x04,0x01,0x0C,0x01,0x0C,0x01,0x88,0x00,0x88,0x00,0x98,0x00,0x98,0x00,0x50,0x00,0x50,0x00,0x70,0x00,0x30,0x00,0x20,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"V",54*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF7,0x0E,0x62,0x04,0x42,0x04,0x46,0x04,0x46,0x04,0x64,0x02,0x64,0x02,0xE4,0x02,0xE4,0x02,0x9C,0x02,0x9C,0x01,0x98,0x01,0x98,0x01,0x88,0x01,0x88,0x00,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"W",55*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9E,0x07,0x0C,0x01,0x08,0x01,0x18,0x01,0x90,0x00,0xB0,0x00,0x60,0x00,0x20,0x00,0x60,0x00,0x60,0x00,0xD0,0x00,0x90,0x00,0x88,0x01,0x08,0x01,0x04,0x03,0x8E,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"X",56*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x06,0x04,0x04,0x02,0x0C,0x02,0x08,0x01,0x18,0x01,0xB8,0x00,0xB0,0x00,0x70,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xF8,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"Y",57*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x07,0x0C,0x02,0x06,0x03,0x02,0x01,0x80,0x01,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x10,0x00,0x18,0x00,0x08,0x04,0x0C,0x04,0x04,0x02,0xFE,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"Z",58*/ +{0x00,0x00,0x00,0x00,0xE0,0x03,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,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0xE0,0x03,0x00,0x00},/*"[",59*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0xC0,0x00,0x80,0x00,0x80,0x00,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x04},/*"\",60*/ +{0x00,0x00,0x00,0x00,0x7C,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x7C,0x00,0x00,0x00},/*"]",61*/ +{0x00,0x00,0x60,0x00,0x90,0x00,0x08,0x01,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F},/*"_",63*/ +{0x00,0x00,0x00,0x00,0x18,0x00,0x60,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x01,0x0C,0x03,0x0C,0x03,0x00,0x03,0xE0,0x03,0x1C,0x03,0x0E,0x03,0x06,0x03,0x06,0x03,0x8E,0x0B,0x7C,0x0E,0x00,0x00,0x00,0x00,0x00,0x00},/*"a",65*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0xCC,0x01,0x3C,0x03,0x1C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x02,0x1C,0x03,0xE4,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"b",66*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x8C,0x01,0x8C,0x01,0x86,0x01,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x02,0x0C,0x02,0x0C,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xC0,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x78,0x03,0x8C,0x03,0x0C,0x03,0x06,0x03,0x06,0x03,0x06,0x03,0x06,0x03,0x06,0x03,0x04,0x03,0x8C,0x07,0x78,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"d",68*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x18,0x03,0x08,0x02,0x0C,0x06,0x0C,0x06,0xFC,0x07,0x0C,0x00,0x0C,0x00,0x18,0x04,0x18,0x02,0xE0,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x03,0x60,0x06,0x30,0x06,0x30,0x00,0x30,0x00,0xFE,0x01,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"f",70*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0xD8,0x06,0x8C,0x01,0x8C,0x01,0x8C,0x01,0x98,0x01,0xF8,0x00,0x0C,0x00,0xFC,0x00,0xCC,0x03,0x06,0x03,0x06,0x03,0x8E,0x03,0xF8,0x00},/*"g",71*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0xEC,0x01,0x1C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x9E,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"h",72*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x7C,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"i",73*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0xC0,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0xF0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xCC,0x00,0x7C,0x00},/*"j",74*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x8C,0x03,0x8C,0x00,0x8C,0x00,0x4C,0x00,0x6C,0x00,0x5C,0x00,0x8C,0x00,0x8C,0x01,0x0C,0x01,0x0C,0x03,0x9E,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"k",75*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x7C,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"l",76*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x07,0xEE,0x06,0x66,0x06,0x66,0x06,0x66,0x06,0x66,0x06,0x66,0x06,0x66,0x06,0x66,0x06,0x66,0x06,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00},/*"m",77*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x01,0x1C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x9E,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"n",78*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x98,0x01,0x0C,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x03,0x0C,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"o",79*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x01,0x1C,0x03,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x03,0x1C,0x03,0xEC,0x01,0x0C,0x00,0x0C,0x00,0x3E,0x00},/*"p",80*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x02,0x8C,0x03,0x0C,0x03,0x06,0x03,0x06,0x03,0x06,0x03,0x06,0x03,0x06,0x03,0x04,0x03,0x8C,0x03,0x78,0x03,0x00,0x03,0x00,0x03,0xC0,0x07},/*"q",81*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9F,0x03,0x58,0x06,0x38,0x06,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"r",82*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x03,0x1C,0x03,0x0C,0x02,0x0C,0x02,0x38,0x00,0xF0,0x00,0xC0,0x03,0x04,0x03,0x04,0x03,0x8C,0x03,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x30,0x00,0x30,0x00,0xFE,0x01,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x02,0x30,0x02,0xE0,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x02,0x8E,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x0C,0x03,0x9C,0x07,0x78,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"u",85*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x07,0x0C,0x02,0x08,0x01,0x08,0x01,0x18,0x01,0x90,0x00,0xB0,0x00,0xB0,0x00,0x60,0x00,0x60,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"v",86*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF7,0x0E,0x62,0x04,0x46,0x04,0x64,0x02,0x64,0x02,0xEC,0x02,0x9C,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"w",87*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBC,0x07,0x18,0x01,0x10,0x01,0xB0,0x00,0x60,0x00,0x60,0x00,0xE0,0x00,0x90,0x00,0x08,0x01,0x08,0x03,0x9E,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"x",88*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9E,0x07,0x08,0x01,0x08,0x01,0x08,0x01,0x90,0x00,0x90,0x00,0xB0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x20,0x00,0x20,0x00,0x24,0x00,0x1C,0x00},/*"y",89*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x01,0x84,0x01,0xC4,0x00,0x44,0x00,0x60,0x00,0x20,0x00,0x30,0x00,0x18,0x02,0x08,0x02,0x0C,0x03,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00},/*"z",90*/ +{0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x40,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x03,0x00,0x00},/*"{",91*/ +{0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00},/*"|",92*/ +{0x00,0x00,0x00,0x00,0x0C,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x0C,0x00,0x00,0x00},/*"}",93*/ +{0x00,0x00,0x1C,0x00,0x22,0x04,0xC2,0x04,0x80,0x03,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,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/ +}; +#endif + +#ifdef ASCII_3216 +const unsigned char ascii_3216[][64]={ +{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,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,0x00,0x00,0x00,0x00,0xC0,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x01,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0xC0,0x03,0xC0,0x03,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x1C,0xE0,0x1C,0xF0,0x1E,0x70,0x0E,0x38,0x07,0x18,0x03,0x08,0x01,0x84,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0xFE,0x7F,0xFE,0x7F,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0xFE,0x7F,0xFE,0x7F,0x08,0x04,0x08,0x04,0x08,0x04,0x08,0x04,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"#",3*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0xC0,0x07,0x60,0x19,0x10,0x31,0x18,0x31,0x18,0x39,0x18,0x39,0x38,0x01,0x70,0x01,0xE0,0x01,0xC0,0x03,0x80,0x07,0x00,0x0F,0x00,0x1D,0x00,0x39,0x00,0x31,0x1C,0x31,0x1C,0x31,0x0C,0x31,0x0C,0x11,0x18,0x0D,0xE0,0x07,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00},/*"$",4*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x10,0x36,0x18,0x63,0x08,0x63,0x0C,0x63,0x04,0x63,0x04,0x63,0x02,0x63,0x02,0x63,0x01,0x36,0x1D,0x9C,0x37,0x80,0x22,0x80,0x63,0x40,0x63,0x40,0x63,0x20,0x63,0x20,0x63,0x30,0x63,0x10,0x22,0x18,0x36,0x08,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"%",5*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x98,0x01,0x8C,0x01,0x8C,0x01,0x8C,0x01,0x8C,0x01,0x8C,0x00,0xCC,0x00,0x78,0x00,0x18,0x3E,0x1C,0x08,0x36,0x08,0x32,0x08,0x63,0x04,0x63,0x04,0xC3,0x04,0xC3,0x03,0x83,0x43,0x06,0x43,0x8E,0x26,0x78,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"&",6*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x3C,0x00,0x3C,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x0C,0x00,0x06,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x03,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x40,0x00,0x00},/*"(",8*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x30,0x00,0x20,0x00,0x60,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x60,0x00,0x60,0x00,0x30,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0x00,0x00},/*")",9*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x80,0x03,0x00,0x01,0x1C,0x71,0x3C,0x79,0x78,0x3D,0xC0,0x07,0x00,0x01,0xC0,0x07,0x78,0x3D,0x3C,0x79,0x1C,0x71,0x00,0x01,0x80,0x03,0x80,0x03,0x80,0x01,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0xFC,0x7F,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x3C,0x00,0x3C,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x0C,0x00,0x06,0x00},/*",",12*/ +{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,0xFE,0x7F,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},/*"-",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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x3C,0x00,0x3C,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x20,0x00,0x30,0x00,0x10,0x00,0x18,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x06,0x00,0x02,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0xC0,0x00,0x40,0x00,0x60,0x00,0x20,0x00,0x30,0x00,0x10,0x00,0x18,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x06,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/*"/",15*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x07,0x60,0x0C,0x30,0x18,0x18,0x30,0x18,0x30,0x18,0x20,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x18,0x20,0x18,0x30,0x18,0x30,0x30,0x18,0x60,0x0C,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"0",16*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xC0,0x03,0xF8,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x10,0x1C,0x08,0x18,0x04,0x30,0x04,0x30,0x0C,0x30,0x0C,0x30,0x00,0x30,0x00,0x18,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00,0x40,0x00,0x20,0x20,0x10,0x20,0x08,0x20,0x04,0x30,0xFC,0x1F,0xFC,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x18,0x0E,0x0C,0x0C,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x00,0x18,0x00,0x0C,0x00,0x06,0xC0,0x03,0x00,0x0E,0x00,0x18,0x00,0x10,0x00,0x30,0x00,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x10,0x0C,0x18,0x18,0x0C,0xE0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x0E,0x00,0x0E,0x00,0x0F,0x80,0x0E,0x80,0x0E,0x40,0x0E,0x60,0x0E,0x20,0x0E,0x10,0x0E,0x10,0x0E,0x08,0x0E,0x04,0x0E,0x04,0x0E,0xFE,0x7F,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x0E,0xC0,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"4",20*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x3F,0xF0,0x3F,0x10,0x00,0x10,0x00,0x10,0x00,0x08,0x00,0x08,0x00,0xC8,0x07,0x28,0x0C,0x18,0x18,0x08,0x10,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x0C,0x30,0x0C,0x30,0x04,0x18,0x04,0x18,0x08,0x0C,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0xC0,0x10,0x20,0x30,0x10,0x30,0x18,0x00,0x18,0x00,0x08,0x00,0x0C,0x00,0x8C,0x0F,0x6C,0x18,0x3C,0x30,0x1C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x18,0x60,0x18,0x20,0x30,0x30,0x60,0x18,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"6",22*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x3F,0xF8,0x3F,0x1C,0x10,0x0C,0x08,0x04,0x08,0x04,0x04,0x00,0x04,0x00,0x02,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x01,0x80,0x00,0x80,0x00,0x80,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"7",23*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x30,0x0C,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x1C,0x30,0x38,0x18,0x70,0x08,0xE0,0x07,0xB0,0x07,0x18,0x0E,0x0C,0x1C,0x06,0x38,0x06,0x30,0x06,0x30,0x06,0x30,0x06,0x30,0x0C,0x18,0x18,0x0C,0xE0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"8",24*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0x18,0x04,0x0C,0x08,0x0C,0x18,0x06,0x10,0x06,0x30,0x06,0x30,0x06,0x30,0x06,0x30,0x06,0x38,0x0C,0x3C,0x18,0x36,0xF0,0x31,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x18,0x0C,0x0C,0x0C,0x06,0x0C,0x03,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"9",25*/ +{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,0x80,0x01,0xC0,0x03,0xC0,0x03,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0xC0,0x03,0xC0,0x03,0x80,0x01,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,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xC0,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x00,0x00},/*";",27*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x06,0x00,0x03,0x80,0x01,0xC0,0x00,0x60,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x00,0x80,0x01,0x00,0x03,0x00,0x06,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"<",28*/ +{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,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"=",29*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x60,0x00,0xC0,0x00,0x80,0x01,0x00,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x80,0x01,0xC0,0x00,0x60,0x00,0x20,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*">",30*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x07,0x30,0x18,0x08,0x30,0x08,0x60,0x0C,0x60,0x1C,0x60,0x1C,0x60,0x1C,0x60,0x00,0x30,0x00,0x1C,0x00,0x06,0x00,0x01,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0xC0,0x03,0xC0,0x03,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"?",31*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x07,0x60,0x18,0x10,0x30,0x18,0x20,0x0C,0x2F,0x8C,0x4D,0x86,0x4C,0xC6,0x4C,0xC6,0x4C,0x66,0x4C,0x66,0x44,0x66,0x44,0x66,0x26,0x66,0x26,0x66,0x15,0xCC,0x1C,0x0C,0x40,0x08,0x20,0x18,0x30,0x30,0x18,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"@",32*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x01,0x40,0x01,0x60,0x03,0x20,0x03,0x20,0x03,0x20,0x03,0x30,0x06,0x10,0x06,0x10,0x06,0x10,0x06,0xF8,0x0F,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x0C,0x0C,0x04,0x18,0x04,0x18,0x06,0x18,0x1F,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"A",33*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x07,0x18,0x1C,0x18,0x38,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x18,0x18,0x0C,0xF8,0x07,0x18,0x18,0x18,0x30,0x18,0x20,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x30,0x18,0x18,0xFE,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"B",34*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x27,0x60,0x38,0x10,0x30,0x18,0x20,0x0C,0x40,0x0C,0x40,0x04,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x0C,0x40,0x0C,0x40,0x0C,0x20,0x18,0x30,0x30,0x18,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"C",35*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x03,0x18,0x0E,0x18,0x18,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x30,0x18,0x30,0x18,0x10,0x18,0x18,0x18,0x0E,0xFE,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"D",36*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x18,0x30,0x18,0x20,0x18,0x60,0x18,0x40,0x18,0x00,0x18,0x08,0x18,0x08,0x18,0x0C,0xF8,0x0F,0x18,0x0C,0x18,0x08,0x18,0x08,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x40,0x18,0x40,0x18,0x20,0x18,0x30,0xFE,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"E",37*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x7F,0x18,0x70,0x18,0x40,0x18,0xC0,0x18,0x80,0x18,0x00,0x18,0x10,0x18,0x10,0x18,0x18,0xF8,0x1F,0x18,0x18,0x18,0x10,0x18,0x10,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"F",38*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x13,0x70,0x1C,0x10,0x10,0x18,0x10,0x0C,0x20,0x0C,0x20,0x04,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0xFC,0x06,0x30,0x06,0x30,0x0C,0x30,0x0C,0x30,0x18,0x30,0x18,0x30,0x30,0x08,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"G",39*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x7E,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0xFC,0x1F,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x3F,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"H",40*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x1F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xF8,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x7F,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x0E,0x06,0x0E,0x03,0x8E,0x01,0xFC,0x00},/*"J",42*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x7C,0x18,0x18,0x18,0x08,0x18,0x04,0x18,0x06,0x18,0x02,0x18,0x01,0x98,0x01,0x98,0x01,0xD8,0x01,0xB8,0x03,0x38,0x03,0x18,0x07,0x18,0x06,0x18,0x0E,0x18,0x0C,0x18,0x1C,0x18,0x18,0x18,0x30,0x18,0x30,0x7E,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"K",43*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x40,0x18,0x40,0x18,0x20,0x18,0x30,0xFE,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"L",44*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1C,0x38,0x1C,0x38,0x1C,0x38,0x1C,0x3C,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x36,0x74,0x32,0x64,0x32,0x64,0x32,0x64,0x32,0x64,0x31,0xC4,0x31,0xC4,0x31,0xC4,0x31,0xC4,0x30,0xC4,0x30,0x84,0x30,0x9F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"M",45*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x7C,0x1C,0x10,0x3C,0x10,0x34,0x10,0x34,0x10,0x74,0x10,0x64,0x10,0xE4,0x10,0xC4,0x10,0xC4,0x11,0x84,0x11,0x84,0x13,0x04,0x13,0x04,0x17,0x04,0x16,0x04,0x1E,0x04,0x1C,0x04,0x1C,0x04,0x1C,0x04,0x18,0x1F,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"N",46*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x03,0x30,0x0C,0x18,0x18,0x08,0x10,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x0C,0x20,0x0C,0x30,0x08,0x10,0x18,0x18,0x30,0x0C,0xC0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"O",47*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x0F,0x18,0x18,0x18,0x30,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x30,0x18,0x18,0xF8,0x0F,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"P",48*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x03,0x30,0x0C,0x18,0x18,0x0C,0x10,0x0C,0x30,0x0C,0x20,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0xE4,0x61,0x2C,0x33,0x1C,0x32,0x18,0x16,0x30,0x0E,0xC0,0x07,0x00,0x4C,0x00,0x7C,0x00,0x38,0x00,0x00,0x00,0x00},/*"Q",49*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x07,0x18,0x1C,0x18,0x38,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x18,0x18,0x0C,0xF8,0x07,0x98,0x03,0x18,0x03,0x18,0x07,0x18,0x06,0x18,0x06,0x18,0x0E,0x18,0x0C,0x18,0x0C,0x18,0x1C,0x18,0x18,0x7E,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"R",50*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x27,0x30,0x38,0x18,0x30,0x0C,0x20,0x0C,0x20,0x0C,0x00,0x0C,0x00,0x18,0x00,0x78,0x00,0xE0,0x03,0x80,0x0F,0x00,0x1E,0x00,0x38,0x00,0x70,0x00,0x60,0x04,0x60,0x04,0x60,0x08,0x60,0x18,0x30,0x38,0x18,0xC8,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"S",51*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x3F,0x8C,0x21,0x84,0x61,0x82,0x41,0x82,0x41,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xE0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"T",52*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x7C,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x08,0x08,0x38,0x04,0xE0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"U",53*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0xF8,0x18,0x20,0x18,0x20,0x18,0x20,0x30,0x10,0x30,0x10,0x30,0x10,0x30,0x10,0x60,0x08,0x60,0x08,0x60,0x08,0xE0,0x0C,0xC0,0x04,0xC0,0x04,0xC0,0x04,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"V",54*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDF,0xF3,0x86,0x61,0x86,0x21,0x86,0x21,0x8C,0x21,0x0C,0x21,0x8C,0x23,0x8C,0x13,0x8C,0x13,0x8C,0x13,0x4C,0x13,0x58,0x12,0x58,0x16,0x58,0x0E,0x38,0x0E,0x38,0x0E,0x38,0x0E,0x30,0x0C,0x10,0x04,0x10,0x04,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"W",55*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x3E,0x18,0x08,0x38,0x08,0x30,0x04,0x30,0x04,0x70,0x02,0x60,0x02,0xE0,0x01,0xC0,0x01,0xC0,0x01,0x80,0x01,0x80,0x03,0x40,0x03,0x40,0x07,0x20,0x06,0x20,0x06,0x10,0x0C,0x10,0x0C,0x08,0x18,0x08,0x18,0x3E,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"X",56*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x7C,0x1C,0x10,0x18,0x10,0x18,0x08,0x30,0x08,0x30,0x0C,0x70,0x04,0x60,0x04,0x60,0x02,0xC0,0x02,0xC0,0x02,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xE0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Y",57*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x3F,0x18,0x18,0x08,0x18,0x04,0x0C,0x04,0x0E,0x00,0x06,0x00,0x07,0x00,0x03,0x80,0x03,0x80,0x01,0xC0,0x01,0xC0,0x00,0xE0,0x00,0x60,0x00,0x70,0x00,0x30,0x00,0x38,0x20,0x18,0x20,0x1C,0x10,0x0C,0x18,0xFE,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Z",58*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3F,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0xC0,0x3F,0x00,0x00,0x00,0x00},/*"[",59*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x18,0x00,0x18,0x00,0x10,0x00,0x30,0x00,0x20,0x00,0x60,0x00,0x60,0x00,0x40,0x00,0xC0,0x00,0x80,0x00,0x80,0x01,0x80,0x01,0x00,0x01,0x00,0x03,0x00,0x02,0x00,0x06,0x00,0x06,0x00,0x04,0x00,0x0C,0x00,0x08,0x00,0x18,0x00,0x18,0x00,0x10,0x00,0x30,0x00,0x20,0x00,0x00},/*"\",60*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x03,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0xFC,0x03,0x00,0x00,0x00,0x00},/*"]",61*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x07,0xC0,0x06,0x20,0x08,0x10,0x10,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,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,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,0xFF,0xFF},/*"_",63*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0xC0,0x00,0x00,0x01,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x03,0x18,0x06,0x0C,0x0C,0x0C,0x0C,0x00,0x0C,0x80,0x0F,0x70,0x0C,0x1C,0x0C,0x0C,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x4C,0x0C,0x4F,0xF8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"a",65*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x1E,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0xD8,0x18,0x38,0x30,0x38,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x20,0x38,0x30,0x78,0x18,0xC8,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"b",66*/ +{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,0xC0,0x07,0x70,0x0C,0x18,0x18,0x18,0x18,0x0C,0x18,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x20,0x18,0x20,0x18,0x10,0x30,0x08,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x1E,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0xE0,0x1B,0x30,0x1C,0x18,0x18,0x18,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x08,0x18,0x18,0x1C,0x30,0x7A,0xE0,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"d",68*/ +{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,0xC0,0x07,0x30,0x0C,0x18,0x18,0x08,0x10,0x0C,0x30,0x0C,0x30,0xFC,0x3F,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x18,0x20,0x18,0x10,0x70,0x18,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"e",69*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x80,0xC3,0x80,0xC0,0xC0,0xC0,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xFC,0x1F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xF8,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"f",70*/ +{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,0xC0,0x77,0x30,0x6C,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x10,0x18,0x30,0x0C,0xF0,0x07,0x18,0x00,0x18,0x00,0xF0,0x0F,0xF0,0x3F,0x08,0x70,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x38,0x38,0xE0,0x0F},/*"g",71*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x1E,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x98,0x0F,0xD8,0x18,0x38,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x7E,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"h",72*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x80,0x03,0x80,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xF8,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"i",73*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x80,0x1F,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x18,0x0C,0x18,0x06,0xF0,0x03},/*"j",74*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x1E,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x3E,0x18,0x0C,0x18,0x06,0x18,0x03,0x18,0x01,0x98,0x01,0xD8,0x01,0x38,0x03,0x18,0x07,0x18,0x06,0x18,0x0C,0x18,0x1C,0x18,0x18,0x7E,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"k",75*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xF8,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"l",76*/ +{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,0xEE,0x1C,0x9C,0x33,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0xDE,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"m",77*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x1E,0x0F,0xD8,0x18,0x38,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x7E,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"n",78*/ +{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,0xC0,0x07,0x70,0x1C,0x10,0x30,0x18,0x30,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0x18,0x30,0x18,0x30,0x30,0x18,0xC0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"o",79*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x9E,0x0F,0x58,0x18,0x38,0x30,0x18,0x20,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x30,0x38,0x30,0x78,0x18,0x98,0x07,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x7E,0x00},/*"p",80*/ +{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,0xC0,0x23,0x30,0x3C,0x18,0x38,0x18,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x08,0x30,0x18,0x38,0x30,0x3C,0xE0,0x33,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0xFC},/*"q",81*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x7E,0x3C,0x60,0x66,0x60,0x61,0xE0,0x00,0xE0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"r",82*/ +{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,0xE0,0x27,0x30,0x38,0x18,0x30,0x18,0x20,0x18,0x00,0x70,0x00,0xE0,0x03,0x80,0x0F,0x00,0x1C,0x04,0x30,0x04,0x30,0x0C,0x30,0x1C,0x18,0xEC,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"s",83*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xC0,0x00,0xE0,0x00,0xFC,0x1F,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x20,0xC0,0x20,0x80,0x11,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x1E,0x3C,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x38,0x30,0xF4,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"u",85*/ +{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,0x7E,0x3C,0x18,0x18,0x18,0x08,0x38,0x08,0x30,0x04,0x30,0x04,0x70,0x02,0x60,0x02,0x60,0x02,0xE0,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"v",86*/ +{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,0xDF,0xF7,0x8E,0x63,0x0C,0x23,0x8C,0x23,0x8C,0x23,0x98,0x13,0x98,0x13,0x58,0x16,0x58,0x16,0x70,0x0E,0x70,0x0E,0x70,0x0E,0x20,0x04,0x20,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"w",87*/ +{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,0x3E,0x70,0x08,0x70,0x04,0xE0,0x04,0xC0,0x02,0xC0,0x01,0x80,0x03,0x80,0x03,0x40,0x07,0x60,0x06,0x20,0x0C,0x10,0x0C,0x18,0x18,0x3E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"x",88*/ +{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,0x7E,0x7C,0x18,0x18,0x18,0x08,0x30,0x08,0x30,0x08,0x30,0x04,0x60,0x04,0x60,0x04,0xC0,0x02,0xC0,0x02,0xC0,0x02,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x80,0x00,0x80,0x00,0x4C,0x00,0x3C,0x00},/*"y",89*/ +{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,0x1F,0x0C,0x0C,0x04,0x0E,0x04,0x06,0x00,0x03,0x80,0x03,0x80,0x01,0xC0,0x00,0xE0,0x00,0x70,0x20,0x30,0x20,0x38,0x30,0x1C,0x18,0xFC,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"z",90*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x08,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x02,0x80,0x01,0x00,0x02,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x08,0x00,0x30,0x00,0x00},/*"{",91*/ +{0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01},/*"|",92*/ +{0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x10,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x80,0x01,0x40,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,0x0C,0x00,0x00,0x00},/*"}",93*/ +{0x00,0x00,0x38,0x00,0xC4,0x00,0x86,0x40,0x02,0x61,0x00,0x22,0x00,0x1C,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/ +}; +#endif + +#ifdef LOGO_M +const unsigned char logo_M[] = { + + 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, + 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, + 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, + 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, + 0x00, 0x01, 0xf8, 0x00, 0x00, 0xff, 0xc0, 0x00, + 0x00, 0x07, 0xfc, 0x00, 0x01, 0xff, 0xe0, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x07, 0xff, 0xf0, 0x00, + 0x00, 0x1f, 0xff, 0x80, 0x0f, 0xff, 0xf0, 0x00, + 0x00, 0x3f, 0xff, 0xc0, 0x1f, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xe0, 0x7f, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xf0, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xfb, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xff, 0xff, 0x9f, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xff, 0xff, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf3, 0xff, 0xfc, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf1, 0xff, 0xf8, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0xff, 0xe0, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x7f, 0x80, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x1e, 0x00, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x08, 0x00, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x00, 0x0e, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xf0, 0x00, 0x1e, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x00, 0x7e, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x00, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x01, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x03, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x07, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x07, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x03, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x01, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x00, 0xfe, 0x0f, 0xf8, 0x00, + 0x00, 0x3f, 0xe0, 0x00, 0x7e, 0x0f, 0xf8, 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, 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, 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, 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, 0x00 + +}; +#endif + +#ifdef LOGO_R +const unsigned char logo_R[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, + 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x07, 0xff, 0xf8, 0xff, 0xff, 0x80, 0x00, + 0x07, 0xff, 0xf0, 0xff, 0xff, 0x80, 0x00, + 0x07, 0xff, 0xf0, 0x7f, 0xff, 0x80, 0x00, + 0x0f, 0xff, 0xf0, 0x7f, 0xff, 0xc0, 0x00, + 0x0f, 0xff, 0xf0, 0x7f, 0xff, 0xc0, 0x00, + 0x0f, 0xff, 0xf0, 0x3f, 0xff, 0xe0, 0x00, + 0x0f, 0xff, 0xf0, 0x3f, 0xff, 0xe0, 0x00, + 0x0f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x00, + 0x1f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x00, + 0x1f, 0xff, 0xe0, 0x0f, 0xff, 0xf8, 0x00, + 0x1f, 0xff, 0xe0, 0x0f, 0xff, 0xf8, 0x00, + 0x1f, 0xff, 0xe0, 0x0f, 0xff, 0xf8, 0x00, + 0x1f, 0xff, 0xc0, 0x07, 0xff, 0xfc, 0x00, + 0x1f, 0xff, 0xc0, 0x07, 0xff, 0xfc, 0x00, + 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xfe, 0x00, + 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xfe, 0x00, + 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, + 0x3f, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, + 0x3f, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, + 0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0x80, + 0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0xc0, + 0x3f, 0xff, 0x00, 0x00, 0x7f, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif + +#ifdef HUAJI +const unsigned char huaji[] = { + 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, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xe0, 0x00, 0x1f, 0xc0, 0x00, + 0x00, 0x0f, 0xf0, 0x00, 0x1f, 0xe0, 0x00, + 0x00, 0x0c, 0x70, 0x00, 0x38, 0x70, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x30, 0x70, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x20, 0x30, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0xc0, 0x00, 0x01, 0xfe, 0x00, + 0x00, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0x00, + 0x01, 0xe0, 0x0f, 0x00, 0x38, 0x01, 0xc0, + 0x03, 0x00, 0x03, 0x80, 0xe0, 0x00, 0x60, + 0x06, 0x00, 0x00, 0xc1, 0xc0, 0x00, 0x30, + 0x0c, 0xc0, 0x00, 0xc1, 0xb0, 0x00, 0x18, + 0x0d, 0xc0, 0x00, 0x63, 0x78, 0x00, 0x18, + 0x0d, 0xff, 0xf8, 0x43, 0x7f, 0xfe, 0x18, + 0x0f, 0xff, 0x7f, 0xc1, 0xff, 0xcf, 0xf0, + 0x07, 0xe0, 0x07, 0x81, 0xf8, 0x01, 0xf0, + 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, 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, 0x00, 0x02, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0x00, + 0x00, 0x03, 0x80, 0x00, 0x00, 0xe0, 0x00, + 0x00, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x00, + 0x00, 0x00, 0xe0, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x00, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xff, 0x80, 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, 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, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif \ No newline at end of file diff --git a/assets/User_code/device/oid.c b/assets/User_code/device/oid.c new file mode 100644 index 0000000..6570526 --- /dev/null +++ b/assets/User_code/device/oid.c @@ -0,0 +1,467 @@ +/* + oid编码器驱动 +*/ + +/*编码器can通信的默认波特率为500kHZ*/ +/* Includes ----------------------------------------------------------------- */ +#include "device/oid.h" +#include "bsp/time.h" +#include "mm.h" +/* Private function prototypes ---------------------------------------------- */ + +static OID_CANManager_t* OID_GetCANManager(BSP_CAN_t can); + +/* Private functions -------------------------------------------------------- */ + +static OID_CANManager_t *can_managers[BSP_CAN_NUM] = {NULL}; + +/** + * @brief 接收数据处理 + * @param[in] none + * @retval none + */ +static void OID_ParseFeedbackFrame( OID_t *encoder , uint8_t *rx_data ) +{ + if(encoder->param.id == rx_data[1])//判断编码器id + { + switch(rx_data[2])//判断指令 + { + case 0x01: + encoder->feedback.angle_fbk = rx_data[3]|rx_data[4]<<8|rx_data[5]<<16|rx_data[6]<<24; + encoder->feedback.angle_360 = encoder->feedback.angle_fbk*360.0f/OID_RESOLUTION; + encoder->feedback.angle_2PI = encoder->feedback.angle_fbk*M_2PI/OID_RESOLUTION; + break; + + case 0x0A: + encoder->feedback.speed_fbk=rx_data[3]|rx_data[4]<<8|rx_data[5]<<16|rx_data[6]<<24; + encoder->feedback.speed_rpm=encoder->feedback.speed_fbk/OID_RESOLUTION/(0.1f/60.0f); + break; + + default: + break; + } + } +} + +int8_t OID_Update(OID_Param_t *param) +{ + + if (param == NULL) return DEVICE_ERR_NULL; + + OID_CANManager_t *manager = OID_GetCANManager(param->can); + if (manager == NULL) return DEVICE_ERR_NULL; + + OID_t *encoder = NULL; + + for (int i = 0; i < manager->encoder_count; i++) { + if (manager->encoders[i] && manager->encoders[i]->param.id == param->id) { + encoder = manager->encoders[i]; + break; + } + } + + if (encoder == NULL) return DEVICE_ERR_NO_DEV; + + // 从CAN队列获取数据 + BSP_CAN_Message_t rx_msg; + if (BSP_CAN_GetMessage( param->can , param->id , &rx_msg, BSP_CAN_TIMEOUT_IMMEDIATE) != BSP_OK) + { + uint64_t now_time = BSP_TIME_Get(); + if (now_time - encoder->header.last_online_time > 100000) // 100ms超时,单位微秒 + { + encoder->header.online = false; + } + return DEVICE_ERR; + } + + encoder->header.online = true; + encoder->header.last_online_time = BSP_TIME_Get(); + // 处理接收到的数据 + OID_ParseFeedbackFrame( encoder , rx_msg.data ); + return DEVICE_OK; // 没有新数据 +} + +/** + * @brief 更新所有编码器数据 + * @return 更新结果 + */ +int8_t OID_UpdateAll(void) { + int8_t ret = DEVICE_OK; + for (int can = 0; can < BSP_CAN_NUM; can++) { + OID_CANManager_t *manager = OID_GetCANManager((BSP_CAN_t)can); + if (manager == NULL) continue; + + for (int i = 0; i < manager->encoder_count; i++) { + OID_t *encoder = manager->encoders[i]; + if (encoder != NULL) { + if (OID_Update(&encoder->param) != DEVICE_OK) { + ret = DEVICE_ERR; + } + } + } + } + return ret; +} + +/** + * @brief 获取指定CAN总线的管理器 + * @param can CAN总线 + * @return CAN管理器指针 + */ +static OID_CANManager_t* OID_GetCANManager(BSP_CAN_t can) { + if (can >= BSP_CAN_NUM) { + return NULL; + } + + return can_managers[can]; +} + +/** + * @brief 创建CAN管理器 + * @param can CAN总线 + * @return 创建结果 + */ +static int8_t OID_CreateCANManager(BSP_CAN_t can) { + if (can >= BSP_CAN_NUM) return DEVICE_ERR; + if (can_managers[can] != NULL) return DEVICE_OK; + + can_managers[can] = (OID_CANManager_t*)BSP_Malloc(sizeof(OID_CANManager_t)); + if (can_managers[can] == NULL) return DEVICE_ERR; + + memset(can_managers[can], 0, sizeof(OID_CANManager_t)); + can_managers[can]->can = can; + return DEVICE_OK; +} + +/** + * @brief 注册一个欧艾迪编码器 + * @param param 编码器参数 + * @return 注册结果 + */ +int8_t OID_Register(OID_Param_t *param) +{ + if (param == NULL) { + return DEVICE_ERR_NULL; + } + + /* 创建CAN管理器 */ + if (OID_CreateCANManager(param->can) != DEVICE_OK) { + return DEVICE_ERR; + } + + /* 获取CAN管理器 */ + OID_CANManager_t *manager = OID_GetCANManager(param->can); + if (manager == NULL) { + return DEVICE_ERR; + } + + /* 检查是否已注册 */ + for (int i = 0; i < manager->encoder_count; i++) { + if (manager->encoders[i] && manager->encoders[i]->param.id == param->id) { + return DEVICE_ERR_INITED; + } + } + + /* 检查是否已达到最大数量 */ + if (manager->encoder_count >= OID_MAX_NUM) { + return DEVICE_ERR; + } + + /* 分配内存 */ + OID_t *encoder = (OID_t *)BSP_Malloc(sizeof(OID_t)); + if (encoder == NULL) { + return DEVICE_ERR; + } + + /* 初始化电机 */ + memset(encoder, 0, sizeof(OID_t)); + memcpy(&encoder->param, param, sizeof(OID_Param_t)); + encoder->header.online = false; +// encoder->encoder.reverse = param->reverse; + + /* 注册CAN接收ID - DM电机使用Master ID接收反馈 */ + uint16_t feedback_id = param->id; + if (BSP_CAN_RegisterId(param->can, feedback_id, 3) != BSP_OK) { + BSP_Free(encoder); + return DEVICE_ERR; + } + + /* 添加到管理器 */ + manager->encoders[manager->encoder_count] = encoder; + manager->encoder_count++; + + return DEVICE_OK; +} + +/** + * @brief 使编码器离线(设置在线状态为false) + * @param param 编码器参数 + * @return 操作结果 + */ +int8_t OID_Offline(OID_Param_t *param) { + if (param == NULL) { + return DEVICE_ERR_NULL; + } + + OID_t *encoder = OID_GetEncoder(param); + if (encoder == NULL) { + return DEVICE_ERR_NO_DEV; + } + + encoder->header.online = false; + return DEVICE_OK; +} + +/** + * @brief 获取指定编码器的实例指针 + * @param param 编码器参数 + * @return 编码器实例指针 + */ +OID_t* OID_GetEncoder(OID_Param_t *param) { + if (param == NULL) { + return NULL; + } + + OID_CANManager_t *manager = OID_GetCANManager(param->can); + if (manager == NULL) { + return NULL; + } + + /* 查找对应的编码器 */ + for (int i = 0; i < manager->encoder_count; i++) { + OID_t *encoder = manager->encoders[i]; + if (encoder && encoder->param.can == param->can && + encoder->param.id == param->id) { + return encoder; + } + } + + return NULL; +} +/** + * @brief 读取编码器值 + * @param[in] 编码器id + * @retval none + */ +int8_t OID_Read_Value(OID_Param_t *param) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x01; + frame.data[3] = 0x00; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器id + * @param[in] 编码器当前id,编码器设置id + * @retval none + */ +int8_t OID_Set_ID(OID_Param_t *param,OID_Param_t *param_new) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x02; + frame.data[3] = param_new->id; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置can通讯波特率 0x00:500K(默认);0x01:1M;0x02:250K;0x03:125K;0x04:100K; + * @param[in] 编码器id,编码器设置波特率 + * @retval none + */ +int8_t OID_Set_Baudrate(OID_Param_t *param,OID_Baudrate_t encoder_vaud_rate) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x03; + frame.data[3] = encoder_vaud_rate; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器模式 0x00:查询,0x02:自动返回编码器角速度值,0xAA:自动返回编码器值 + * @param[in] 编码器id,编码器设置模式 + * @retval none + */ +int8_t OID_Set_Mode(OID_Param_t *param,OID_Mode_t encoder_mode) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x04; + frame.data[3] = encoder_mode; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器自动回传时间(掉电记忆,单位:微秒),数值范围:50~65535(16 位无符号整数) + 注意:设置太短的返回时间后,通过编码器上位机再设置其他参数很容易失败,谨慎使用! + * @param[in] 编码器id,编码器自动回传时间 + * @retval none + */ +int8_t OID_Set_AutoFeedbackTime(OID_Param_t *param,uint8_t encoder_time) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x05; + frame.data[3] = encoder_time; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置当前位置值为零点 + * @param[in] 编码器id + * @retval none + */ +int8_t OID_Set_ZeroPoint(OID_Param_t *param) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x06; + frame.data[3] = 0x00; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器值递增方向 0x00:顺时针,0x01:逆时针 + * @param[in] 编码器id + * @retval none + */ +int8_t OID_Set_Polarity(OID_Param_t *param,OID_Direction_t encoder_direction) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x07; + frame.data[3] = encoder_direction; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 读取编码器角度值 + * @param[in] 编码器id + * @retval none + 编码器旋转速度=编码器角速度值/单圈 + 精度/转速计算时间(单位:转/分钟) + 例如:编码器角速度值回传为1000,单圈 + 精度为32768,转速采样时间为 + 100ms(0.1/60min) + 编码器旋转速度=1000/32768/(0.1/60) + =1000*0.0183=18.31转/分钟 + */ +int8_t OID_Read_AngularVelocity(OID_Param_t *param) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x0A; + frame.data[3] = 0x00; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器角速度采样时间(掉电记忆,单位:毫秒) + * @param[in] 编码器id,采样时间 + * @retval none + */ +int8_t OID_Set_AngularVelocitySamplingTime(OID_Param_t *param,uint8_t encoder_time) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x0B; + frame.data[3] = encoder_time; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器中点 设定当前编码器值为 M(M 为单圈分辨率*圈数/2) + * @param[in] 编码器id + * @retval none + */ +int8_t OID_Set_Midpoint(OID_Param_t *param) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x0C; + frame.data[3] = 0x01; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 设置编码器当前位置值 数值范围:0~X(X 为单圈分辨率*圈数- 1) + * @param[in] 编码器id + * @retval none + */ +int8_t OID_Set_CurrentPosition(OID_Param_t *param,uint8_t encoder_direction) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x0D; + frame.data[3] = encoder_direction; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} +/** + * @brief 编码器设置当前值为 5 圈值 即当前编码器值为 Z(Z 为单圈分辨率*5) + * @param[in] 编码器id + * @retval none + */ +int8_t OID_Set_CurrentValue5Turns(OID_Param_t *param) +{ + BSP_CAN_StdDataFrame_t frame; + frame.id = param->id; + frame.dlc = 4; + frame.data[0] = 0x04; + frame.data[1] = param->id; + frame.data[2] = 0x0F; + frame.data[3] = 0x01; + + + return BSP_CAN_TransmitStdDataFrame(param->can, &frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; +} + + + diff --git a/assets/User_code/device/oid.h b/assets/User_code/device/oid.h new file mode 100644 index 0000000..9b74764 --- /dev/null +++ b/assets/User_code/device/oid.h @@ -0,0 +1,269 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include "device/device.h" +#include "bsp/can.h" +#include "component/user_math.h" + +/* Exported constants ------------------------------------------------------- */ +#define OID_MAX_NUM 32 +#define OID_RESOLUTION 1024 //编码器分辨率 +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ + +/** + * @brief 编码器工作模式枚举 + */ +typedef enum { + OID_MODE_QUERY = 0x00, // 查询模式 + OID_MODE_AUTO_SPEED = 0x02, // 自动返回编码器角速度值 + OID_MODE_AUTO_POSITION = 0xAA // 自动返回编码器值 +} OID_Mode_t; + +/** + * @brief 编码器方向枚举 + */ +typedef enum { + OID_DIR_CW = 0x00, // 顺时针 + OID_DIR_CCW = 0x01 // 逆时针 +} OID_Direction_t; + +/** + * @brief 编码器波特率枚举 + * 当编码器的ID和波特率更改后,闪灯的颜色会相应变化,状态灯颜色参照表及代表的意义如下: + * + * 颜色及其数值定义关系: + * - 蓝色(0) : 500K(默认) + * - 青色(1) : 1M + * - 橙色(2) : 250K + * - 紫色(3) : 125K + * - 绿色(4) : 100K + * - 红色(5) : 保留 + */ +typedef enum { + OID_BAUD_500K = 0x00, // 蓝色 - 500K(默认) + OID_BAUD_1M = 0x01, // 青色 - 1M + OID_BAUD_250K = 0x02, // 橙色 - 250K + OID_BAUD_125K = 0x03, // 紫色 - 125K + OID_BAUD_100K = 0x04 // 绿色 - 100K +} OID_Baudrate_t; + +typedef struct { + BSP_CAN_t can; + uint16_t id; + +} OID_Param_t; + +typedef struct { + //0x01 编码器值反馈 + float angle_fbk; + float angle_360; + float angle_2PI; + //0x0A 速度反馈 + float speed_fbk; + float speed_rpm; + +} OID_Feedback_t; + +typedef struct { + DEVICE_Header_t header; + OID_Param_t param; + OID_Feedback_t feedback; +} OID_t; + +/*CAN管理器,管理一个CAN总线上所有的编码器*/ +typedef struct { + BSP_CAN_t can; + OID_t *encoders[OID_MAX_NUM]; + uint8_t encoder_count; +} OID_CANManager_t; + + +/** + * @brief 更新指定编码器数据 + * @param param 编码器参数指针 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR_NULL: 参数为空 + * - DEVICE_ERR_NO_DEV: 编码器未找到 + * - DEVICE_ERR: 其他错误 + */ +int8_t OID_Update(OID_Param_t *param); + +/** + * @brief 更新所有已注册编码器数据 + * @return 操作结果 + * - DEVICE_OK: 全部成功 + * - DEVICE_ERR: 部分或全部失败 + */ +int8_t OID_UpdateAll(void); + +/** + * @brief 注册一个欧艾迪编码器 + * @param param 编码器参数指针 + * @return 注册结果 + * - DEVICE_OK: 注册成功 + * - DEVICE_ERR_NULL: 参数为空 + * - DEVICE_ERR_INITED: 已注册 + * - DEVICE_ERR: 其他错误 + */ +int8_t OID_Register(OID_Param_t *param); + +/** + * @brief 设置编码器离线状态 + * @param param 编码器参数指针 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR_NULL: 参数为空 + * - DEVICE_ERR_NO_DEV: 编码器未找到 + */ +int8_t OID_Offline(OID_Param_t *param); + +/** + * @brief 获取指定编码器实例指针 + * @param param 编码器参数指针 + * @return 编码器实例指针,失败返回NULL + */ +OID_t* OID_GetEncoder(OID_Param_t *param); + +/** + * @brief 设置编码器ID + * @param param 当前编码器参数 + * @param param_new 新编码器参数(包含新ID) + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_ID(OID_Param_t *param, OID_Param_t *param_new); + +/** + * @brief 设置编码器CAN通信波特率 + * @param param 编码器参数 + * @param encoder_vaud_rate 波特率设置 + * - 0x00: 500K(默认) + * - 0x01: 1M + * - 0x02: 250K + * - 0x03: 125K + * - 0x04: 100K + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_Baudrate(OID_Param_t *param, OID_Baudrate_t encoder_vaud_rate); + +/** + * @brief 设置编码器工作模式 + * @param param 编码器参数 + * @param encoder_mode 工作模式 + * - 0x00: 查询模式 + * - 0x02: 自动返回编码器角速度值 + * - 0xAA: 自动返回编码器值 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_Mode(OID_Param_t *param, OID_Mode_t encoder_mode); + +/** + * @brief 设置编码器自动回传时间 + * @param param 编码器参数 + * @param encoder_time 自动回传时间(单位:微秒) + * 数值范围:50~65535(16位无符号整数) + * @note 注意:设置太短的返回时间后,通过编码器上位机再设置其他参数很容易失败,谨慎使用! + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_AutoFeedbackTime(OID_Param_t *param, uint8_t encoder_time); + +/** + * @brief 设置当前位置为零点 + * @param param 编码器参数 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_ZeroPoint(OID_Param_t *param); + +/** + * @brief 设置编码器值递增方向 + * @param param 编码器参数 + * @param encoder_direction 方向设置 + * - 0x00: 顺时针 + * - 0x01: 逆时针 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_Polarity(OID_Param_t *param, OID_Direction_t encoder_direction); + +/** + * @brief 设置编码器角速度采样时间 + * @param param 编码器参数 + * @param encoder_time 采样时间(单位:毫秒) + * @note 掉电记忆功能 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_AngularVelocitySamplingTime(OID_Param_t *param, uint8_t encoder_time); + +/** + * @brief 设置编码器中点位置 + * @param param 编码器参数 + * @note 设定当前编码器值为 M(M 为单圈分辨率 × 圈数 / 2) + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_Midpoint(OID_Param_t *param); + +/** + * @brief 设置编码器当前位置值 + * @param param 编码器参数 + * @param encoder_direction 位置值 + * 数值范围:0~X(X 为单圈分辨率 × 圈数 - 1) + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_CurrentPosition(OID_Param_t *param, uint8_t encoder_direction); + +/** + * @brief 设置编码器当前值为5圈值 + * @param param 编码器参数 + * @note 即当前编码器值为 Z(Z 为单圈分辨率 × 5) + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Set_CurrentValue5Turns(OID_Param_t *param); + +/** + * @brief 读取编码器角速度值 + * @param param 编码器参数 + * @note 编码器旋转速度 = 编码器角速度值 / 单圈精度 / 转速计算时间(单位:转/分钟) + * 例如:编码器角速度值回传为1000,单圈精度为32768,转速采样时间为100ms(0.1/60min) + * 编码器旋转速度 = 1000 / 32768 / (0.1/60) = 1000 × 0.0183 = 18.31转/分钟 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Read_AngularVelocity(OID_Param_t *param); + +/** + * @brief 读取编码器值 + * @param param 编码器参数 + * @return 操作结果 + * - DEVICE_OK: 成功 + * - DEVICE_ERR: 失败 + */ +int8_t OID_Read_Value(OID_Param_t *param); + +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/module/cmd/cmd.c b/assets/User_code/module/cmd/cmd.c new file mode 100644 index 0000000..6dcca41 --- /dev/null +++ b/assets/User_code/module/cmd/cmd.c @@ -0,0 +1,265 @@ +/* + * CMD 模块 V2 - 主控制模块实现 + */ +#include "cmd.h" +#include "bsp/time.h" +#include +#include + +/* ========================================================================== */ +/* 命令构建函数 */ +/* ========================================================================== */ + +/* 从RC输入生成底盘命令 */ +static void CMD_RC_BuildChassisCmd(CMD_t *ctx) { + CMD_RCModeMap_t *map = &ctx->config->rc_mode_map; + + /* 根据左拨杆位置选择模式 */ + switch (ctx->input.rc.sw[0]) { + case CMD_SW_UP: + ctx->output.chassis.cmd.mode = map->sw_left_up; + break; + case CMD_SW_MID: + ctx->output.chassis.cmd.mode = map->sw_left_mid; + break; + case CMD_SW_DOWN: + ctx->output.chassis.cmd.mode = map->sw_left_down; + break; + default: + ctx->output.chassis.cmd.mode = CHASSIS_MODE_RELAX; + break; + } + + /* 摇杆控制移动 */ + ctx->output.chassis.cmd.ctrl_vec.vx = ctx->input.rc.joy_right.x; + ctx->output.chassis.cmd.ctrl_vec.vy = ctx->input.rc.joy_right.y; +} + +/* 从RC输入生成云台命令 */ +static void CMD_RC_BuildGimbalCmd(CMD_t *ctx) { + CMD_RCModeMap_t *map = &ctx->config->rc_mode_map; + + /* 根据拨杆选择云台模式 */ + switch (ctx->input.rc.sw[0]) { + case CMD_SW_UP: + ctx->output.gimbal.cmd.mode = map->gimbal_sw_up; + break; + case CMD_SW_MID: + ctx->output.gimbal.cmd.mode = map->gimbal_sw_mid; + break; + case CMD_SW_DOWN: + ctx->output.gimbal.cmd.mode = map->gimbal_sw_down; + break; + default: + ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELAX; + break; + } + + /* 左摇杆控制云台 */ + ctx->output.gimbal.cmd.delta_yaw = -ctx->input.rc.joy_left.x * 2.0f; + ctx->output.gimbal.cmd.delta_pit = -ctx->input.rc.joy_left.y * 1.5f; +} + +/* 从RC输入生成射击命令 */ +static void CMD_RC_BuildShootCmd(CMD_t *ctx) { + if (ctx->input.online[CMD_SRC_RC]) { + ctx->output.shoot.cmd.mode = SHOOT_MODE_SINGLE; + } else { + ctx->output.shoot.cmd.mode = SHOOT_MODE_SAFE; + } + + /* 根据右拨杆控制射击 */ + switch (ctx->input.rc.sw[1]) { + case CMD_SW_DOWN: + ctx->output.shoot.cmd.ready = true; + ctx->output.shoot.cmd.firecmd = true; + break; + case CMD_SW_MID: + ctx->output.shoot.cmd.ready = true; + ctx->output.shoot.cmd.firecmd = false; + break; + case CMD_SW_UP: + default: + ctx->output.shoot.cmd.ready = false; + ctx->output.shoot.cmd.firecmd = false; + break; + } +} + +/* 从PC输入生成底盘命令 */ +static void CMD_PC_BuildChassisCmd(CMD_t *ctx) { + + if (!ctx->input.online[CMD_SRC_PC]) { + ctx->output.chassis.cmd.mode = CHASSIS_MODE_RELAX; + return; + } + + ctx->output.chassis.cmd.mode = CHASSIS_MODE_FOLLOW_GIMBAL; + + /* WASD控制移动 */ + ctx->output.chassis.cmd.ctrl_vec.vx = 0.0f; + ctx->output.chassis.cmd.ctrl_vec.vy = 0.0f; + CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_CHASSIS); +} + +/* 从PC输入生成云台命令 */ +static void CMD_PC_BuildGimbalCmd(CMD_t *ctx) { + CMD_Sensitivity_t *sens = &ctx->config->sensitivity; + + if (!ctx->input.online[CMD_SRC_PC]) { + ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELAX; + return; + } + + ctx->output.gimbal.cmd.mode = GIMBAL_MODE_ABSOLUTE; + + /* 鼠标控制云台 */ + ctx->output.gimbal.cmd.delta_yaw = (float)-ctx->input.pc.mouse.x * ctx->timer.dt * sens->mouse_sens; + ctx->output.gimbal.cmd.delta_pit = (float)ctx->input.pc.mouse.y * ctx->timer.dt * sens->mouse_sens * 1.5f; + CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_GIMBAL); +} + +/* 从PC输入生成射击命令 */ +static void CMD_PC_BuildShootCmd(CMD_t *ctx) { + if (!ctx->input.online[CMD_SRC_PC]) { + ctx->output.shoot.cmd.mode = SHOOT_MODE_SAFE; + return; + } + + ctx->output.shoot.cmd.ready = true; + ctx->output.shoot.cmd.firecmd = ctx->input.pc.mouse.l_click; + + CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_SHOOT); + +} + +/* 离线安全模式 */ +static void CMD_SetOfflineMode(CMD_t *ctx) { + ctx->output.chassis.cmd.mode = CHASSIS_MODE_RELAX; + ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELAX; + ctx->output.shoot.cmd.mode = SHOOT_MODE_SAFE; +} + +/* ========================================================================== */ +/* 公开API实现 */ +/* ========================================================================== */ + +int8_t CMD_Init(CMD_t *ctx, CMD_Config_t *config) { + if (ctx == NULL || config == NULL) { + return CMD_ERR_NULL; + } + + memset(ctx, 0, sizeof(CMD_t)); + ctx->config = config; + + /* 初始化适配器 */ + CMD_Adapter_InitAll(); + + /* 初始化行为处理器 */ + CMD_Behavior_Init(); + + return CMD_OK; +} + +int8_t CMD_UpdateInput(CMD_t *ctx) { + if (ctx == NULL) { + return CMD_ERR_NULL; + } + + /* 保存上一帧输入 */ + memcpy(&ctx->last_input, &ctx->input, sizeof(ctx->input)); + + /* 更新所有输入源 */ + for (int i = 0; i < CMD_SRC_NUM; i++) { + CMD_Adapter_GetInput((CMD_InputSource_t)i, &ctx->input); + } + + return CMD_OK; +} +typedef void (*CMD_BuildCommandFunc)(CMD_t *cmd); +typedef struct { + CMD_InputSource_t source; + CMD_BuildCommandFunc chassisFunc; + CMD_BuildCommandFunc gimbalFunc; + CMD_BuildCommandFunc shootFunc; +} CMD_SourceHandler_t; + +CMD_SourceHandler_t sourceHandlers[CMD_SRC_NUM] = { + {CMD_SRC_RC, CMD_RC_BuildChassisCmd, CMD_RC_BuildGimbalCmd, CMD_RC_BuildShootCmd}, + {CMD_SRC_PC, CMD_PC_BuildChassisCmd, CMD_PC_BuildGimbalCmd, CMD_PC_BuildShootCmd}, + {CMD_SRC_NUC, NULL, NULL, NULL}, + {CMD_SRC_REF, NULL, NULL, NULL}, +}; + +int8_t CMD_Arbitrate(CMD_t *ctx) { + if (ctx == NULL) { + return CMD_ERR_NULL; + } + + /* 自动仲裁:优先级 PC > RC > NUC */ + CMD_InputSource_t candidates[] = {CMD_SRC_PC, CMD_SRC_RC, CMD_SRC_NUC}; + const int num_candidates = sizeof(candidates) / sizeof(candidates[0]); + + /* 如果当前输入源仍然在线且有效,保持使用 */ + if (ctx->active_source < CMD_SRC_NUM && + ctx->active_source != CMD_SRC_REF && + ctx->input.online[ctx->active_source]) { + goto seize; + } + + /* 否则选择第一个可用的控制输入源 */ + for (int i = 0; i < num_candidates; i++) { + CMD_InputSource_t src = candidates[i]; + if (ctx->input.online[src]) { + ctx->active_source = src; + break; + }else { + ctx->active_source = CMD_SRC_NUM; + continue; + } + } + ctx->output.chassis.source = ctx->active_source; + ctx->output.gimbal.source = ctx->active_source; + ctx->output.shoot.source = ctx->active_source; + + /* 优先级抢占逻辑 */ + seize: + CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_NONE); + + return CMD_OK; +} + +int8_t CMD_GenerateCommands(CMD_t *ctx) { + if (ctx == NULL) { + return CMD_ERR_NULL; + } + + /* 更新时间 */ + uint64_t now_us = BSP_TIME_Get_us(); + ctx->timer.now = now_us / 1000000.0f; + ctx->timer.dt = (now_us - ctx->timer.last_us) / 1000000.0f; + ctx->timer.last_us = now_us; + + /* 没有有效输入源 */ + if (ctx->active_source >= CMD_SRC_NUM) { + CMD_SetOfflineMode(ctx); + return CMD_ERR_NO_INPUT; + } + + sourceHandlers[ctx->output.gimbal.source].gimbalFunc(ctx); + sourceHandlers[ctx->output.chassis.source].chassisFunc(ctx); + sourceHandlers[ctx->output.shoot.source].shootFunc(ctx); + return CMD_OK; +} + +int8_t CMD_Update(CMD_t *ctx) { + int8_t ret; + + ret = CMD_UpdateInput(ctx); + if (ret != CMD_OK) return ret; + + CMD_Arbitrate(ctx); + + ret = CMD_GenerateCommands(ctx); + return ret; +} diff --git a/assets/User_code/module/cmd/cmd.h b/assets/User_code/module/cmd/cmd.h new file mode 100644 index 0000000..c70c46f --- /dev/null +++ b/assets/User_code/module/cmd/cmd.h @@ -0,0 +1,172 @@ +/* + * CMD 模块 V2 - 主控制模块 + * 统一的命令控制接口 + */ +#pragma once + +#include "cmd_types.h" +#include "cmd_adapter.h" +#include "cmd_behavior.h" + +/* 引入输出模块的命令类型 */ +#include "module/chassis.h" +#include "module/gimbal.h" +#include "module/shoot.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* 输出命令结构 */ +/* ========================================================================== */ + +/* 每个模块的输出包含源信息和命令 */ +typedef struct { + CMD_InputSource_t source; + Chassis_CMD_t cmd; +} CMD_ChassisOutput_t; + +typedef struct { + CMD_InputSource_t source; + Gimbal_CMD_t cmd; +} CMD_GimbalOutput_t; + +typedef struct { + CMD_InputSource_t source; + Shoot_CMD_t cmd; +} CMD_ShootOutput_t; + +/* ========================================================================== */ +/* 配置结构 */ +/* ========================================================================== */ + +/* 灵敏度配置 */ +typedef struct { + float mouse_sens; /* 鼠标灵敏度 */ + float move_sens; /* 移动灵敏度 */ + float move_fast_mult; /* 快速移动倍率 */ + float move_slow_mult; /* 慢速移动倍率 */ +} CMD_Sensitivity_t; + +/* RC模式映射配置 - 定义开关位置到模式的映射 */ +typedef struct { + /* 左拨杆映射 - 底盘模式 */ + Chassis_Mode_t sw_left_up; + Chassis_Mode_t sw_left_mid; + Chassis_Mode_t sw_left_down; + + /* 右拨杆映射 - 云台/射击模式 */ + Gimbal_Mode_t gimbal_sw_up; + Gimbal_Mode_t gimbal_sw_mid; + Gimbal_Mode_t gimbal_sw_down; +} CMD_RCModeMap_t; + +/* 整体配置 */ +typedef struct { + /* 输入源优先级,索引越小优先级越高 */ + CMD_InputSource_t source_priority[CMD_SRC_NUM]; + + /* 灵敏度设置 */ + CMD_Sensitivity_t sensitivity; + + /* RC模式映射 */ + CMD_RCModeMap_t rc_mode_map; + +} CMD_Config_t; + +/* ========================================================================== */ +/* 主控制上下文 */ +/* ========================================================================== */ + +typedef struct { + float now; + float dt; + uint32_t last_us; +} CMD_Timer_t; + +typedef struct CMD_Context { + /* 配置 */ + CMD_Config_t *config; + + /* 时间 */ + CMD_Timer_t timer; + + /* 当前帧和上一帧的原始输入 */ + CMD_RawInput_t input; + CMD_RawInput_t last_input; + + /* 仲裁后的活跃输入源 */ + CMD_InputSource_t active_source; + + /* 输出 */ + struct { + CMD_ChassisOutput_t chassis; + CMD_GimbalOutput_t gimbal; + CMD_ShootOutput_t shoot; + } output; +} CMD_t; + +/* ========================================================================== */ +/* 主API接口 */ +/* ========================================================================== */ + +/** + * @brief 初始化CMD模块 + * @param ctx CMD上下文 + * @param config 配置指针 + * @return CMD_OK成功,其他失败 + */ +int8_t CMD_Init(CMD_t *ctx, CMD_Config_t *config); + +/** + * @brief 更新所有输入源的数据 + * @param ctx CMD上下文 + * @return CMD_OK成功 + */ +int8_t CMD_UpdateInput(CMD_t *ctx); + +/** + * @brief 执行仲裁,决定使用哪个输入源 + * @param ctx CMD上下文 + * @return 选中的输入源 + */ +int8_t CMD_Arbitrate(CMD_t *ctx); + +/** + * @brief 生成所有模块的控制命令 + * @param ctx CMD上下文 + * @return CMD_OK成功 + */ +int8_t CMD_GenerateCommands(CMD_t *ctx); + +/** + * @brief 一键更新(包含UpdateInput + Arbitrate + GenerateCommands) + * @param ctx CMD上下文 + * @return CMD_OK成功 + */ +int8_t CMD_Update(CMD_t *ctx); + +/* ========================================================================== */ +/* 输出获取接口 */ +/* ========================================================================== */ + +/* 获取底盘命令 */ +static inline Chassis_CMD_t* CMD_GetChassisCmd(CMD_t *ctx) { + return &ctx->output.chassis.cmd; + } + +/* 获取云台命令 */ +static inline Gimbal_CMD_t* CMD_GetGimbalCmd(CMD_t *ctx) { + return &ctx->output.gimbal.cmd; +} + +/* 获取射击命令 */ +static inline Shoot_CMD_t* CMD_GetShootCmd(CMD_t *ctx) { + return &ctx->output.shoot.cmd; +} + +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/module/cmd/cmd_adapter.c b/assets/User_code/module/cmd/cmd_adapter.c new file mode 100644 index 0000000..d8023f6 --- /dev/null +++ b/assets/User_code/module/cmd/cmd_adapter.c @@ -0,0 +1,184 @@ +/* + * CMD 模块 V2 - 输入适配器实现 + */ +#include "cmd_adapter.h" +#include + +/* ========================================================================== */ +/* 适配器存储 */ +/* ========================================================================== */ +// static CMD_InputAdapter_t *g_adapters[CMD_SRC_NUM] = {0}; +CMD_InputAdapter_t *g_adapters[CMD_SRC_NUM] = {0}; +/* ========================================================================== */ +/* DR16 抽象实现 */ +/* ========================================================================== */ +#if CMD_RC_DEVICE_TYPE == 0 + +int8_t CMD_DR16_Init(void *data) { + DR16_t *dr16 = (DR16_t *)data; + return DR16_Init(dr16); +} + +int8_t CMD_DR16_RC_GetInput(void *data, CMD_RawInput_t *output) { + DR16_t *dr16 = (DR16_t *)data; + + memset(&output->rc, 0, sizeof(CMD_RawInput_RC_t)); + + output->online[CMD_SRC_RC] = dr16->header.online; + + /* 遥控器摇杆映射 */ + output->rc.joy_left.x = dr16->data.rc.ch_l_x; + output->rc.joy_left.y = dr16->data.rc.ch_l_y; + output->rc.joy_right.x = dr16->data.rc.ch_r_x; + output->rc.joy_right.y = dr16->data.rc.ch_r_y; + + /* 拨杆映射 */ + switch (dr16->data.rc.sw_l) { + case DR16_SW_UP: output->rc.sw[0] = CMD_SW_UP; break; + case DR16_SW_MID: output->rc.sw[0] = CMD_SW_MID; break; + case DR16_SW_DOWN: output->rc.sw[0] = CMD_SW_DOWN; break; + default: output->rc.sw[0] = CMD_SW_ERR; break; + } + switch (dr16->data.rc.sw_r) { + case DR16_SW_UP: output->rc.sw[1] = CMD_SW_UP; break; + case DR16_SW_MID: output->rc.sw[1] = CMD_SW_MID; break; + case DR16_SW_DOWN: output->rc.sw[1] = CMD_SW_DOWN; break; + default: output->rc.sw[1] = CMD_SW_ERR; break; + } + + /* 拨轮映射 */ + output->rc.dial = dr16->data.rc.ch_res; + + return CMD_OK; +} + +int8_t CMD_DR16_PC_GetInput(void *data, CMD_RawInput_t *output) { + DR16_t *dr16 = (DR16_t *)data; + + memset(&output->pc, 0, sizeof(CMD_RawInput_PC_t)); + + output->online[CMD_SRC_PC] = dr16->header.online; + + /* PC端鼠标映射 */ + output->pc.mouse.x = dr16->data.pc.mouse.x; + output->pc.mouse.y = dr16->data.pc.mouse.y; + output->pc.mouse.l_click = dr16->data.pc.mouse.l_click; + output->pc.mouse.r_click = dr16->data.pc.mouse.r_click; + + /* 键盘映射 */ + output->pc.keyboard.bitmap = dr16->raw_data.key; + + return CMD_OK; +} + +bool CMD_DR16_IsOnline(void *data) { + DR16_t *dr16 = (DR16_t *)data; + return dr16->header.online; +} +extern DR16_t cmd_dr16; +/* 定义适配器实例 */ +CMD_DEFINE_ADAPTER(DR16_RC, cmd_dr16, CMD_SRC_RC, CMD_DR16_Init, CMD_DR16_RC_GetInput, CMD_DR16_IsOnline) +CMD_DEFINE_ADAPTER(DR16_PC, cmd_dr16, CMD_SRC_PC, CMD_DR16_Init, CMD_DR16_PC_GetInput, CMD_DR16_IsOnline) + +#endif /* CMD_RC_DEVICE_TYPE == 0 */ + +/* ========================================================================== */ +/* AT9S 抽象实现 (示例框架) */ +/* ========================================================================== */ +#if CMD_RC_DEVICE_TYPE == 1 + +int8_t CMD_AT9S_Init(void *data) { + AT9S_t *at9s = (AT9S_t *)data; + return AT9S_Init(at9s); +} + +int8_t CMD_AT9S_GetInput(void *data, CMD_RawInput_t *output) { + AT9S_t *at9s = (AT9S_t *)data; + + memset(output, 0, sizeof(CMD_RawInput_RC_t)); + + output->online[CMD_SRC_RC] = at9s->header.online; + + /* TODO: 按照AT9S的数据格式进行映射 */ + output->joy_left.x = at9s->data.rc.ch_l_x; + output->joy_left.y = at9s->data.rc.ch_l_y; + output->joy_right.x = at9s->data.rc.ch_r_x; + output->joy_right.y = at9s->data.rc.ch_r_y; + + /* 拨杆映射需要根据AT9S的实际定义 */ + + return CMD_OK; +} + +bool CMD_AT9S_IsOnline(void *data) { + AT9S_t *at9s = (AT9S_t *)data; + return at9s->header.online; +} + +CMD_DEFINE_ADAPTER(AT9S, at9s, CMD_SRC_RC, CMD_AT9S_Init, CMD_AT9S_GetInput, CMD_AT9S_IsOnline) + +#endif /* CMD_RC_DEVICE_TYPE == 1 */ + +/* ========================================================================== */ +/* 适配器管理实现 */ +/* ========================================================================== */ + +int8_t CMD_Adapter_Register(CMD_InputAdapter_t *adapter) { + if (adapter == NULL || adapter->source >= CMD_SRC_NUM) { + return CMD_ERR_NULL; + } + g_adapters[adapter->source] = adapter; + return CMD_OK; +} + +int8_t CMD_Adapter_InitAll(void) { + /* 注册编译时选择的RC设备适配器 */ +#if CMD_RC_DEVICE_TYPE == 0 + /* DR16 支持 RC 和 PC 输入 */ + CMD_Adapter_Register(&g_adapter_DR16_RC); + CMD_Adapter_Register(&g_adapter_DR16_PC); +#elif CMD_RC_DEVICE_TYPE == 1 + /* AT9S 目前只支持 RC 输入 */ + CMD_Adapter_Register(&g_adapter_AT9S); +#endif + + /* 注册NUC适配器 */ + + /* 注册REF适配器 */ + + /* 初始化所有已注册的适配器 */ + for (int i = 0; i < CMD_SRC_NUM; i++) { + if (g_adapters[i] != NULL && g_adapters[i]->init != NULL) { + g_adapters[i]->init(g_adapters[i]->device_data); + } + } + + return CMD_OK; +} + +int8_t CMD_Adapter_GetInput(CMD_InputSource_t source, CMD_RawInput_t *output) { + if (source >= CMD_SRC_NUM || output == NULL) { + return CMD_ERR_NULL; + } + + CMD_InputAdapter_t *adapter = g_adapters[source]; + if (adapter == NULL || adapter->get_input == NULL) { + output->online[adapter->source] = false; + return CMD_ERR_NO_INPUT; + } + + return adapter->get_input(adapter->device_data, output); +} + +bool CMD_Adapter_IsOnline(CMD_InputSource_t source) { + if (source >= CMD_SRC_NUM) { + return false; + } + + CMD_InputAdapter_t *adapter = g_adapters[source]; + if (adapter == NULL || adapter->is_online == NULL) { + return false; + } + + return adapter->is_online(adapter->device_data); +} diff --git a/assets/User_code/module/cmd/cmd_adapter.h b/assets/User_code/module/cmd/cmd_adapter.h new file mode 100644 index 0000000..4fbbc47 --- /dev/null +++ b/assets/User_code/module/cmd/cmd_adapter.h @@ -0,0 +1,111 @@ +/* + * CMD 模块 V2 - 输入适配器接口 + * 定义设备到统一输入结构的转换接口 + */ +#pragma once + +#include "cmd_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* 适配器接口定义 */ +/* ========================================================================== */ + +/* 适配器操作函数指针类型 */ +typedef int8_t (*CMD_AdapterInitFunc)(void *device_data); +typedef int8_t (*CMD_AdapterGetInputFunc)(void *device_data, CMD_RawInput_t *output); +typedef bool (*CMD_AdapterIsOnlineFunc)(void *device_data); + +/* 适配器描述结构 */ +typedef struct { + const char *name; /* 适配器名称 */ + CMD_InputSource_t source; /* 对应的输入源 */ + void *device_data; /* 设备数据指针 */ + CMD_AdapterInitFunc init; /* 初始化函数 */ + CMD_AdapterGetInputFunc get_input; /* 获取输入函数 */ + CMD_AdapterIsOnlineFunc is_online; /* 在线检测函数 */ +} CMD_InputAdapter_t; + +/* ========================================================================== */ +/* 适配器注册宏 */ +/* ========================================================================== */ + +/* + * 声明适配器 + * 使用示例: + * CMD_DECLARE_ADAPTER(DR16, dr16, DR16_t) + * + * 会生成: + * - extern DR16_t dr16; // 设备实例声明 + * - int8_t CMD_DR16_Init(void *data); + * - int8_t CMD_DR16_GetInput(void *data, CMD_RawInput_t *output); + * - bool CMD_DR16_IsOnline(void *data); + */ +#define CMD_DECLARE_ADAPTER(NAME, var, TYPE) \ + extern TYPE var; \ + int8_t CMD_##NAME##_Init(void *data); \ + int8_t CMD_##NAME##_GetInput(void *data, CMD_RawInput_t *output); \ + bool CMD_##NAME##_IsOnline(void *data); + +/* + * 定义适配器实例 + * 使用示例: + * CMD_DEFINE_ADAPTER(DR16_RC, dr16, CMD_SRC_RC, CMD_DR16_Init, CMD_DR16_RC_GetInput, CMD_DR16_RC_IsOnline) + */ +#define CMD_DEFINE_ADAPTER(NAME, var, source_enum, init_func, get_func, online_func) \ + static CMD_InputAdapter_t g_adapter_##NAME = { \ + .name = #NAME, \ + .source = source_enum, \ + .device_data = (void*)&var, \ + .init = init_func, \ + .get_input = get_func, \ + .is_online = online_func, \ + }; + +/* ========================================================================== */ +/* RC设备适配器配置 */ +/* ========================================================================== */ + +/* 选择使用的RC设备 - 只需修改这里 */ +#define CMD_RC_DEVICE_TYPE 0 /* 0:DR16, 1:AT9S, 2:VT13 */ + +#if CMD_RC_DEVICE_TYPE == 0 + #include "device/dr16.h" + CMD_DECLARE_ADAPTER(DR16_RC, dr16, DR16_t) + CMD_DECLARE_ADAPTER(DR16_PC, dr16, DR16_t) + #define CMD_RC_ADAPTER_NAME DR16 + #define CMD_RC_ADAPTER_VAR dr16 +#elif CMD_RC_DEVICE_TYPE == 1 + #include "device/at9s_pro.h" + CMD_DECLARE_ADAPTER(AT9S, at9s, AT9S_t) + #define CMD_RC_ADAPTER_NAME AT9S + #define CMD_RC_ADAPTER_VAR at9s +#elif CMD_RC_DEVICE_TYPE == 2 + #include "device/vt13.h" + CMD_DECLARE_ADAPTER(VT13, vt13, VT13_t) + #define CMD_RC_ADAPTER_NAME VT13 + #define CMD_RC_ADAPTER_VAR vt13 +#endif + +/* ========================================================================== */ +/* 适配器管理接口 */ +/* ========================================================================== */ + +/* 初始化所有适配器 */ +int8_t CMD_Adapter_InitAll(void); + +/* 获取指定输入源的原始输入 */ +int8_t CMD_Adapter_GetInput(CMD_InputSource_t source, CMD_RawInput_t *output); + +/* 检查输入源是否在线 */ +bool CMD_Adapter_IsOnline(CMD_InputSource_t source); + +/* 注册适配器 (运行时注册,可选) */ +int8_t CMD_Adapter_Register(CMD_InputAdapter_t *adapter); + +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/module/cmd/cmd_behavior.c b/assets/User_code/module/cmd/cmd_behavior.c new file mode 100644 index 0000000..92b24bd --- /dev/null +++ b/assets/User_code/module/cmd/cmd_behavior.c @@ -0,0 +1,172 @@ +/* + * CMD 模块 V2 - 行为处理器实现 + */ +#include "cmd_behavior.h" +#include "cmd.h" +#include "module/gimbal.h" +#include + +/* ========================================================================== */ +/* 行为回调函数 */ +/* ========================================================================== */ + +/* 行为处理函数实现 */ +int8_t CMD_Behavior_Handle_FORE(CMD_t *ctx) { + ctx->output.chassis.cmd.ctrl_vec.vy += ctx->config->sensitivity.move_sens; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_BACK(CMD_t *ctx) { + ctx->output.chassis.cmd.ctrl_vec.vy -= ctx->config->sensitivity.move_sens; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_LEFT(CMD_t *ctx) { + ctx->output.chassis.cmd.ctrl_vec.vx -= ctx->config->sensitivity.move_sens; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_RIGHT(CMD_t *ctx) { + ctx->output.chassis.cmd.ctrl_vec.vx += ctx->config->sensitivity.move_sens; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_ACCELERATE(CMD_t *ctx) { + ctx->output.chassis.cmd.ctrl_vec.vx *= ctx->config->sensitivity.move_fast_mult; + ctx->output.chassis.cmd.ctrl_vec.vy *= ctx->config->sensitivity.move_fast_mult; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_DECELERATE(CMD_t *ctx) { + ctx->output.chassis.cmd.ctrl_vec.vx *= ctx->config->sensitivity.move_slow_mult; + ctx->output.chassis.cmd.ctrl_vec.vy *= ctx->config->sensitivity.move_slow_mult; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_FIRE(CMD_t *ctx) { + ctx->output.shoot.cmd.firecmd = true; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_FIRE_MODE(CMD_t *ctx) { + ctx->output.shoot.cmd.mode = (ctx->output.shoot.cmd.mode + 1) % SHOOT_MODE_NUM; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_ROTOR(CMD_t *ctx) { + ctx->output.chassis.cmd.mode = CHASSIS_MODE_ROTOR; + ctx->output.chassis.cmd.mode_rotor = ROTOR_MODE_RAND; + ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELATIVE; + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_AUTOAIM(CMD_t *ctx) { + /* TODO: 自瞄模式切换 */ + return CMD_OK; +} + +int8_t CMD_Behavior_Handle_CHECKSOURCERCPC(CMD_t *ctx) { + /* TODO: 切换RC和PC输入源 */ + if (ctx->active_source == CMD_SRC_PC) { + ctx->active_source = CMD_SRC_RC; + ctx->output.chassis.source = CMD_SRC_RC; + ctx->output.gimbal.source = CMD_SRC_RC; + ctx->output.shoot.source = CMD_SRC_RC; + } else if(ctx->active_source == CMD_SRC_RC) { + ctx->active_source = CMD_SRC_PC; + ctx->output.chassis.source = CMD_SRC_PC; + ctx->output.gimbal.source = CMD_SRC_PC; + ctx->output.shoot.source = CMD_SRC_PC; + } + return CMD_OK; +} + +/* 行为配置表 - 由宏生成 */ +static const CMD_BehaviorConfig_t g_behavior_configs[] = { + CMD_BEHAVIOR_TABLE(BUILD_BEHAVIOR_CONFIG) +}; + +/* ========================================================================== */ +/* API实现 */ +/* ========================================================================== */ + +int8_t CMD_Behavior_Init(void) { + /* 当前静态配置,无需初始化 */ + return CMD_OK; +} + +bool CMD_Behavior_IsTriggered(const CMD_RawInput_t *current, + const CMD_RawInput_t *last, + const CMD_BehaviorConfig_t *config) { + if (config == NULL || current == NULL) { + return false; + } + + bool now_pressed = false; + bool last_pressed = false; + + // 鼠标特殊按键处理 + if (config->key == (CMD_KEY_L_CLICK)) { + now_pressed = current->pc.mouse.l_click; + last_pressed = last ? last->pc.mouse.l_click : false; + } else if (config->key == (CMD_KEY_R_CLICK)) { + now_pressed = current->pc.mouse.r_click; + last_pressed = last ? last->pc.mouse.r_click : false; + } else if (config->key == (CMD_KEY_M_CLICK)) { + now_pressed = current->pc.mouse.m_click; + last_pressed = last ? last->pc.mouse.m_click : false; + } else if (config->key == 0) { + return false; + } else { + // 多按键组合检测 + now_pressed = ((current->pc.keyboard.bitmap & config->key) == config->key); + last_pressed = last ? ((last->pc.keyboard.bitmap & config->key) == config->key) : false; + } + + switch (config->trigger) { + case CMD_ACTIVE_PRESSED: + return now_pressed; + case CMD_ACTIVE_RISING_EDGE: + return now_pressed && !last_pressed; + case CMD_ACTIVE_FALLING_EDGE: + return !now_pressed && last_pressed; + default: + return false; + } +} + +int8_t CMD_Behavior_ProcessAll(CMD_t *ctx, + const CMD_RawInput_t *current, + const CMD_RawInput_t *last, + CMD_ModuleMask_t active_modules) { + if (ctx == NULL || current == NULL) { + return CMD_ERR_NULL; + } + + for (size_t i = 0; i < BEHAVIOR_CONFIG_COUNT; i++) { + const CMD_BehaviorConfig_t *config = &g_behavior_configs[i]; + + /* 过滤模块掩码 */ + if ((config->module_mask & active_modules) == 0) { + continue; + } + + /* 检查是否触发 */ + if (CMD_Behavior_IsTriggered(current, last, config)) { + if (config->handler != NULL) { + config->handler(ctx); + } + } + } + + return CMD_OK; +} + +const CMD_BehaviorConfig_t* CMD_Behavior_GetConfig(CMD_Behavior_t behavior) { + for (size_t i = 0; i < BEHAVIOR_CONFIG_COUNT; i++) { + if (g_behavior_configs[i].behavior == behavior) { + return &g_behavior_configs[i]; + } + } + return NULL; +} diff --git a/assets/User_code/module/cmd/cmd_behavior.h b/assets/User_code/module/cmd/cmd_behavior.h new file mode 100644 index 0000000..fda9074 --- /dev/null +++ b/assets/User_code/module/cmd/cmd_behavior.h @@ -0,0 +1,69 @@ +/* + * CMD 模块 V2 - 行为处理器 + * 实现PC端按键到行为的映射和处理 + */ +#pragma once + +#include "cmd_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* 行为处理器接口 */ +/* ========================================================================== */ + +/* 行为处理函数类型 */ +struct CMD_Context; /* 前向声明 */ +typedef int8_t (*CMD_BehaviorHandler)(struct CMD_Context *ctx); + +/* 行为配置项 */ +typedef struct { + CMD_Behavior_t behavior; /* 行为枚举 */ + uint32_t key; /* 绑定的按键 */ + CMD_TriggerType_t trigger; /* 触发类型 */ + CMD_ModuleMask_t module_mask; /* 影响的模块 */ + CMD_BehaviorHandler handler; /* 处理函数 */ +} CMD_BehaviorConfig_t; + +/* ========================================================================== */ +/* 行为表生成宏 */ +/* ========================================================================== */ + +/* 从宏表生成配置数组 */ +#define BUILD_BEHAVIOR_CONFIG(name, key, trigger, mask) \ + { CMD_BEHAVIOR_##name, key, trigger, mask, CMD_Behavior_Handle_##name }, + +/* 声明所有行为处理函数 */ +#define DECLARE_BEHAVIOR_HANDLER(name, key, trigger, mask) \ + int8_t CMD_Behavior_Handle_##name(struct CMD_Context *ctx); + +/* 展开声明 */ +CMD_BEHAVIOR_TABLE(DECLARE_BEHAVIOR_HANDLER) +#undef DECLARE_BEHAVIOR_HANDLER + +/* ========================================================================== */ +/* 行为处理器API */ +/* ========================================================================== */ + +/* 初始化行为处理器 */ +int8_t CMD_Behavior_Init(void); + +/* 检查行为是否被触发 */ +bool CMD_Behavior_IsTriggered(const CMD_RawInput_t *current, + const CMD_RawInput_t *last, + const CMD_BehaviorConfig_t *config); + +/* 处理所有触发的行为 */ +int8_t CMD_Behavior_ProcessAll(struct CMD_Context *ctx, + const CMD_RawInput_t *current, + const CMD_RawInput_t *last, + CMD_ModuleMask_t active_modules); + +/* 获取行为配置 */ +const CMD_BehaviorConfig_t* CMD_Behavior_GetConfig(CMD_Behavior_t behavior); + +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/module/cmd/cmd_example.c b/assets/User_code/module/cmd/cmd_example.c new file mode 100644 index 0000000..dbea4b0 --- /dev/null +++ b/assets/User_code/module/cmd/cmd_example.c @@ -0,0 +1,144 @@ +/* + * CMD 模块 V2 - 使用示例和配置模板 + * + * 本文件展示如何配置和使用新的CMD模块 + */ +#include "cmd.h" + +/* ========================================================================== */ +/* 配置示例 */ +/* ========================================================================== */ + +/* 默认配置 */ +// static CMD_Config_t g_cmd_config = { +// /* 灵敏度设置 */ +// .sensitivity = { +// .mouse_sens = 0.8f, +// .move_sens = 1.0f, +// .move_fast_mult = 1.5f, +// .move_slow_mult = 0.5f, +// }, + +// /* RC拨杆模式映射 */ +// .rc_mode_map = { +// /* 左拨杆控制底盘模式 */ +// .sw_left_up = CHASSIS_MODE_BREAK, +// .sw_left_mid = CHASSIS_MODE_FOLLOW_GIMBAL, +// .sw_left_down = CHASSIS_MODE_ROTOR, + +// /* 用于云台模式 */ +// .gimbal_sw_up = GIMBAL_MODE_ABSOLUTE, +// .gimbal_sw_mid = GIMBAL_MODE_ABSOLUTE, +// .gimbal_sw_down = GIMBAL_MODE_RELATIVE, +// }, + +// }; + +// /* CMD上下文 */ +// static CMD_t g_cmd_ctx; + +/* ========================================================================== */ +/* 任务示例 */ +/* ========================================================================== */ + +/* + * 初始化示例 + */ +// void Example_CMD_Init(void) { +// CMD_Init(&g_cmd_ctx, &g_cmd_config); +// } + +// /* +// * 任务循环示例 +// */ +// void Example_CMD_Task(void) { +// /* 一键更新 */ +// CMD_Update(&g_cmd_ctx); + +// /* 获取命令发送到各模块 */ +// Chassis_CMD_t *chassis_cmd = CMD_GetChassisCmd(&g_cmd_ctx); +// Gimbal_CMD_t *gimbal_cmd = CMD_GetGimbalCmd(&g_cmd_ctx); +// Shoot_CMD_t *shoot_cmd = CMD_GetShootCmd(&g_cmd_ctx); + +// /* 使用命令... */ +// (void)chassis_cmd; +// (void)gimbal_cmd; +// (void)shoot_cmd; +// } + +/* ========================================================================== */ +/* 架构说明 */ +/* ========================================================================== */ + +/* + * ## 新架构优势 + * + * ### 1. 统一的输入抽象层 (CMD_RawInput_t) + * - 所有设备(DR16/AT9S/VT13等)都转换成相同格式 + * - 上层代码无需关心具体设备类型 + * - 添加新设备只需实现适配器,不改动主逻辑 + * + * ### 2. 适配器模式 + * - 每个设备一个适配器文件 + * - 实现 Init, GetInput, IsOnline 三个函数 + * - 通过宏选择编译哪个适配器 + * + * ### 3. X-Macro配置表 + * - CMD_INPUT_SOURCE_TABLE: 配置输入源 + * - CMD_OUTPUT_MODULE_TABLE: 配置输出模块 + * - CMD_BEHAVIOR_TABLE: 配置按键行为映射 + * - 编译时生成枚举、配置数组、处理函数 + * + * ### 4. 行为驱动设计 + * - 行为与按键解耦 + * - 运行时可修改映射 + * - 支持边沿触发和持续触发 + * + * ### 5. 清晰的分层 + * + * ┌──────────────────────────────────────┐ + * │ 应用层 (cmd.c) │ + * │ - CMD_Update() │ + * │ - 仲裁、命令生成 │ + * └──────────────┬───────────────────────┘ + * │ + * ┌──────────────▼───────────────────────┐ + * │ 行为处理层 (cmd_behavior.c) │ + * │ - 按键触发检测 │ + * │ - 行为函数调用 │ + * └──────────────┬───────────────────────┘ + * │ + * ┌──────────────▼──────────────────────────┐ + * │ 抽象输入层 (cmd_types.h) │ + * │ - 多输入源操作同一CMD_RawInput_t不同分区 │ + * │ - 统一的摇杆、开关、键鼠结构 │ + * └──────────────┬──────────────────────────┘ + * │ + * ┌──────────────▼───────────────────────┐ + * │ 适配器层 (cmd_adapter.c) │ + * │ - DR16_Adapter │ + * │ - AT9S_Adapter │ + * │ - 设备数据 → CMD_RawInput_t │ + * └──────────────────────────────────────┘ + * + * ## 扩展指南 + * + * ### 添加新遥控器设备 + * 1. 在 cmd_adapter.h 中添加宏定义选项 + * 2. 在 cmd_adapter.c 中实现三个适配器函数 + * 3. 修改 CMD_RC_DEVICE_TYPE 宏选择新设备 + * + * ### 添加新输入源(如自定义协议) + * 1. 在 CMD_INPUT_SOURCE_TABLE 添加条目 + * 2. 实现对应的适配器 + * 3. 在 CMD_GenerateCommands 添加处理分支 + * + * ### 添加新行为 + * 1. 在 CMD_BEHAVIOR_TABLE 添加条目,并修正BEHAVIOR_CONFIG_COUNT + * 2. 实现 CMD_Behavior_Handle_XXX 函数 + * + * ### 添加新输出模块 + * 1. 在 CMD_OUTPUT_MODULE_TABLE 添加条目 + * 2. 在 CMD_t 中添加输出成员 + * 3. 实现对应的 BuildXXXCmd 函数 + */ diff --git a/assets/User_code/module/cmd/cmd_types.h b/assets/User_code/module/cmd/cmd_types.h new file mode 100644 index 0000000..961ea29 --- /dev/null +++ b/assets/User_code/module/cmd/cmd_types.h @@ -0,0 +1,196 @@ +/* + * CMD 模块 V2 - 类型定义 + * 统一的输入/输出抽象层 + */ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* 错误码定义 */ +/* ========================================================================== */ +#define CMD_OK (0) +#define CMD_ERR_NULL (-1) +#define CMD_ERR_MODE (-2) +#define CMD_ERR_SOURCE (-3) +#define CMD_ERR_NO_INPUT (-4) + +/* ========================================================================== */ +/* 输入源配置宏表 */ +/* ========================================================================== */ +/* + * 使用方法:在config中定义需要启用的输入源 + * 格式: X(枚举名, 优先级, 适配器初始化函数, 获取数据函数) + */ +#define CMD_INPUT_SOURCE_TABLE(X) \ + X(RC, CMD_RC_AdapterInit, CMD_RC_GetInput) \ + X(PC, CMD_PC_AdapterInit, CMD_PC_GetInput) \ + X(NUC, CMD_NUC_AdapterInit, CMD_NUC_GetInput) \ + X(REF, CMD_REF_AdapterInit, CMD_REF_GetInput) + +/* 输出模块配置宏表 */ +#define CMD_OUTPUT_MODULE_TABLE(X) \ + X(CHASSIS, Chassis_CMD_t, chassis) \ + X(GIMBAL, Gimbal_CMD_t, gimbal) \ + X(SHOOT, Shoot_CMD_t, shoot) + + +/* ========================================================================== */ +/* 输入源枚举 */ +/* ========================================================================== */ +#define ENUM_INPUT_SOURCE(name, ...) CMD_SRC_##name, +typedef enum { + CMD_INPUT_SOURCE_TABLE(ENUM_INPUT_SOURCE) + CMD_SRC_NUM +} CMD_InputSource_t; +#undef ENUM_INPUT_SOURCE + +/* ========================================================================== */ +/* 统一输入数据结构 */ +/* ========================================================================== */ + +/* 摇杆数据 - 统一为-1.0 ~ 1.0 */ +typedef struct { + float x; + float y; +} CMD_Joystick_t; + +/* 开关位置 */ +typedef enum { + CMD_SW_ERR = 0, + CMD_SW_UP, + CMD_SW_MID, + CMD_SW_DOWN, +} CMD_SwitchPos_t; + +/* 鼠标数据 */ +typedef struct { + int16_t x; /* 鼠标X轴移动速度 */ + int16_t y; /* 鼠标Y轴移动速度 */ + int16_t z; /* 鼠标滚轮 */ + bool l_click; /* 左键 */ + bool r_click; /* 右键 */ + bool m_click; /* 中键 */ +} CMD_Mouse_t; + +/* 键盘数据 - 最多支持32个按键 */ +typedef struct { + uint32_t bitmap; /* 按键位图 */ +} CMD_Keyboard_t; + +/* 键盘按键索引 */ +typedef enum { + CMD_KEY_W = (1 << 0), CMD_KEY_S = (1 << 1), CMD_KEY_A = (1 << 2), CMD_KEY_D = (1 << 3), + CMD_KEY_SHIFT = (1 << 4), CMD_KEY_CTRL = (1 << 5), CMD_KEY_Q = (1 << 6), CMD_KEY_E = (1 << 7), + CMD_KEY_R = (1 << 8), CMD_KEY_F = (1 << 9), CMD_KEY_G = (1 << 10), CMD_KEY_Z = (1 << 11), + CMD_KEY_X = (1 << 12), CMD_KEY_C = (1 << 13), CMD_KEY_V = (1 << 14), CMD_KEY_B = (1 << 15), + CMD_KEY_NUM +} CMD_KeyIndex_t; + +/* 裁判系统数据 */ +typedef struct { + uint8_t game_status; /* 比赛状态 */ +} CMD_Referee_t; + +typedef struct { + CMD_Joystick_t joy_left; /* 左摇杆 */ + CMD_Joystick_t joy_right; /* 右摇杆 */ + CMD_SwitchPos_t sw[4]; /* 4个拨杆 */ + float dial; /* 拨轮 */ +} CMD_RawInput_RC_t; + +typedef struct { + CMD_Mouse_t mouse; + CMD_Keyboard_t keyboard; +} CMD_RawInput_PC_t; + +typedef struct { + int a; +} CMD_RawInput_NUC_t; + +typedef struct { + CMD_Referee_t referee; +} CMD_RawInput_REF_t; + +/* 统一的原始输入结构 - 所有设备适配后都转换成这个格式 */ +typedef struct { + bool online[CMD_SRC_NUM]; + + /* 遥控器部分 */ + CMD_RawInput_RC_t rc; + + /* PC部分 */ + CMD_RawInput_PC_t pc; + + /* NUC部分 */ + /* 暂无定义,预留扩展 */ + CMD_RawInput_NUC_t nuc; + + /* REF部分 - 裁判系统数据 */ + CMD_RawInput_REF_t ref; +} CMD_RawInput_t; + +/* ========================================================================== */ +/* 模块掩码 */ +/* ========================================================================== */ +typedef enum { + CMD_MODULE_NONE = (1 << 0), + CMD_MODULE_CHASSIS = (1 << 1), + CMD_MODULE_GIMBAL = (1 << 2), + CMD_MODULE_SHOOT = (1 << 3), + CMD_MODULE_ALL = 0x0E +} CMD_ModuleMask_t; + +/* ========================================================================== */ +/* 行为定义 */ +/* ========================================================================== */ +/* 行为-按键映射宏表 */ +#define BEHAVIOR_CONFIG_COUNT (11) +#define CMD_BEHAVIOR_TABLE(X) \ + X(FORE, CMD_KEY_W, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(BACK, CMD_KEY_S, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(LEFT, CMD_KEY_A, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(RIGHT, CMD_KEY_D, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(ACCELERATE, CMD_KEY_SHIFT, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(DECELERATE, CMD_KEY_CTRL, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(FIRE, CMD_KEY_L_CLICK, CMD_ACTIVE_PRESSED, CMD_MODULE_SHOOT) \ + X(FIRE_MODE, CMD_KEY_B, CMD_ACTIVE_RISING_EDGE, CMD_MODULE_SHOOT) \ + X(ROTOR, CMD_KEY_E, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \ + X(AUTOAIM, CMD_KEY_R, CMD_ACTIVE_RISING_EDGE, CMD_MODULE_GIMBAL | CMD_MODULE_SHOOT) \ + X(CHECKSOURCERCPC, CMD_KEY_CTRL|CMD_KEY_SHIFT|CMD_KEY_V, CMD_ACTIVE_RISING_EDGE, CMD_MODULE_NONE) +/* 触发类型 */ +typedef enum { + CMD_ACTIVE_PRESSED, /* 按住时触发 */ + CMD_ACTIVE_RISING_EDGE, /* 按下瞬间触发 */ + CMD_ACTIVE_FALLING_EDGE, /* 松开瞬间触发 */ +} CMD_TriggerType_t; + +/* 特殊按键值 */ +#define CMD_KEY_NONE 0xFF +#define CMD_KEY_L_CLICK (1 << 31) +#define CMD_KEY_R_CLICK (1 << 30) +#define CMD_KEY_M_CLICK (1 << 29) + +/* 行为枚举 - 由宏表自动生成 */ +#define ENUM_BEHAVIOR(name, key, trigger, mask) CMD_BEHAVIOR_##name, +typedef enum { + CMD_BEHAVIOR_TABLE(ENUM_BEHAVIOR) + CMD_BEHAVIOR_NUM +} CMD_Behavior_t; +#undef ENUM_BEHAVIOR + +/* ========================================================================== */ +/* 键盘辅助宏 */ +/* ========================================================================== */ +#define CMD_KEY_PRESSED(kb, key) (((kb)->bitmap >> (key)) & 1) +#define CMD_KEY_SET(kb, key) ((kb)->bitmap |= (1 << (key))) +#define CMD_KEY_CLEAR(kb, key) ((kb)->bitmap &= ~(1 << (key))) + +#ifdef __cplusplus +} +#endif diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..06d987c --- /dev/null +++ b/build.bat @@ -0,0 +1,51 @@ +@echo off +chcp 65001 > nul +echo ========================================== +echo MRobot 打包脚本 +echo ========================================== +echo. + +REM 清理旧的构建文件 +echo 1. 清理旧的构建文件... +if exist build rmdir /s /q build +if exist dist rmdir /s /q dist +if exist MRobot.spec del /f /q MRobot.spec + +REM 使用 PyInstaller 打包(onedir 模式) +echo. +echo 2. 使用 PyInstaller 打包... +pyinstaller MRobot.py --onedir --windowed --icon=assets\logo\M.ico --name=MRobot --clean + +if %errorlevel% neq 0 ( + echo. + echo ❌ PyInstaller 打包失败! + pause + exit /b 1 +) + +echo. +echo 3. 检查打包结果... +if not exist "dist\MRobot" ( + echo ❌ 未找到 dist\MRobot 目录! + pause + exit /b 1 +) + +if not exist "dist\MRobot\MRobot.exe" ( + echo ❌ 未找到 MRobot.exe! + pause + exit /b 1 +) + +echo. +echo ✅ PyInstaller 打包完成! +echo. +echo 4. 下一步: +echo - 如果要创建安装程序,请运行 Inno Setup 编译 MRobot.iss +echo - 或者直接使用 dist\MRobot 文件夹中的程序 +echo. +echo ========================================== +echo 打包完成 +echo ========================================== +echo. +pause diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..3b59ed0 --- /dev/null +++ b/build.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# MRobot 打包脚本 +# 使用方法: chmod +x build.sh && ./build.sh + +echo "==========================================" +echo " MRobot 打包脚本" +echo "==========================================" +echo "" + +# 清理旧的构建文件 +echo "1. 清理旧的构建文件..." +rm -rf build dist *.spec + +# 使用 PyInstaller 打包(onedir 模式) +echo "" +echo "2. 使用 PyInstaller 打包..." +pyinstaller MRobot.py \ + --onedir \ + --windowed \ + --icon=assets/logo/M.ico \ + --name=MRobot \ + --clean + +if [ $? -ne 0 ]; then + echo "" + echo "❌ PyInstaller 打包失败!" + exit 1 +fi + +echo "" +echo "3. 检查打包结果..." +if [ ! -d "dist/MRobot" ]; then + echo "❌ 未找到 dist/MRobot 目录!" + exit 1 +fi + +if [ ! -f "dist/MRobot/MRobot.exe" ]; then + echo "❌ 未找到 MRobot.exe!" + exit 1 +fi + +echo "" +echo "✅ PyInstaller 打包完成!" +echo "" +echo "4. 下一步:" +echo " - 如果要创建安装程序,请运行 Inno Setup 编译 MRobot.iss" +echo " - 或者直接使用 dist/MRobot 文件夹中的程序" +echo "" +echo "==========================================" +echo " 打包完成" +echo "=========================================="