├── .gitignore ├── Board Documentation ├── SimPad_2.PcbDoc ├── SimPad_2_Anniversary_Edition.PcbDoc ├── SimPad_2_Anniversary_Edition_ES.PcbDoc ├── SimPad_Nano.PcbDoc └── SimPad_Nano_Anniversary_Edition.PcbDoc ├── LICENSE ├── README.en.md ├── README.md ├── ROM ├── .gitignore ├── .vscode │ └── settings.json ├── README.md ├── bsp.h ├── ch552.h ├── cvm.c ├── cvm.h ├── cvm_logo.png ├── dev_note.txt ├── fir.c ├── fir.h ├── instr.h ├── main.c ├── make.ps1 ├── rgb.c ├── rgb.h ├── rom.c ├── rom.h ├── simpad_instruction_table.xlsx ├── sys.c ├── sys.h ├── usb.c └── usb.h ├── Schematic Design ├── SimPad_2.pdf ├── SimPad_2_Anniversary_Edition.pdf ├── SimPad_Nano.pdf └── SimPad_Nano_Anniversary_Edition.pdf └── SimHost ├── .gitignore ├── HID.cs ├── HelpForm.Designer.cs ├── HelpForm.cs ├── HelpForm.resx ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── SimHost.csproj ├── SimHost.sln ├── app.config ├── icon.ico ├── icon.png ├── icon.psd └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | # A .gitignore for Keil projects. 2 | # Copy from https://github.com/mrshrdlu/gitignore-keil/blob/master/keil.gitignore 3 | # Taken mostly from http://www.keil.com/support/man/docs/uv4/uv4_b_filetypes.htm 4 | 5 | # User-specific uVision files 6 | *.opt 7 | *.uvopt 8 | *.uvoptx 9 | *.uvgui 10 | *.uvgui.* 11 | *.uvguix.* 12 | 13 | # Listing files 14 | *.cod 15 | *.htm 16 | *.i 17 | *.lst 18 | *.map 19 | *.m51 20 | *.m66 21 | # define exception below if needed 22 | *.scr 23 | 24 | # Object and HEX files 25 | *.axf 26 | *.b[0-3][0-9] 27 | *.hex 28 | *.d 29 | *.crf 30 | *.elf 31 | *.hex 32 | *.h86 33 | *.lib 34 | *.obj 35 | *.o 36 | *.sbr 37 | 38 | # Build files 39 | # define exception below if needed 40 | *.bat 41 | *._ia 42 | *.__i 43 | *._ii 44 | 45 | # Generated output files 46 | /Listings/* 47 | /Objects/* 48 | 49 | # Debugger files 50 | # define exception below if needed 51 | *.ini 52 | 53 | # Other files 54 | *.build_log.htm 55 | *.cdb 56 | *.dep 57 | *.ic 58 | *.lin 59 | *.lnp 60 | *.orc 61 | # define exception below if needed 62 | *.pack 63 | # define exception below if needed 64 | *.pdsc 65 | *.plg 66 | # define exception below if needed 67 | *.sct 68 | *.sfd 69 | *.sfr 70 | 71 | # Miscellaneous 72 | *.tra 73 | *.bin 74 | *.fed 75 | *.l1p 76 | *.l2p 77 | *.iex 78 | 79 | # To explicitly override the above, define any exceptions here; e.g.: 80 | # !my_customized_scatter_file.sct 81 | 82 | # VS code settings 83 | .vscode/* -------------------------------------------------------------------------------- /Board Documentation/SimPad_2.PcbDoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Board Documentation/SimPad_2.PcbDoc -------------------------------------------------------------------------------- /Board Documentation/SimPad_2_Anniversary_Edition.PcbDoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Board Documentation/SimPad_2_Anniversary_Edition.PcbDoc -------------------------------------------------------------------------------- /Board Documentation/SimPad_2_Anniversary_Edition_ES.PcbDoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Board Documentation/SimPad_2_Anniversary_Edition_ES.PcbDoc -------------------------------------------------------------------------------- /Board Documentation/SimPad_Nano.PcbDoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Board Documentation/SimPad_Nano.PcbDoc -------------------------------------------------------------------------------- /Board Documentation/SimPad_Nano_Anniversary_Edition.PcbDoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Board Documentation/SimPad_Nano_Anniversary_Edition.PcbDoc -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # Firmware for SimPad Based on The 8051 Architecture 2 | 3 | ![License AGPL-3.0](https://img.shields.io/github/license/iamapig120/SimPad_firmware_8051.svg) 4 | 5 | [Simplified Chinese](README.md) 6 | 7 | The repository for firmware of SimPad devices designed based on the 8051 architecture. 8 | 9 | [PC-side Configurator](https://github.com/SimDevices-Project/simpad-control-panel) 10 | 11 | ## Compiling 12 | 13 | Currently, you need to get the Keil μVersion C51 in order to compile the firmware correctly. 14 | 15 | ## Files 16 | 17 | You could refer to the following table to find what you're looking for. 18 | 19 | |Folder|Content| 20 | |-|-| 21 | |ROM|Firmware source code| 22 | |Schematic Design|Product PCB schematics| 23 | |Board Documentation|PCB source files| 24 | 25 | ## Editing 26 | 27 | You could find the schematic information from files under the directory `Schematic Design`. Please add new features to SimPad as you prefer! In addition, what you write will have a chance to be pushed to SimPads around the world. 28 | 29 | ## Attention 30 | 31 | You must not use any name, including product name and trademark, that is associated to SimPad and SimDevices for promotional or other purposes. Please be kindly advised. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [New Depository 新仓库](https://github.com/SimDevices-Project/Firmware_8051) 2 | 3 | # SimPad 基于 8051 架构的产品固件 4 | 5 | ![License AGPL-3.0](https://img.shields.io/github/license/iamapig120/SimPad_firmware_8051.svg) 6 | 7 | [English](README.en.md) 8 | 9 | SimPad 系列设备其中使用 8051 架构设计的产品固件仓库。 10 | 11 | [电脑端设置工具](https://github.com/SimDevices-Project/simpad-control-panel) 12 | 13 | ## 编译环境 14 | 15 | 当前,要正确编译固件,您需要拥有 SDCC (http://sdcc.sourceforge.net/) 进行编译。 16 | 17 | ## 文件说明 18 | 19 | 您可以参考以下表格来寻找您要查找的资料。 20 | 21 | |文件夹|内容| 22 | |-|-| 23 | |ROM|固件源代码| 24 | |Schematic Design|产品PCB原理图| 25 | |Board Documentation|PCB源文件| 26 | 27 | ## 参与编辑 28 | 29 | 您可以参考 `Schematic Design` 目录下的文件来得到电路信息,然后参与到固件的编写当中,按照您的想法为 SimPad 添加新的功能和特性吧!此外,您参与编写的固件将通过 SimPad 推送送至全球用户的设备上运行。 30 | 31 | ## 请注意 32 | 33 | 您不能以宣传或其他目的使用有关于 SimPad 及 SimDevices 的产品名称、商标以及称呼,请悉知。 34 | -------------------------------------------------------------------------------- /ROM/.gitignore: -------------------------------------------------------------------------------- 1 | /out -------------------------------------------------------------------------------- /ROM/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.errorSquiggles": "Disabled", 3 | "files.associations": { 4 | "iosfwd": "c", 5 | "xlocale": "c", 6 | "xstring": "c", 7 | "stack": "c", 8 | "iostream": "cpp" 9 | } 10 | } -------------------------------------------------------------------------------- /ROM/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/ROM/README.md -------------------------------------------------------------------------------- /ROM/bsp.h: -------------------------------------------------------------------------------- 1 | #ifndef __BSP_H 2 | #define __BSP_H 3 | 4 | #ifndef __MULTI_COMPILE__ 5 | /* 编译目标设置 开始 */ 6 | #define SIMPAD_V2_AE 7 | //#define SIMPAD_NANO_AE 8 | //#define SIM_KEY 9 | //#define SIMPAD_V2 10 | //#define SIMPAD_NANO 11 | /* 编译目标设置 结束 */ 12 | #endif 13 | 14 | /* 切换至性能模式 */ 15 | //#define PERFORMANCE_MODE 16 | 17 | /* 使能字符串输入模拟指令 */ 18 | //#define INSTR_ENB_STRP 19 | 20 | /* 使能灯光渐变列表 */ 21 | #define RGB_USE_GRAD_LIST 22 | /* 使能简化灯光渐变列表,CH552受存储空间限制,必须打开 */ 23 | #define RGB_GRAD_LIST_LITE 24 | 25 | __sfr __at (0x90) P1; 26 | __sbit __at (0x90) P10; 27 | __sbit __at (0x91) P11; 28 | __sbit __at (0x92) P12; 29 | __sbit __at (0x93) P13; 30 | __sbit __at (0x94) P14; 31 | __sbit __at (0x95) P15; 32 | __sbit __at (0x96) P16; 33 | __sbit __at (0x97) P17; 34 | 35 | __sfr __at (0xB0) P3; 36 | __sbit __at (0xB0) P30; 37 | __sbit __at (0xB1) P31; 38 | __sbit __at (0xB2) P32; 39 | __sbit __at (0xB3) P33; 40 | __sbit __at (0xB4) P34; 41 | __sbit __at (0xB5) P35; 42 | __sbit __at (0xB6) P36; 43 | __sbit __at (0xB7) P37; 44 | 45 | /* 芯片内部存储空间大小 */ 46 | #define FLASH_SIZE 0x80 47 | 48 | /* 板级接口定义,需要注意的是,按键需定义为BTx */ 49 | #if defined(SIMPAD_V2_AE) 50 | #define BT1 P33 51 | #define BT2 P32 52 | #define BT3 P34 53 | #define BT4 P31 54 | #define BT5 P30 55 | #define KEY_COUNT 5 56 | #define LED P12 57 | #define LED_COUNT 4 58 | #elif defined(SIMPAD_NANO_AE) 59 | #define BT1 P15 60 | #define BT2 P17 61 | #define BT3 P16 62 | #define KEY_COUNT 3 63 | #define LED P14 64 | #define LED_COUNT 2 65 | #define HAS_ROM 66 | #define ROM_SIZE 0x800 67 | #define ROM_SDA P11 68 | #define ROM_SCL P10 69 | #define ROM_WP P33 70 | #elif defined(SIM_KEY) 71 | #define BT1 P17 72 | #define KEY_COUNT 1 73 | #define LED P14 74 | #define LED_COUNT 1 75 | #define HAS_ROM 76 | #define ROM_SIZE 0x800 77 | #define ROM_SDA P11 78 | #define ROM_SCL P10 79 | #define ROM_WP P33 80 | #elif defined(SIMPAD_V2) 81 | #define BT1 P32 82 | #define BT2 P33 83 | #define BT3 P11 84 | #define BT4 P10 85 | #define BT5 P34 86 | #define KEY_COUNT 5 87 | #define G1R P15 88 | #define G1G P16 89 | #define G1B P14 90 | #define G2R P13 91 | #define G2G P12 92 | #define G2B P17 93 | #define LED_COUNT 2 94 | #elif defined(SIMPAD_NANO) 95 | #define BT1 P17 96 | #define BT2 P15 97 | #define BT3 P16 98 | #define KEY_COUNT 3 99 | #define LED P14 100 | #define LED_COUNT 2 101 | #else 102 | #error "No board defined!" 103 | #endif 104 | 105 | #endif -------------------------------------------------------------------------------- /ROM/cvm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * NyaSama Core Virtualize Module 3 | * NSDN (C) 2014 - 2020 4 | * Version: 0.01a 5 | **/ 6 | #include "cvm.h" 7 | 8 | #include 9 | 10 | #include "instr.h" 11 | 12 | /* ---------------- 指令注册开始 ---------------- */ 13 | /* 14 | * 指令注册方式: { 函数指针, 指令类型 } 15 | * 其中,指令类型有: 16 | * CVM_OP_NARG 无操作数,长度为1字节 17 | * CVM_OP_DST8 含一个1字节的操作数,长度为2字节 18 | * CVM_OP_DST 含一个1字节的操作数类型和一个2字节的操作数,长度为4字节 19 | * CVM_OP_DST_SRC 含有两个1字节的操作数类型和两个2字节的操作数,并附加一个保留字节,长度为8字节 20 | * 21 | * 指令实现见 instr.h 22 | */ 23 | static __code CVM_FUNC cvmFuncList[] = { 24 | { &__instr_nop, CVM_OP_NARG }, 25 | { &__instr_jmp, CVM_OP_DST8 }, 26 | { &__instr_clr, CVM_OP_NARG }, 27 | { &__instr_prt, CVM_OP_DST8 }, 28 | { &__instr_hidp, CVM_OP_NARG }, 29 | { &__instr_strp, CVM_OP_DST8 }, 30 | { &__instr_out, CVM_OP_DST }, 31 | { &__instr_keyp, CVM_OP_NARG }, 32 | { &__instr_ldi, CVM_OP_DST }, 33 | { &__instr_lde, CVM_OP_DST }, 34 | { &__instr_wri, CVM_OP_DST }, 35 | { &__instr_wre, CVM_OP_DST }, 36 | { &__instr_sleep, CVM_OP_DST }, 37 | { &__instr_led, CVM_OP_DST_SRC }, 38 | { &__instr_time, CVM_OP_DST }, 39 | { &__instr_fade, CVM_OP_DST_SRC }, 40 | { &__instr_trig, CVM_OP_DST }, 41 | { &__instr_rgb, CVM_OP_DST }, 42 | { &__instr_sysrst, CVM_OP_DST }, 43 | { &__instr_reload, CVM_OP_DST }, 44 | { &__instr_iap, CVM_OP_DST } 45 | }; 46 | /* ---------------- 指令注册结束 ---------------- */ 47 | 48 | static __idata bool cvmEndFlag = false; // 解释器结束标志 49 | static __idata cvm_ret (*cvmWDTCallback)() = NULL; // 解释器看门狗回调 50 | static __idata cvm_addr cvmProgCnt = 0; // 程序计数器 51 | #define CVM_JMP_DUMMY 0xFFFF 52 | static __idata cvm_addr cvmJmpAddr = CVM_JMP_DUMMY; // 跳转寄存器 53 | 54 | static __idata CVM_ERR_INFO cvmErrInfo; // 错误指示器 55 | 56 | /* 57 | * 获取错误指示器的指针,用于获取详细的错误信息 58 | */ 59 | CVM_ERR_INFO* cvm_err_info() { 60 | return &cvmErrInfo; 61 | } 62 | 63 | /* 64 | * 终止解释器 65 | */ 66 | void cvm_end() { 67 | cvmEndFlag = true; 68 | } 69 | 70 | /* 71 | * 将跳转寄存器设置为某个地址,解释器将在下个周期跳转 72 | */ 73 | void cvm_jmp(cvm_addr addr) { 74 | cvmJmpAddr = addr; 75 | } 76 | 77 | /* 78 | * 设置解释器看门狗回调 79 | */ 80 | void cvm_wdt(cvm_ret (*callback)()) { 81 | cvmWDTCallback = callback; 82 | } 83 | 84 | /* 85 | * 执行单条指令 86 | */ 87 | cvm_ret cvm_exe(CVM_OP* op) { 88 | #if CVM_FUNC_MAX <= 0xFF 89 | return cvmFuncList[op->op_index].func(op); 90 | #elif defined(CVM_LONGLEN_OP) 91 | #if CVM_FUNC_MAX == 0x1FF 92 | return cvmFuncList[op->op_index | ((op->type_dst_expr & 0x80) << 1)].func(op); 93 | #elif CVM_FUNC_MAX == 0x3FF 94 | return cvmFuncList[op->op_index | ((op->type_dst_expr & 0x80) << 1) | ((op->type_src & 0x80) << 2)].func(op); 95 | #elif CVM_FUNC_MAX == 0x7FF 96 | return cvmFuncList[op->op_index | ((op->type_dst_expr & 0x80) << 1) | ((op->type_src & 0x80) << 2) | ((op->type_ext & 0x80) << 3)].func(op); 97 | #endif 98 | #endif 99 | } 100 | 101 | /* 102 | * 获取下一条指令长度 103 | */ 104 | uint8_t __cvm_get_op_len(uint8_t* code) { 105 | #ifdef CVM_VARLEN_OP 106 | #if CVM_FUNC_MAX <= 0xFF 107 | return cvmFuncList[*code].length; 108 | #elif defined(CVM_LONGLEN_OP) 109 | #if CVM_FUNC_MAX == 0x1FF 110 | return cvmFuncList[*code | ((*(code + 1) & 0x80) << 1)].length; 111 | #elif CVM_FUNC_MAX == 0x3FF 112 | return cvmFuncList[*code | ((*(code + 1) & 0x80) << 1) | ((*(code + 6) & 0x80) << 2)].length; 113 | #elif CVM_FUNC_MAX == 0x7FF 114 | return cvmFuncList[*code | ((*(code + 1) & 0x80) << 1) | ((*(code + 6) & 0x80) << 2) | ((*(code + 11) & 0x80) << 3)].length; 115 | #endif 116 | #endif 117 | #else 118 | return sizeof(CVM_OP); 119 | #endif 120 | } 121 | 122 | #define ___CVM_GET_U32(addr) ((uint32_t) (*(addr) | (*(addr + 1) << 8) | (*(addr + 2) << 16) | (*(addr + 3) << 24))) 123 | #define ___CVM_GET_U16(addr) ((uint16_t) (*(addr) | (*(addr + 1) << 8))) 124 | 125 | /* 126 | * 从二进制码中获取指令结构 127 | * 其中 length 通过 __cvm_get_op_len 得到,op 为输出参数 128 | */ 129 | void __cvm_parse_op(uint8_t* code, uint8_t length, CVM_OP* op) { 130 | memset(op, 0, sizeof(CVM_OP)); 131 | 132 | #ifdef CVM_VARLEN_OP 133 | if (length >= CVM_OP_NARG) { 134 | op->op_index = *code; 135 | #ifdef CVM_LONGLEN_OP 136 | if (length >= CVM_OP_DST8) { 137 | op->type_dst_expr = *(code + 1); 138 | if (length >= CVM_OP_DST) { 139 | op->dst= ___CVM_GET_U32(code + 2); 140 | if (length >= CVM_OP_DST_SRC) { 141 | op->type_src = *(code + 6); 142 | op->src= ___CVM_GET_U32(code + 7); 143 | if (length == CVM_OP_DST_SRC_EXT) { 144 | op->type_ext = *(code + 11); 145 | op->ext= ___CVM_GET_U32(code + 12); 146 | } 147 | } 148 | } 149 | } 150 | #else 151 | if (length >= CVM_OP_DST8) { 152 | op->type_dst_expr = *(code + 1); 153 | if (length >= CVM_OP_DST) { 154 | op->dst= ___CVM_GET_U16(code + 2); 155 | if (length == CVM_OP_DST_SRC) { 156 | op->type_src = *(code + 4); 157 | op->src= ___CVM_GET_U16(code + 5); 158 | } 159 | } 160 | } 161 | #endif 162 | } 163 | #else 164 | if (length == sizeof(CVM_OP)) { 165 | op->op_index = *code; 166 | #ifdef CVM_LONGLEN_OP 167 | op->type_dst_expr = *(code + 1); 168 | op->dst= *(code + 2) | (*(code + 3) << 8) | (*(code + 4) << 16) | (*(code + 5) << 24); 169 | op->type_src = *(code + 6); 170 | op->src= *(code + 7) | (*(code + 8) << 8) | (*(code + 9) << 16) | (*(code + 10) << 24); 171 | op->type_ext = *(code + 11); 172 | op->ext= *(code + 12) | (*(code + 13) << 8) | (*(code + 14) << 16) | (*(code + 15) << 24); 173 | #else 174 | op->type_dst_expr = *(code + 1); 175 | op->dst= *(code + 2) | (*(code + 3) << 8); 176 | op->type_src = *(code + 4); 177 | op->src= *(code + 5) | (*(code + 6) << 8); 178 | op->reversed = 0xFF; 179 | #endif 180 | } 181 | #endif 182 | } 183 | 184 | /* 185 | * 执行二进制程序 186 | * 其中 length 为二进制程序长度 187 | */ 188 | cvm_ret cvm_run(uint8_t* code, cvm_addr length) { 189 | uint8_t op_length = 0; uint8_t* offset = code; 190 | CVM_OP op_body; 191 | cvm_ret result = CVM_RET_OK; 192 | cvmEndFlag = false; 193 | cvmProgCnt = 0; 194 | 195 | memset(&cvmErrInfo, 0, sizeof(CVM_ERR_INFO)); 196 | 197 | while (cvmProgCnt < length) { 198 | if (cvmWDTCallback != NULL) { 199 | result = cvmWDTCallback(); 200 | if (result != CVM_RET_OK) 201 | return CVM_RET_ERR; 202 | } 203 | 204 | if (cvmEndFlag == true) { 205 | cvmEndFlag = false; 206 | break; 207 | } 208 | 209 | offset = code + cvmProgCnt; 210 | 211 | op_length = __cvm_get_op_len(offset); 212 | if (cvmProgCnt + op_length > length) { 213 | cvmErrInfo.msg = 'L'; 214 | cvmErrInfo.addr = cvmProgCnt; 215 | return CVM_RET_ERR; 216 | } 217 | 218 | __cvm_parse_op(offset, op_length, &op_body); 219 | 220 | result = cvm_exe(&op_body); 221 | 222 | if (result == CVM_RET_ERR) { 223 | cvmErrInfo.msg = 'E'; 224 | cvmErrInfo.addr = cvmProgCnt; 225 | memcpy(&(cvmErrInfo.op), &op_body, sizeof(CVM_OP)); 226 | return CVM_RET_ERR; 227 | } 228 | 229 | if (cvmProgCnt >= length) { 230 | cvmErrInfo.msg = 'A'; 231 | cvmErrInfo.addr = cvmProgCnt; 232 | return CVM_RET_ERR; 233 | } 234 | 235 | if (cvmJmpAddr != CVM_JMP_DUMMY) { 236 | if (cvmJmpAddr >= length) { 237 | cvmErrInfo.msg = 'J'; 238 | cvmErrInfo.addr = cvmProgCnt; 239 | memcpy(&(cvmErrInfo.op), &op_body, sizeof(CVM_OP)); 240 | return CVM_RET_ERR; 241 | } 242 | cvmProgCnt = cvmJmpAddr; 243 | cvmJmpAddr = CVM_JMP_DUMMY; 244 | } else { 245 | if (result == CVM_RET_END) 246 | break; 247 | else if (result == CVM_RET_RST) 248 | cvmProgCnt = 0; 249 | else 250 | cvmProgCnt += op_length; 251 | } 252 | } 253 | 254 | return CVM_RET_OK; 255 | } 256 | -------------------------------------------------------------------------------- /ROM/cvm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * NyaSama Core Virtualize Module 3 | * NSDN (C) 2014 - 2020 4 | * Version: 0.01a 5 | **/ 6 | #ifndef __CVM_H_ 7 | #define __CVM_H_ 8 | 9 | 10 | #include 11 | 12 | #define CVM_VER "0.01a" 13 | 14 | /* ---------------- 配置区域开始 ---------------- */ 15 | 16 | #define CVM_FUNC_MAX 0xFF 17 | //#define CVM_FUNC_MAX 0x1FF 18 | //#define CVM_FUNC_MAX 0x3FF 19 | //#define CVM_FUNC_MAX 0x7FF 20 | 21 | /* 使用超过 256 种指令的情况下, 需开启长指令支持, 并关闭变长指令支持 */ 22 | /* 比如: 编号为 0x100 ~ 0x1FF 的指令省略目标操作数的时候会引发错误 */ 23 | #define CVM_VARLEN_OP 24 | //#define CVM_LONGLEN_OP 25 | 26 | #define cvm_ret uint8_t 27 | #define CVM_RET_END 0xFF 28 | #define CVM_RET_RST 0xFE 29 | 30 | #define CVM_RET_OK 0x00 31 | #define CVM_RET_ERR 0x01 32 | 33 | #define cvm_addr uint16_t 34 | 35 | /* ---------------- 配置区域结束 ---------------- */ 36 | 37 | 38 | /* ------------------------------------------------- */ 39 | /* ---------------- 以下内容不应修改 ---------------- */ 40 | /* ------------------------------------------------- */ 41 | 42 | // 目标操作数类型便捷访问宏定义 43 | #define type_dst type_dst_expr 44 | 45 | typedef struct { 46 | uint8_t op_index; // 1 byte, 指令编号低 8 位 47 | uint8_t type_dst_expr; // 1 byte, 低 7 位为目标操作数类型, 或者为双字节指令的操作数 48 | // type_dst & 0x80 1 bit, 指令编号第 9 位, 目前作为保留位 49 | uint32_t dst; // 4 bytes, 立即数或虚拟地址 50 | uint8_t type_src; // 1 byte, 低 7 位为源操作数类型 51 | // type_src & 0x80 1 bit, 指令编号第 10 位, 目前作为保留位 52 | uint32_t src; // 4 bytes, 立即数或虚拟地址 53 | uint8_t type_ext; // 1 byte, 低 7 位为附加操作数类型 54 | // type_ext & 0x80 1 bit, 指令编号第 11 位, 目前作为保留位 55 | uint32_t ext; // 4 bytes, 立即数或虚拟地址 56 | } CVM_OP_L; // 16 bytes 57 | 58 | typedef struct { 59 | uint8_t op_index; // 1 byte, 指令编号 60 | uint8_t type_dst_expr; // 1 byte, 目标操作数类型, 或者为双字节指令的操作数 61 | uint16_t dst; // 2 bytes, 立即数或虚拟地址 62 | uint8_t type_src; // 1 byte, 源操作数类型 63 | uint16_t src; // 2 bytes, 立即数或虚拟地址 64 | uint8_t reversed; // 1 byte, 保留 65 | } CVM_OP_S; // 8 bytes 66 | 67 | #ifdef CVM_VARLEN_OP 68 | #define CVM_OP_NARG 1 69 | #define CVM_OP_DST8 2 70 | #ifdef CVM_LONGLEN_OP 71 | #define CVM_OP_DST 6 72 | #define CVM_OP_DST_SRC 11 73 | #define CVM_OP_DST_SRC_EXT 16 74 | #else 75 | #define CVM_OP_DST 4 76 | #define CVM_OP_DST_SRC 8 77 | #endif 78 | #endif 79 | 80 | #ifdef CVM_LONGLEN_OP 81 | #define CVM_OP CVM_OP_L 82 | typedef uint32_t cvm_arg; 83 | #else 84 | #define CVM_OP CVM_OP_S 85 | typedef uint16_t cvm_arg; 86 | #endif 87 | 88 | typedef struct { 89 | cvm_ret (*func)(CVM_OP* op); 90 | #ifdef CVM_VARLEN_OP 91 | uint8_t length; 92 | #endif 93 | } CVM_FUNC; 94 | 95 | #ifndef CVM_FUNC_MAX 96 | #define CVM_FUNC_MAX 0x80 97 | #endif 98 | 99 | #if CVM_FUNC_MAX > 0xFF 100 | #ifndef CVM_LONGLEN_OP 101 | #error CVM_LONGLEN_OP should be defined. 102 | #endif 103 | #ifdef CVM_VARLEN_OP 104 | #error CVM_VARLEN_OP should not be defined. 105 | #endif 106 | #endif 107 | 108 | #if CVM_FUNC_MAX <= 0xFF 109 | typedef uint8_t cvm_opi; 110 | #else 111 | typedef uint16_t cvm_opi; 112 | #endif 113 | 114 | typedef struct { 115 | char msg; 116 | cvm_addr addr; 117 | CVM_OP op; 118 | } CVM_ERR_INFO; 119 | 120 | CVM_ERR_INFO* cvm_err_info(); 121 | 122 | void cvm_end(); 123 | void cvm_jmp(cvm_addr addr); 124 | cvm_ret cvm_exe(CVM_OP* op); 125 | cvm_ret cvm_run(uint8_t* code, cvm_addr length); 126 | 127 | void cvm_wdt(cvm_ret (*callback)()); 128 | 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /ROM/cvm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/ROM/cvm_logo.png -------------------------------------------------------------------------------- /ROM/dev_note.txt: -------------------------------------------------------------------------------- 1 | ================================================================================================================== 2 | = 数据包定义 3 | ================================================================================================================== 4 | 发送至上位机的包头为0xAA,发送至下位机的包头为0x55 5 | 数据长度为32字节(上位机会接收到33字节) 6 | 7 | ================================================================================================================== 8 | = 指令集(此说明仅针对汇编语言,并非字节码说明,字节码请参看 SimPad固件指令表(simpad_instruction_table.xlsx)) 9 | ================================================================================================================== 10 | 指令码 示意 对应API 说明 11 | ------------------------------------------------------------------------------------------------------------------ 12 | 0x00 nop 空指令 13 | 0x01 jmp addr 直接跳转 14 | 0x02 clr 复位上位机发送缓冲区指针 15 | 0x03 prt char/string 打印到上位机发送缓冲区,指针累加 16 | 0x04 hidp pushHIDData() 将发送缓冲区内数据发送至上位机并清空 17 | 0x05 strp u16 将发送缓冲区内数据按字符串通过模拟按键发送至上位机,按键之间延时r0毫秒 18 | 0x06 out u8a, u8b usbSetKeycode() 将按键数据索引u8a的键值设置为u8b 19 | 0x07 keyp usbPushKeydata()将按键数据发送到上位机 20 | 0x08 ldi u8, u16 romRead8i() 读取内部flash中u16偏移地址到发送缓冲区偏移u8 21 | 0x09 lde u8, u16 romRead8e() 读取外部flash中u16偏移地址到发送缓冲区偏移u8 22 | 0x0A wri u16, u8 romWrite8i() 将u8写入到内部flash中u16偏移地址 23 | 0x0B wre u16, u8 romWrite8e() 将u8写入到外部flash中u16偏移地址 24 | 0x0C sleep u16 delay() 延时毫秒,此指令不应在USB端口执行 25 | 0x0D led u8, u24 rgbSetLed() 将u8序号的led颜色设置为u24,并清空渐变列表 26 | 0x0E time u16 rgbSetTime() 设置渐变持续时间,u16取0则为终止标记 27 | 0x0F fade u8, u24 rgbAddFade() 将u24颜色添加到u8序号的led渐变列表 28 | 0x10 trig u8a, u8b rgbSetTrig() 设置u8a序号的led渐变触发方式,u8b中每一位对应了相应序号的按键使能 29 | 0x11 rgb u8a, u8b rgbSetMode() 设置u8a序号的led为rgb渐变模式 30 | 0x12 sysrst 0x55, 0xAA55 系统软复位 31 | 0x13 reload 0xAA, 0x55AA 重载程序至xRAM 32 | 0x14 iap 0x5A, 0xA55A 进入IAP模式 33 | 34 | ================================================================================================================== 35 | = 存储器地址分配 36 | ================================================================================================================== 37 | 类别 地址(0x00~0x80为内部flash,否则为外部存储器,程序空间需在寄存器之后,如0x0030) 38 | ------------------------------------------------------------------------------------------------------------------ 39 | BTC 0x0000 双字节,按键触发控制,每两位决定一个按键的触发模式(按下,抬起,持续按下,不使用) 40 | BT1 0x0002 双字节,最高位为键值/地址选择位,取0时低8位为键值,取1时低15位为程序地址 41 | BT1L 0x0004 双字节,上述程序长度,上述选择位取0时忽略 42 | BT2 0x0006 双字节,最高位为键值/地址选择位,取0时低8位为键值,取1时低15位为程序地址 43 | BT2L 0x0008 双字节,上述程序长度,上述选择位取0时忽略 44 | BT3 0x000A 双字节,最高位为键值/地址选择位,取0时低8位为键值,取1时低15位为程序地址 45 | BT3L 0x000C 双字节,上述程序长度,上述选择位取0时忽略 46 | BT4 0x000E 双字节,最高位为键值/地址选择位,取0时低8位为键值,取1时低15位为程序地址 47 | BT4L 0x0010 双字节,上述程序长度,上述选择位取0时忽略 48 | BT5 0x0012 双字节,最高位为键值/地址选择位,取0时低8位为键值,取1时低15位为程序地址 49 | BT5L 0x0014 双字节,上述程序长度,上述选择位取0时忽略 50 | LED1 0x0016 双字节,灯光初始化程序地址,为0xFFFF时为单一颜色初始化 51 | LED1L 0x0018 双字节,上述程序长度,上述程序地址为0xFFFF时为RGB565颜色值 52 | LED2 0x001A 双字节,灯光初始化程序地址,为0xFFFF时为单一颜色初始化 53 | LED2L 0x001C 双字节,上述程序长度,上述程序地址为0xFFFF时为RGB565颜色值 54 | LED3 0x001E 双字节,灯光初始化程序地址,为0xFFFF时为单一颜色初始化 55 | LED3L 0x0020 双字节,上述程序长度,上述程序地址为0xFFFF时为RGB565颜色值 56 | LED4 0x0022 双字节,灯光初始化程序地址,为0xFFFF时为单一颜色初始化 57 | LED4L 0x0024 双字节,上述程序长度,上述程序地址为0xFFFF时为RGB565颜色值 58 | LED1EX 0x0026 单字节,LED1的颜色扩展位,从高到低分别为R2 R1 R0 G1 G0 B2 B1 B0 59 | LED2EX 0x0027 单字节,LED2的颜色扩展位,从高到低分别为R2 R1 R0 G1 G0 B2 B1 B0 60 | LED3EX 0x0028 单字节,LED3的颜色扩展位,从高到低分别为R2 R1 R0 G1 G0 B2 B1 B0 61 | LED4EX 0x0029 单字节,LED4的颜色扩展位,从高到低分别为R2 R1 R0 G1 G0 B2 B1 B0 62 | (已分配42字节,内部Data Flash容量为128字节) 63 | 64 | ================================================================================================================== 65 | = 其他说明 66 | ================================================================================================================== 67 | 对于多媒体按键,需手动设置按键数据0为报告ID 2,并置按键数据1为对应的多媒体键值 68 | 69 | ------------------------------------------------------------------------------------------------------------------ 70 | 对于led的按键触发模式设置,指令可放置于灯光宏中,其中r1每一位对应一个按键的使能,即最低位对应BT1的使能,按键之间 71 | 逻辑关系为或 72 | 对于led的rgb渐变模式,取0则不渐变,取1为正常渐变,取2为反向渐变,取3为按键触发切换 73 | 74 | ------------------------------------------------------------------------------------------------------------------ 75 | 对于BTC寄存器,通过两位确定一个按键的触发模式: 76 | 不使用:0x0,按下:0x1,抬起:0x2,持续按下:0x3 77 | 整个双字节如下:(从高到低排列) 78 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 79 | * * * * * * BT5 BT5 BT4 BT4 BT3 BT3 BT2 BT2 BT1 BT1 80 | 其中高6位目前为保留位,暂不使用 81 | 其中,不使用状态为常规键盘按键模式,其余为宏按键模式 82 | 83 | ------------------------------------------------------------------------------------------------------------------ 84 | 在按下和抬起模式中,如果宏指令包含循环结构,并且当前已经有宏程序在循环执行,此时的触发停止对应的循环,不执行宏代码 85 | 在持续按下模式中,如果宏指令包含循环结构,此时的宏执行效果是未知的(如果是死循环宏);一旦抬起按键将中断当前的宏执行 86 | 如果指令执行做成在大循环内单步执行,就可以避免这些问题(解释器循环合并入主循环) 87 | -------------------------------------------------------------------------------- /ROM/fir.c: -------------------------------------------------------------------------------- 1 | #include "fir.h" 2 | 3 | #include "sys.h" 4 | 5 | static __xdata fir_type firBuffer[FIR_SIZE]; // FIR滤波器缓冲 6 | static __xdata uint8_t firResult[FIR_SIZE]; // FIR滤波结果 7 | uint8_t i = 0; 8 | 9 | #define __set_pin(k) do { BT ## k = 1; for (i = 0; i < 10; i++); } while (0) 10 | #define __fifo_in(i, k) do { firBuffer[i] <<= 1; firBuffer[i] |= !BT ## k; } while (0) 11 | 12 | /* 13 | * FIR滤波器更新 14 | */ 15 | void firUpdate() { 16 | fir_type buf = 0; 17 | for (uint8_t i = 0; i < FIR_SIZE; i++) { 18 | firResult[i] = 0; 19 | buf = firBuffer[i]; 20 | while (buf != 0) { 21 | buf = buf & (buf - 1); 22 | firResult[i] += 1; 23 | } 24 | } 25 | 26 | #if defined(SIM_KEY) 27 | __set_pin(1); 28 | __fifo_in(0, 1); 29 | #else 30 | __set_pin(1); 31 | __set_pin(2); 32 | __fifo_in(0, 1); 33 | __fifo_in(1, 2); 34 | #if (defined(SIMPAD_V2_AE) || defined(SIMPAD_V2)) 35 | __set_pin(3); 36 | __set_pin(4); 37 | __set_pin(5); 38 | __fifo_in(2, 3); 39 | __fifo_in(3, 4); 40 | __fifo_in(4, 5); 41 | #elif (defined(SIMPAD_NANO_AE) || defined(SIMPAD_NANO)) 42 | __set_pin(3); 43 | __fifo_in(2, 3); 44 | #endif 45 | #endif 46 | } 47 | 48 | /* 49 | * 获取滤波后的电平状态 50 | */ 51 | __bit fir(uint8_t i) { 52 | return (firResult[i] > sizeof(fir_type) * 4) && 53 | (firBuffer[i] & 0x1 != 0); 54 | } -------------------------------------------------------------------------------- /ROM/fir.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIR_H 2 | #define __FIR_H 3 | 4 | #include "ch552.h" 5 | #include "bsp.h" 6 | 7 | typedef uint16_t fir_type; 8 | #define FIR_SIZE KEY_COUNT 9 | 10 | void firUpdate(); 11 | __bit fir(uint8_t i); 12 | 13 | #endif -------------------------------------------------------------------------------- /ROM/instr.h: -------------------------------------------------------------------------------- 1 | #ifndef __INSTR_H 2 | #define __INSTR_H 3 | 4 | #include "cvm.h" 5 | #include "bsp.h" 6 | #include "rom.h" 7 | #include "sys.h" 8 | #include "usb.h" 9 | #include "rgb.h" 10 | 11 | #ifdef INSTR_ENB_STRP 12 | #define SHIFT 0x80 13 | static uint8_c _asciimap[128] = { // 模拟字符串输入用的查找表 14 | 0x00, // NUL 15 | 0x00, // SOH 16 | 0x00, // STX 17 | 0x00, // ETX 18 | 0x00, // EOT 19 | 0x00, // ENQ 20 | 0x00, // ACK 21 | 0x00, // BEL 22 | 0x2a, // BS Backspace 23 | 0x2b, // TAB ab 24 | 0x28, // LF Enter 25 | 0x00, // VT 26 | 0x00, // FF 27 | 0x00, // CR 28 | 0x00, // SO 29 | 0x00, // SI 30 | 0x00, // DEL 31 | 0x00, // DC1 32 | 0x00, // DC2 33 | 0x00, // DC3 34 | 0x00, // DC4 35 | 0x00, // NAK 36 | 0x00, // SYN 37 | 0x00, // ETB 38 | 0x00, // CAN 39 | 0x00, // EM 40 | 0x00, // SUB 41 | 0x00, // ESC 42 | 0x00, // FS 43 | 0x00, // GS 44 | 0x00, // RS 45 | 0x00, // US 46 | 47 | 0x2c, // ' ' 48 | 0x1e|SHIFT, // ! 49 | 0x34|SHIFT, // " 50 | 0x20|SHIFT, // # 51 | 0x21|SHIFT, // $ 52 | 0x22|SHIFT, // % 53 | 0x24|SHIFT, // & 54 | 0x34, // ' 55 | 0x26|SHIFT, // ( 56 | 0x27|SHIFT, // ) 57 | 0x25|SHIFT, // * 58 | 0x2e|SHIFT, // + 59 | 0x36, // , 60 | 0x2d, // - 61 | 0x37, // . 62 | 0x38, // / 63 | 0x27, // 0 64 | 0x1e, // 1 65 | 0x1f, // 2 66 | 0x20, // 3 67 | 0x21, // 4 68 | 0x22, // 5 69 | 0x23, // 6 70 | 0x24, // 7 71 | 0x25, // 8 72 | 0x26, // 9 73 | 0x33|SHIFT, // : 74 | 0x33, // ; 75 | 0x36|SHIFT, // < 76 | 0x2e, // = 77 | 0x37|SHIFT, // > 78 | 0x38|SHIFT, // ? 79 | 0x1f|SHIFT, // @ 80 | 0x04|SHIFT, // A 81 | 0x05|SHIFT, // B 82 | 0x06|SHIFT, // C 83 | 0x07|SHIFT, // D 84 | 0x08|SHIFT, // E 85 | 0x09|SHIFT, // F 86 | 0x0a|SHIFT, // G 87 | 0x0b|SHIFT, // H 88 | 0x0c|SHIFT, // I 89 | 0x0d|SHIFT, // J 90 | 0x0e|SHIFT, // K 91 | 0x0f|SHIFT, // L 92 | 0x10|SHIFT, // M 93 | 0x11|SHIFT, // N 94 | 0x12|SHIFT, // O 95 | 0x13|SHIFT, // P 96 | 0x14|SHIFT, // Q 97 | 0x15|SHIFT, // R 98 | 0x16|SHIFT, // S 99 | 0x17|SHIFT, // T 100 | 0x18|SHIFT, // U 101 | 0x19|SHIFT, // V 102 | 0x1a|SHIFT, // W 103 | 0x1b|SHIFT, // X 104 | 0x1c|SHIFT, // Y 105 | 0x1d|SHIFT, // Z 106 | 0x2f, // [ 107 | 0x31, // bslash 108 | 0x30, // ] 109 | 0x23|SHIFT, // ^ 110 | 0x2d|SHIFT, // _ 111 | 0x35, // ` 112 | 0x04, // a 113 | 0x05, // b 114 | 0x06, // c 115 | 0x07, // d 116 | 0x08, // e 117 | 0x09, // f 118 | 0x0a, // g 119 | 0x0b, // h 120 | 0x0c, // i 121 | 0x0d, // j 122 | 0x0e, // k 123 | 0x0f, // l 124 | 0x10, // m 125 | 0x11, // n 126 | 0x12, // o 127 | 0x13, // p 128 | 0x14, // q 129 | 0x15, // r 130 | 0x16, // s 131 | 0x17, // t 132 | 0x18, // u 133 | 0x19, // v 134 | 0x1a, // w 135 | 0x1b, // x 136 | 0x1c, // y 137 | 0x1d, // z 138 | 0x2f|SHIFT, // { 139 | 0x31|SHIFT, // | 140 | 0x30|SHIFT, // } 141 | 0x35|SHIFT, // ~ 142 | 0 // DEL 143 | }; 144 | #endif 145 | 146 | volatile uint8_t out_ptr = 0; // HID发送缓冲区指针 147 | volatile __bit dummy; 148 | #define DUMMY_THING(op) (dummy = op->type_dst_expr != 0) // 避免编译器警告 149 | 150 | /* 151 | * 空指令 152 | */ 153 | cvm_ret __instr_nop(CVM_OP* op) { 154 | __asm__("nop"); 155 | DUMMY_THING(op); 156 | return CVM_RET_OK; 157 | } 158 | 159 | /* 160 | * 直接跳转指令 161 | */ 162 | cvm_ret __instr_jmp(CVM_OP* op) { 163 | cvm_jmp(op->dst); 164 | return CVM_RET_OK; 165 | } 166 | 167 | /* 168 | * 清空HID发送缓冲区 169 | */ 170 | cvm_ret __instr_clr(CVM_OP* op) { 171 | for (uint8_t i = 0; i < HID_BUF; i++) 172 | setHIDData(i, 0); 173 | out_ptr = 0; 174 | DUMMY_THING(op); 175 | return CVM_RET_OK; 176 | } 177 | 178 | /* 179 | * 向HID发送缓冲区写入一个字节 180 | */ 181 | cvm_ret __instr_prt(CVM_OP* op) { 182 | setHIDData(out_ptr, op->type_dst_expr); 183 | out_ptr += 1; 184 | return CVM_RET_OK; 185 | } 186 | 187 | /* 188 | * 将HID发送缓冲区内的数据上传 189 | */ 190 | cvm_ret __instr_hidp(CVM_OP* op) { 191 | pushHIDData(); 192 | DUMMY_THING(op); 193 | return __instr_clr(op); 194 | } 195 | 196 | /* 197 | * 将HID接收缓冲区内的数据看作字符串并模拟按键输入 198 | */ 199 | cvm_ret __instr_strp(CVM_OP* op) { 200 | uint8_t t = op->type_dst_expr; 201 | #ifdef INSTR_ENB_STRP 202 | uint8_t c = 0; 203 | for (uint8_t i = 0; i < out_ptr; i++) { 204 | c = getHIDData(i); 205 | c = _asciimap[c]; 206 | usbSetKeycode(0, 1); 207 | usbSetKeycode(1, (c & SHIFT) ? 0x02 : 0x00); 208 | usbSetKeycode(2, c); 209 | usbPushKeydata(); 210 | delay(t / 2); 211 | usbSetKeycode(1, 0); 212 | usbSetKeycode(2, 0); 213 | usbPushKeydata(); 214 | delay(t); 215 | } 216 | #else 217 | delay(t); 218 | #endif 219 | out_ptr = 0; 220 | return CVM_RET_OK; 221 | } 222 | 223 | /* 224 | * 设置键值 225 | */ 226 | cvm_ret __instr_out(CVM_OP* op) { 227 | usbSetKeycode(op->type_dst_expr, op->dst); 228 | return CVM_RET_OK; 229 | } 230 | 231 | /* 232 | * 将按键信息上传 233 | */ 234 | cvm_ret __instr_keyp(CVM_OP* op) { 235 | usbPushKeydata(); 236 | DUMMY_THING(op); 237 | return CVM_RET_OK; 238 | } 239 | 240 | /* 241 | * 将内部存储器中的一个字节存入HID发送缓冲区 242 | */ 243 | cvm_ret __instr_ldi(CVM_OP* op) { 244 | setHIDData(op->type_dst_expr, romRead8i(op->dst)); 245 | return CVM_RET_OK; 246 | } 247 | 248 | /* 249 | * 将外部存储器中的一个字节存入HID发送缓冲区 250 | */ 251 | cvm_ret __instr_lde(CVM_OP* op) { 252 | setHIDData(op->type_dst_expr, romRead8e(op->dst)); 253 | return CVM_RET_OK; 254 | } 255 | 256 | /* 257 | * 将一个字节存入内部存储器 258 | */ 259 | cvm_ret __instr_wri(CVM_OP* op) { 260 | romWrite8i(op->dst, op->type_dst_expr); 261 | return CVM_RET_OK; 262 | } 263 | 264 | /* 265 | * 将一个字节存入外部存储器 266 | */ 267 | cvm_ret __instr_wre(CVM_OP* op) { 268 | romWrite8e(op->dst, op->type_dst_expr); 269 | return CVM_RET_OK; 270 | } 271 | 272 | /* 273 | * 延时一段时间,单位为毫秒 274 | */ 275 | cvm_ret __instr_sleep(CVM_OP* op) { 276 | delay(op->dst); //TODO 277 | return CVM_RET_OK; 278 | } 279 | 280 | /* 281 | * 设置LED的颜色 282 | */ 283 | cvm_ret __instr_led(CVM_OP* op) { 284 | rgbSetLed(op->dst, op->src); 285 | return CVM_RET_OK; 286 | } 287 | 288 | /* 289 | * 设置LED渐变时间 290 | */ 291 | cvm_ret __instr_time(CVM_OP* op) { 292 | rgbSetTime(op->dst); 293 | return CVM_RET_OK; 294 | } 295 | 296 | /* 297 | * 添加LED渐变节点 298 | */ 299 | cvm_ret __instr_fade(CVM_OP* op) { 300 | rgbAddFade(op->dst, op->src); 301 | return CVM_RET_OK; 302 | } 303 | 304 | /* 305 | * 设置LED触发模式 306 | */ 307 | cvm_ret __instr_trig(CVM_OP* op) { 308 | rgbSetTrig(op->type_dst_expr, op->dst); 309 | return CVM_RET_OK; 310 | } 311 | 312 | /* 313 | * 设置LED显示模式 314 | */ 315 | cvm_ret __instr_rgb(CVM_OP* op) { 316 | rgbSetMode(op->type_dst_expr, op->dst); 317 | return CVM_RET_OK; 318 | } 319 | 320 | /* 321 | * 系统软复位 322 | */ 323 | cvm_ret __instr_sysrst(CVM_OP* op) { 324 | if (op->type_dst_expr == 0x55 && op->dst == 0xAA55) { 325 | EA = 0; 326 | SAFE_MOD = 0x55; 327 | SAFE_MOD = 0xAA; 328 | GLOBAL_CFG |= bSW_RESET; 329 | return CVM_RET_OK; 330 | } 331 | return CVM_RET_ERR; 332 | } 333 | 334 | /* 335 | * 从存储器中重载配置 336 | */ 337 | cvm_ret __instr_reload(CVM_OP* op) { 338 | if (op->type_dst_expr == 0xAA && op->dst == 0x55AA) { 339 | sysLoadConfig(); 340 | return CVM_RET_OK; 341 | } 342 | return CVM_RET_ERR; 343 | } 344 | 345 | volatile void (*__iap_main)() = 0x3000; // IAP程序入口点 346 | 347 | /* 348 | * 启动IAP程序 349 | */ 350 | cvm_ret __instr_iap(CVM_OP* op) { 351 | if (op->type_dst_expr == 0x5A && op->dst == 0xA55A) { 352 | __iap_main(); 353 | return CVM_RET_OK; 354 | } 355 | return CVM_RET_ERR; 356 | } 357 | 358 | #endif -------------------------------------------------------------------------------- /ROM/main.c: -------------------------------------------------------------------------------- 1 | #include "ch552.h" 2 | #include "sys.h" 3 | #include "rom.h" 4 | #include "usb.h" 5 | #include "rgb.h" 6 | #include "fir.h" 7 | #include "bsp.h" 8 | 9 | #include "cvm.h" 10 | 11 | void __usbDeviceInterrupt() __interrupt (INT_NO_USB) __using (1); // USB中断定义 12 | extern uint8_t FLAG; 13 | 14 | void __tim2Interrupt() __interrupt (INT_NO_TMR2) __using (2); // TIM2中断定义 15 | 16 | volatile __bit control = 0; 17 | volatile uint8_t prevKey = 0; 18 | 19 | volatile uint8_t runKey = 0xFF; 20 | cvm_ret cvmWDTCallback() { // 解释器看门狗回调定义 21 | if (runKey != 0xFF) { 22 | if ((runKey & 0x80) != 0) { 23 | if (fir(runKey & 0x7F) == 0) 24 | cvm_end(); 25 | } else { 26 | if ((prevKey & (0x01 << runKey)) != (fir(runKey) << runKey)) 27 | cvm_end(); 28 | } 29 | } 30 | return CVM_RET_OK; 31 | } 32 | 33 | #ifdef PERFORMANCE_MODE 34 | __bit __get_pin(uint8_t i) { 35 | switch (i) { 36 | #if (KEY_COUNT >= 1) 37 | case 1: 38 | return BT1; 39 | #endif 40 | #if (KEY_COUNT >= 2) 41 | case 2: 42 | return BT2; 43 | #endif 44 | #if (KEY_COUNT >= 3) 45 | case 3: 46 | return BT3; 47 | #endif 48 | #if (KEY_COUNT >= 4) 49 | case 4: 50 | return BT4; 51 | #endif 52 | #if (KEY_COUNT == 5) 53 | case 5: 54 | return BT5; 55 | #endif 56 | default: 57 | break; 58 | } 59 | return 0; 60 | } 61 | 62 | __bit __test(uint8_t v, uint8_t i) { 63 | return (v & (1 << i)); 64 | } 65 | 66 | void main() { 67 | uint8_t i; 68 | sysClockConfig(); 69 | delay(5); 70 | 71 | romInit(); 72 | delay(500); 73 | 74 | sysLoadConfig(); 75 | SysConfig* cfg = sysGetConfig(); 76 | 77 | sysTickConfig(); 78 | usbDevInit(); 79 | rgbInit(); 80 | EA = 1; 81 | 82 | for (i = 0; i < LED_COUNT; i++) { 83 | if (cfg->ledConfig[i].marco) 84 | cvm_run(cfg->ledConfig[i].program, cfg->ledConfig[i].length); 85 | else 86 | rgbSetLed(i, cfg->ledConfig[i].color); 87 | } 88 | rgbUpdate(); 89 | rgbPush(); 90 | 91 | delay(500); 92 | usbReleaseAll(); 93 | usbPushKeydata(); 94 | requestHIDData(); 95 | 96 | cvm_wdt(&cvmWDTCallback); 97 | 98 | uint8_t state = 0, trig = 0; 99 | while (1) { 100 | firUpdate(); 101 | 102 | uint8_t nowKey = 0; 103 | for (i = 0; i < KEY_COUNT; i++) { 104 | nowKey <<= 1; 105 | nowKey |= fir(i); 106 | } 107 | 108 | for (i = 0; i < KEY_COUNT; i++) { 109 | if (cfg->keyConfig[i].mode == KeyNone) { 110 | usbSetKeycode(0, 1); 111 | usbSetKeycode(1, 0); 112 | if (!cfg->keyConfig[i].marco && cfg->keyConfig[i].code < 0xE0) { 113 | if (__test(state, i) != 0 && __get_pin(i) == 0) { 114 | // negedge 115 | usbSetKeycode(i + 2, cfg->keyConfig[i].code); 116 | usbPushKeydata(); 117 | } else if (fir(i)) { 118 | trig |= (1 << i); 119 | } else if (!fir(i) && __test(trig, i) != 0) { 120 | trig &= !(1 << i); 121 | usbSetKeycode(i + 2, 0x00); 122 | } 123 | } 124 | if (prevKey != nowKey) 125 | usbPushKeydata(); 126 | } 127 | } 128 | 129 | state = 0; 130 | for (i = 0; i < KEY_COUNT; i++) { 131 | state <<= 1; 132 | state |= __get_pin(i); 133 | } 134 | 135 | if (hasHIDData()) { 136 | cvm_wdt(NULL); 137 | cvm_run(fetchHIDData(), HID_BUF); 138 | requestHIDData(); 139 | cvm_wdt(&cvmWDTCallback); 140 | } 141 | 142 | if (prevKey != nowKey) 143 | prevKey = nowKey; 144 | } 145 | 146 | } 147 | #else 148 | void main() { 149 | uint8_t i; 150 | sysClockConfig(); 151 | delay(5); 152 | 153 | romInit(); 154 | delay(500); 155 | 156 | sysLoadConfig(); 157 | SysConfig* cfg = sysGetConfig(); 158 | 159 | sysTickConfig(); 160 | usbDevInit(); 161 | rgbInit(); 162 | EA = 1; 163 | 164 | for (i = 0; i < LED_COUNT; i++) { 165 | if (cfg->ledConfig[i].marco) 166 | cvm_run(cfg->ledConfig[i].program, cfg->ledConfig[i].length); 167 | else 168 | rgbSetLed(i, cfg->ledConfig[i].color); 169 | } 170 | 171 | delay(500); 172 | usbReleaseAll(); 173 | usbPushKeydata(); 174 | requestHIDData(); 175 | 176 | cvm_wdt(&cvmWDTCallback); 177 | 178 | while (1) { 179 | firUpdate(); 180 | rgbUpdate(); 181 | rgbPush(); 182 | 183 | uint8_t nowKey = 0; 184 | for (i = 0; i < KEY_COUNT; i++) { 185 | nowKey <<= 1; 186 | nowKey |= fir(i); 187 | } 188 | 189 | uint8_t ctrlKey = 0; 190 | __bit hasCtrlKey = 0; 191 | for (i = 0; i < KEY_COUNT; i++) { 192 | if (cfg->keyConfig[i].mode == KeyNone) { 193 | usbSetKeycode(0, 1); 194 | usbSetKeycode(1, 0); 195 | if (!cfg->keyConfig[i].marco) { 196 | if (cfg->keyConfig[i].code >= 0xE0) { 197 | hasCtrlKey = 1; 198 | ctrlKey |= (fir(i) ? 0x01 << (cfg->keyConfig[i].code - 0xE0) : 0x00); 199 | } else 200 | usbSetKeycode(i + 2, fir(i) ? cfg->keyConfig[i].code : 0x00); 201 | } 202 | if (prevKey != nowKey) 203 | usbPushKeydata(); 204 | } else { 205 | usbReleaseAll(); 206 | usbSetKeycode(0, 1); 207 | usbPushKeydata(); 208 | usbSetKeycode(0, 2); 209 | usbPushKeydata(); 210 | usbReleaseAll(); 211 | if (cfg->keyConfig[i].marco) { 212 | if (cfg->keyConfig[i].mode == KeyPress) { 213 | if (fir(i)) { 214 | runKey = i | 0x80; 215 | cvm_run(cfg->keyConfig[i].program, cfg->keyConfig[i].length); 216 | runKey = 0xFF; 217 | } 218 | } else { 219 | __bit trig = 0; 220 | if (cfg->keyConfig[i].mode == KeyDown) 221 | trig = (prevKey & (0x01 << i)) == 0 && (nowKey & (0x01 << i)) != 0; 222 | else 223 | trig = (prevKey & (0x01 << i)) != 0 && (nowKey & (0x01 << i)) == 0; 224 | if (trig) { 225 | runKey = i; 226 | cvm_run(cfg->keyConfig[i].program, cfg->keyConfig[i].length); 227 | runKey = 0xFF; 228 | } 229 | } 230 | } 231 | } 232 | } 233 | 234 | if (prevKey != nowKey && hasCtrlKey) { 235 | usbSetKeycode(0, 1); 236 | usbSetKeycode(1, ctrlKey); 237 | usbPushKeydata(); 238 | } 239 | 240 | if (hasHIDData()) { 241 | cvm_wdt(NULL); 242 | cvm_run(fetchHIDData(), HID_BUF); 243 | requestHIDData(); 244 | cvm_wdt(&cvmWDTCallback); 245 | } 246 | 247 | if (prevKey != nowKey) 248 | prevKey = nowKey; 249 | } 250 | 251 | } 252 | #endif 253 | -------------------------------------------------------------------------------- /ROM/make.ps1: -------------------------------------------------------------------------------- 1 | function clean_dir($params) { 2 | if (Test-Path $params) { 3 | Remove-Item -r $params 4 | } 5 | $null = mkdir $params 6 | } 7 | 8 | Write-Output "clean outputs..." 9 | clean_dir("./out/") 10 | 11 | $main = "main.c" 12 | $out = "./out" 13 | $tmp = "./out/tmp" 14 | 15 | $iram = 256 16 | $xram = 1024 17 | $code = 0x3000 18 | $xram_start = 0x0108 # 这里要看usb.c内的DMA缓冲区结束地址 19 | 20 | function compile($params) { 21 | $sources = $params[0] 22 | $target = $params[1] 23 | 24 | $defines = "" 25 | $name = "simpad" 26 | 27 | if ($null -ne $target) { 28 | $defines = "-D__MULTI_COMPILE__", "-D$target" 29 | $name = $target.ToLower() 30 | Write-Output "compiling sources for $name" 31 | } else { 32 | Write-Output "compiling sources..." 33 | } 34 | 35 | clean_dir($tmp) 36 | foreach ($s in $sources) { 37 | if ($s -match $main) { 38 | continue 39 | } 40 | if ($null -eq $target) { 41 | Write-Output "CC: $s" 42 | } 43 | sdcc --std-c11 -mmcs51 --opt-code-size --model-large --iram-size $iram --xram-size $xram --code-size $code --xram-loc $xram_start $defines -c "$s" -o "$tmp/" 44 | } 45 | 46 | $hex = "$out/$name.hex" 47 | $bin = "$out/$name.bin" 48 | $objs = Get-ChildItem "$tmp/*.rel" 49 | if ($null -ne $objs) { 50 | if ($null -eq $target) { 51 | Write-Output "linking objects..." 52 | } 53 | sdcc --std-c11 -mmcs51 --opt-code-size --model-large --iram-size $iram --xram-size $xram --code-size $code --xram-loc $xram_start "$main" $objs -o "$tmp/name.hex" 54 | Copy-Item "$tmp/name.hex" $hex 55 | if ($null -eq $target) { 56 | Write-Output "making binary..." 57 | } 58 | makebin -s $code "$hex" "$bin" 59 | 60 | if ($null -eq $target) { 61 | Write-Output "hex file at: $hex" 62 | Write-Output "bin file at: $bin" 63 | } 64 | } 65 | } 66 | 67 | $targets = "SIMPAD_V2_AE", "SIMPAD_NANO_AE", "SIM_KEY", "SIMPAD_V2", "SIMPAD_NANO" 68 | 69 | $sources = Get-ChildItem -Path "./" -File -Name *.c 70 | if ($null -ne $sources) { 71 | if ($args -ne $null) { 72 | switch ($args[0].ToLower()) { 73 | "all" { 74 | Write-Output "building for targets: $targets" 75 | foreach ($s in $targets) { 76 | compile($sources, $s) 77 | } 78 | } 79 | # TODO: 添加其他目标? 80 | Default { 81 | Write-Output "Incorrect param, or you want to use 'all' ?" 82 | } 83 | } 84 | } else { 85 | compile($sources, $null) 86 | } 87 | } 88 | 89 | if (Test-Path $tmp) { 90 | Remove-Item -r $tmp 91 | } 92 | -------------------------------------------------------------------------------- /ROM/rgb.c: -------------------------------------------------------------------------------- 1 | #include "rgb.h" 2 | 3 | #include "bsp.h" 4 | #include "sys.h" 5 | 6 | /* -------- LED数据 -------- */ 7 | #if defined(SIMPAD_V2) 8 | // [index][count: 0, control: 1][red: 0, green: 1, blue: 2] 9 | static uint8_i RGBS[2][2][3]; 10 | #else 11 | static uint32_i rgbGRBData[LED_COUNT]; 12 | #endif 13 | /* -------- LED数据 -------- */ 14 | 15 | /* -------- 非总线式LED驱动 -------- */ 16 | #if defined(SIMPAD_V2) 17 | extern volatile uint32_t sysTickCount; 18 | volatile uint8_t __tick_cnt = 0; 19 | void __tim2Interrupt() __interrupt (INT_NO_TMR2) __using (2) { 20 | if (TF2) { 21 | TF2 = 0; 22 | 23 | RGBS[0][0][0] += 1; RGBS[0][0][1] += 1; RGBS[0][0][2] += 1; 24 | RGBS[1][0][0] += 1; RGBS[1][0][1] += 1; RGBS[1][0][2] += 1; 25 | G1R = RGBS[0][0][0] > RGBS[0][1][0]; 26 | G1G = RGBS[0][0][1] > RGBS[0][1][1]; 27 | G1B = RGBS[0][0][2] > RGBS[0][1][2]; 28 | G2R = RGBS[1][0][0] > RGBS[1][1][0]; 29 | G2G = RGBS[1][0][1] > RGBS[1][1][1]; 30 | G2B = RGBS[1][0][2] > RGBS[1][1][2]; 31 | 32 | if (__tick_cnt < 61) __tick_cnt += 1; 33 | else { 34 | __tick_cnt = 0; 35 | sysTickCount += 1; 36 | } 37 | } 38 | } 39 | #endif 40 | /* -------- 非总线式LED驱动 -------- */ 41 | 42 | /* 43 | * LED初始化 44 | */ 45 | void rgbInit() { 46 | #if defined(SIMPAD_V2) 47 | T2MOD |= (bTMR_CLK | bT2_CLK); 48 | RCAP2 = T2COUNT = 0xFFFF - (uint16_t) (FREQ_SYS / (256L * 240L)); // 240fps, 61400Hz 49 | TR2 = 1; 50 | ET2 = 1; 51 | #else 52 | for (uint8_t i = 0; i < LED_COUNT; i++) 53 | rgbGRBData[i] = 0xFFFFFF; 54 | #endif 55 | } 56 | 57 | /* 58 | * 设置LED颜色 59 | */ 60 | void rgbSet(uint8_t index, uint32_t value) { 61 | #if defined(SIMPAD_V2) 62 | RGBS[index][1][0] = (value >> 16) & 0xFF; 63 | RGBS[index][1][1] = (value >> 8 ) & 0xFF; 64 | RGBS[index][1][2] = (value ) & 0xFF; 65 | #else 66 | rgbGRBData[index] = ((value & 0x00FF00) << 8) | ((value & 0xFF0000) >> 8) | (value & 0x0000FF); 67 | #endif 68 | } 69 | 70 | /* -------- 总线式LED驱动 -------- */ 71 | #if !defined(SIMPAD_V2) 72 | void __ws_rst() { 73 | LED = 0; 74 | delay_us(500); 75 | LED = 1; 76 | } 77 | 78 | void __ws_send(uint32_t value) { 79 | uint8_t i, j; 80 | for (i = 0; i < 24; i++) { 81 | if (value & 0x800000) { 82 | LED = 1; 83 | for (j = 4; j > 0; j--) 84 | __asm__("nop"); 85 | LED = 0; 86 | for (j = 1; j > 0; j--) 87 | __asm__("nop"); 88 | } else { 89 | LED = 1; 90 | for (j = 1; j > 0; j--) 91 | __asm__("nop"); 92 | LED = 0; 93 | for (j = 4; j > 0; j--) 94 | __asm__("nop"); 95 | } 96 | value <<= 1; 97 | } 98 | } 99 | #endif 100 | 101 | void rgbPush() { 102 | #if !defined(SIMPAD_V2) 103 | E_DIS = 1; 104 | __ws_rst(); 105 | uint8_t i; 106 | for (i = 0; i < LED_COUNT; i++) 107 | __ws_send(rgbGRBData[i]); 108 | E_DIS = 0; 109 | #endif 110 | } 111 | /* -------- 总线式LED驱动 -------- */ 112 | 113 | static __xdata RGBConfig fadeConfig[LED_COUNT]; // 渐变配置 114 | volatile uint16_i fadeLength = 0; // 渐变时间缓存 115 | 116 | /* 117 | * 设置LED颜色,对指令集暴露的接口 118 | */ 119 | void rgbSetLed(uint16_t index, uint16_t value) { 120 | uint8_t i = index & 0xFF; 121 | fadeConfig[i].mode = LEDNone; 122 | fadeConfig[i].step = 0; 123 | fadeConfig[i].length = 0; 124 | fadeConfig[i].nodes[0].color = sysGetRGB(value, (index >> 8) & 0xFF); 125 | fadeConfig[i].nodes[0].length = 0; 126 | rgbSet(i, fadeConfig[i].nodes[0].color); 127 | } 128 | 129 | /* 130 | * 设置LED渐变时间缓存 131 | */ 132 | void rgbSetTime(uint16_t time) { 133 | fadeLength = time; 134 | } 135 | 136 | #define CFG(i) (fadeConfig[i]) 137 | 138 | /* 139 | * 添加LED渐变节点 140 | */ 141 | void rgbAddFade(uint16_t index, uint16_t value) { 142 | uint8_t i = index & 0xFF; 143 | uint8_t len = CFG(i).length; 144 | CFG(i).nodes[len].color = sysGetRGB(value, (index >> 8) & 0xFF); 145 | CFG(i).nodes[len].length = fadeLength; 146 | CFG(i).length += 1; 147 | if (CFG(i).length == LED_FADE_LEN) 148 | CFG(i).length = 0; 149 | } 150 | 151 | /* 152 | * 设置LED触发模式 153 | */ 154 | void rgbSetTrig(uint16_t index, uint16_t value) { 155 | uint8_t i = index & 0xFF; 156 | CFG(i).trig = value & 0xFF; 157 | } 158 | 159 | /* 160 | * 设置LED显示模式 161 | */ 162 | void rgbSetMode(uint16_t index, uint16_t value) { 163 | uint8_t i = index & 0xFF; 164 | CFG(i).mode = (LEDMode) (value & 0xFF); 165 | } 166 | 167 | /* 168 | * 彩虹灯光效果 169 | */ 170 | uint32_t __rgb__rainbow(uint8_t step, uint8_t count) { 171 | switch (step) { 172 | case 0: 173 | return 0xFF0000 | ((uint32_t) count << 8); 174 | case 1: 175 | return 0x00FF00 | ((uint32_t) (0xFF - count) << 16); 176 | case 2: 177 | return 0x00FF00 | count; 178 | case 3: 179 | return 0x0000FF | ((uint32_t) (0xFF - count) << 8); 180 | case 4: 181 | return 0x0000FF | ((uint32_t) count << 16); 182 | case 5: 183 | return 0xFF0000 | (0xFF - count); 184 | default: 185 | return 0; 186 | } 187 | } 188 | 189 | /* 190 | * 获取LED触发按键状态 191 | */ 192 | __bit __rgb_key(uint8_t i) { 193 | switch (i) { 194 | #if (KEY_COUNT >= 1) 195 | case 1: 196 | return BT1; 197 | #endif 198 | #if (KEY_COUNT >= 2) 199 | case 2: 200 | return BT2; 201 | #endif 202 | #if (KEY_COUNT >= 3) 203 | case 3: 204 | return BT3; 205 | #endif 206 | #if (KEY_COUNT >= 4) 207 | case 4: 208 | return BT4; 209 | #endif 210 | #if (KEY_COUNT == 5) 211 | case 5: 212 | return BT5; 213 | #endif 214 | default: 215 | break; 216 | } 217 | return 0; 218 | } 219 | 220 | /* 221 | * 获取LED触发状态 222 | */ 223 | __bit __rgb__trig(uint8_t index) { 224 | for (uint8_t i = 0; i < KEY_COUNT; i++) { 225 | if (CFG(index).trig & (0x01 << i)) { 226 | if (__rgb_key(i) == 0) 227 | return 1; 228 | } 229 | } 230 | return 0; 231 | } 232 | 233 | volatile uint8_i trigCtl = 0, trigSte = 0; // 触发控制及触发状态 234 | volatile uint32_i prevTickCount = 0; // 前一刻 235 | 236 | #define NODE(i, j) (CFG(i).nodes[CFG(i).step + (j)]) 237 | 238 | #if defined(RGB_USE_GRAD_LIST) && !defined(RGB_GRAD_LIST_LITE) 239 | /* 240 | * 单通道色彩插值 241 | */ 242 | uint8_t __rgb__inter(uint8_t index, uint8_t input, int16_t total, uint16_t time) { 243 | int8_t sign = total > 0 ? 1 : -1; 244 | uint8_t d = (uint16_t) (sign * total) / time; 245 | uint32_t now = sysGetTickCount(); 246 | if (d == 0) { 247 | d = time / (uint16_t) (sign * total); 248 | if ((now - CFG(index).time) % d == 0) 249 | input += sign * 1; 250 | } else if (prevTickCount != now) { 251 | prevTickCount = now; 252 | input += sign * d; 253 | } 254 | return input; 255 | } 256 | #endif 257 | 258 | /* 259 | * 执行彩虹渐变 260 | */ 261 | void __rgb__perform_rgb(uint8_t i) { 262 | uint32_t c = __rgb__rainbow(CFG(i).step, CFG(i).count); 263 | rgbSet(i, c); 264 | CFG(i).step += (CFG(i).count == 0 ? 1 : 0); 265 | CFG(i).step = CFG(i).step > 5 ? 0 : CFG(i).step; 266 | CFG(i).count += 1; 267 | } 268 | 269 | /* 270 | * 执行逆向彩虹渐变 271 | */ 272 | void __rgb__perform_bgr(uint8_t i) { 273 | uint32_t c = __rgb__rainbow(CFG(i).step, CFG(i).count); 274 | rgbSet(i, c); 275 | CFG(i).step -= (CFG(i).count == 0 ? 1 : 0); 276 | CFG(i).step = CFG(i).step > 5 ? 5 : CFG(i).step; 277 | CFG(i).count -= 1; 278 | } 279 | 280 | /* 281 | * 刷新触发状态 282 | */ 283 | void __rgb__perform_trig(uint8_t trig, uint8_t pos, uint8_t v) { 284 | if (trig && (trigSte & pos) == 0) { 285 | trigSte |= pos; 286 | if ((trigCtl & pos) == 0 || (v != 0)) 287 | trigCtl |= pos; 288 | else 289 | trigCtl &= ~pos; 290 | } else if (!trig && (trigSte & pos) == 1) { 291 | trigSte &= ~pos; 292 | } 293 | } 294 | 295 | /* 296 | * LED灯光更新 297 | */ 298 | void rgbUpdate() { 299 | uint32_t c = 0, cn = 0; 300 | uint8_t tmp, trig; 301 | for (uint8_t i = 0; i < LED_COUNT; i++) { 302 | trig = __rgb__trig(i); 303 | switch (CFG(i).mode) { 304 | case LEDNone: 305 | #ifdef RGB_USE_GRAD_LIST 306 | tmp = (0x01 << i); 307 | __rgb__perform_trig(trig, tmp, 1); 308 | 309 | #ifndef RGB_GRAD_LIST_LITE 310 | if ((trigCtl & tmp) != 0) { 311 | trigCtl &= ~tmp; 312 | CFG(i).step = 0; 313 | CFG(i).time = 0; 314 | CFG(i).r = CFG(i).g = CFG(i).b = 0; 315 | } 316 | 317 | if (CFG(i).time == 0) { 318 | CFG(i).time = sysGetTickCount(); 319 | c = NODE(i, 0).color; 320 | CFG(i).r = (c >> 16) & 0xFF; 321 | CFG(i).g = (c >> 8 ) & 0xFF; 322 | CFG(i).b = (c >> 0 ) & 0xFF; 323 | } 324 | 325 | if (NODE(i, 0).length != 0) { 326 | uint8_x rt = 0, gt = 0, bt = 0; 327 | cn = NODE(i, 1).color; 328 | rt = (cn >> 16) & 0xFF - (c >> 16) & 0xFF; 329 | gt = (cn >> 8 ) & 0xFF - (c >> 8 ) & 0xFF; 330 | bt = (cn ) & 0xFF - (c ) & 0xFF; 331 | CFG(i).r = __rgb__inter(i, CFG(i).r, rt, NODE(i).length); 332 | CFG(i).g = __rgb__inter(i, CFG(i).g, gt, NODE(i).length); 333 | CFG(i).b = __rgb__inter(i, CFG(i).b, bt, NODE(i).length); 334 | c = ((uint32_t) CFG(i).r) << 16; 335 | c |= ((uint32_t) CFG(i).g) << 8; 336 | c |= CFG(i).b; 337 | rgbSet(i, c); 338 | 339 | if (sysGetTickCount() - CFG(i).time > NODE(i, 0).length) { 340 | CFG(i).step += 1; 341 | CFG(i).time = 0; 342 | CFG(i).r = CFG(i).g = CFG(i).b = 0; 343 | if (CFG(i).step == CFG(i).length) 344 | CFG(i).step = 0; 345 | } 346 | } else 347 | rgbSet(i, NODE(i, 0).color); 348 | #else 349 | CFG(i).step = 0; 350 | if ((trigCtl & tmp) != 0) { 351 | trigCtl &= ~tmp; 352 | CFG(i).b = 0; 353 | CFG(i).time = 0; 354 | CFG(i).c = NODE(i, 0).color; 355 | } 356 | 357 | cn = NODE(i, 0).length; 358 | if (cn != 0) { 359 | if (CFG(i).b == 0) { 360 | CFG(i).c -= 0x010101; 361 | CFG(i).time += 1; 362 | } else 363 | CFG(i).c = 0; 364 | rgbSet(i, CFG(i).c); 365 | 366 | if ((CFG(i).time >> (cn & 0x7)) > (cn & 0xFFF8)) 367 | CFG(i).b = 1; 368 | } else { 369 | rgbSet(i, NODE(i, 0).color); 370 | } 371 | #endif 372 | 373 | #else 374 | rgbSet(i, NODE(i, 0).color); 375 | #endif 376 | break; 377 | case LEDRGB: 378 | __rgb__perform_rgb(i); 379 | break; 380 | case LEDBGR: 381 | __rgb__perform_bgr(i); 382 | break; 383 | case LEDTRI: 384 | tmp = (0x01 << i); 385 | __rgb__perform_trig(trig, tmp, 0); 386 | 387 | if ((trigCtl & tmp) != 0) 388 | __rgb__perform_rgb(i); 389 | else 390 | __rgb__perform_bgr(i); 391 | break; 392 | default: 393 | break; 394 | } 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /ROM/rgb.h: -------------------------------------------------------------------------------- 1 | #ifndef __RGB_H 2 | #define __RGB_H 3 | 4 | #include "ch552.h" 5 | 6 | #define LED_FADE_LEN 4 // LED渐变列表最大长度 7 | 8 | // 默认模式 正向渐变 反向渐变 触发模式 9 | typedef enum { LEDNone = 0, LEDRGB = 1, LEDBGR = 2, LEDTRI = 3 } LEDMode; 10 | 11 | // 渐变节点结构体 12 | typedef struct { 13 | uint32_t color; 14 | uint16_t length; 15 | } FadeNode; 16 | 17 | // LED配置结构体 18 | typedef struct { 19 | uint8_t trig; 20 | LEDMode mode; 21 | FadeNode nodes[LED_FADE_LEN]; 22 | uint8_t length; 23 | uint8_t step; 24 | uint8_t count; 25 | uint32_t time; 26 | uint8_t r, g, b; 27 | uint32_t c; 28 | } RGBConfig; 29 | 30 | void rgbInit(); 31 | void rgbSet(uint8_t index, uint32_t value); 32 | void rgbPush(); 33 | 34 | void rgbSetLed(uint16_t index, uint16_t value); 35 | void rgbSetTime(uint16_t time); 36 | void rgbAddFade(uint16_t index, uint16_t value); 37 | void rgbSetTrig(uint16_t index, uint16_t value); 38 | void rgbSetMode(uint16_t index, uint16_t value); 39 | void rgbUpdate(); 40 | 41 | #endif -------------------------------------------------------------------------------- /ROM/rom.c: -------------------------------------------------------------------------------- 1 | #include "rom.h" 2 | 3 | #include "bsp.h" 4 | #include "sys.h" 5 | 6 | /* -------- 外部存储器驱动 -------- */ 7 | #if defined(HAS_ROM) 8 | /* 9 | * EEPROM时序复位 10 | */ 11 | void __eeprom_reset() { 12 | ROM_SDA = 1; delay_us(5); 13 | for (uint8_t i = 0; i < 9; i++) { 14 | ROM_SCL = 1; delay_us(5); 15 | if (ROM_SDA == 1) break; 16 | ROM_SCL = 0; delay_us(5); 17 | } 18 | ROM_SCL = 0; delay_us(5); 19 | ROM_SDA = 1; 20 | ROM_SCL = 1; delay_us(5); 21 | ROM_SDA = 0; delay_us(5); 22 | } 23 | 24 | /* 25 | * 开始时序 26 | */ 27 | void __eeprom_start() { 28 | ROM_SDA = 1; 29 | ROM_SCL = 1; delay_us(5); 30 | ROM_SDA = 0; delay_us(5); 31 | } 32 | 33 | /* 34 | * 停止时序 35 | */ 36 | void __eeprom_stop() { 37 | ROM_SDA = 0; 38 | ROM_SCL = 1; delay_us(5); 39 | ROM_SDA = 1; delay_us(5); 40 | } 41 | 42 | /* 43 | * 应答时序 44 | */ 45 | void __eeprom_ack() { 46 | ROM_SCL = 0; 47 | ROM_SDA = 1; 48 | ROM_SCL = 1; delay_us(5); 49 | for (uint8_t i = 0; i < 0xFF; i++) 50 | if (ROM_SDA == 0) break; 51 | ROM_SCL = 0; delay_us(5); 52 | } 53 | 54 | /* 55 | * 非应答时序 56 | */ 57 | void __eeprom_nak() { 58 | ROM_SCL = 0; 59 | ROM_SDA = 1; 60 | ROM_SCL = 1; delay_us(5); 61 | ROM_SCL = 0; delay_us(5); 62 | } 63 | 64 | /* 65 | * 发送一个字节 66 | */ 67 | void __eeprom_wr(uint8_t data) { 68 | for (uint8_t i = 0; i < 8; i++) { 69 | ROM_SCL = 0; delay_us(5); 70 | ROM_SDA = (data & 0x80); delay_us(5); 71 | ROM_SCL = 1; delay_us(5); 72 | data <<= 1; 73 | } 74 | ROM_SCL = 0; 75 | ROM_SDA = 1; 76 | delay_us(5); 77 | } 78 | 79 | /* 80 | * 读取一个字节 81 | */ 82 | uint8_t __eeprom_rd() { 83 | uint8_t data = 0; 84 | __bit tmp; 85 | ROM_SCL = 0; delay_us(5); 86 | for (uint8_t i = 0; i < 8; i++) { 87 | ROM_SCL = 1; delay_us(5); 88 | tmp = ROM_SDA; 89 | data <<= 1; 90 | data |= tmp; 91 | delay_us(5); 92 | ROM_SCL = 0; delay_us(5); 93 | } 94 | return data; 95 | } 96 | 97 | /* 98 | * 向指定地址写入一个字节 99 | */ 100 | void __eeprom_write(uint16_t addr, uint8_t data) { 101 | ROM_WP = 0; delay_us(5); 102 | addr &= (ROM_SIZE - 1); 103 | uint8_t devAddr = 0xA0 | (((addr >> 8) & 0x07) << 1); 104 | uint8_t wordAddr = addr & 0xFF; 105 | __eeprom_start(); 106 | __eeprom_wr(devAddr & 0xFE); 107 | __eeprom_ack(); 108 | __eeprom_wr(wordAddr); 109 | __eeprom_ack(); 110 | __eeprom_wr(data); 111 | __eeprom_ack(); 112 | __eeprom_stop(); 113 | delay(2); 114 | ROM_WP = 1; delay_us(5); 115 | } 116 | 117 | /* 118 | * 读取指定地址的字节 119 | */ 120 | uint8_t __eeprom_read(uint16_t addr) { 121 | addr &= (ROM_SIZE - 1); 122 | uint8_t devAddr = 0xA0 | (((addr >> 8) & 0x07) << 1); 123 | uint8_t wordAddr = addr & 0xFF; 124 | uint8_t data = 0; 125 | __eeprom_start(); 126 | __eeprom_wr(devAddr & 0xFE); 127 | __eeprom_ack(); 128 | __eeprom_wr(wordAddr); 129 | __eeprom_ack(); 130 | __eeprom_start(); 131 | __eeprom_wr(devAddr | 0x01); 132 | __eeprom_ack(); 133 | data = __eeprom_rd(); 134 | __eeprom_nak(); 135 | __eeprom_stop(); 136 | return data; 137 | } 138 | #else 139 | volatile __bit __rom_dummy; 140 | #endif 141 | /* -------- 外部存储器驱动 -------- */ 142 | 143 | /* 144 | * 内部存储器写入 145 | */ 146 | void __flash_write(uint8_t addr, uint8_t data) { 147 | addr &= (FLASH_SIZE - 1); 148 | uint8_t offset = addr << 1; 149 | SAFE_MOD = 0x55; 150 | SAFE_MOD = 0xAA; 151 | GLOBAL_CFG |= bDATA_WE; 152 | ROM_ADDR = DATA_FLASH_ADDR + offset; 153 | ROM_DATA_L = data; 154 | ROM_CTRL = 0x9A; 155 | SAFE_MOD = 0x55; 156 | SAFE_MOD = 0xAA; 157 | GLOBAL_CFG &= ~bDATA_WE; 158 | } 159 | 160 | /* 161 | * 内部存储器读取 162 | */ 163 | uint8_t __flash_read(uint8_t addr) { 164 | addr &= (FLASH_SIZE - 1); 165 | uint8_t offset = addr << 1; 166 | ROM_ADDR = DATA_FLASH_ADDR + offset; 167 | ROM_CTRL = 0x8E; 168 | return ROM_DATA_L; 169 | } 170 | 171 | /* 172 | * ROM初始化 173 | */ 174 | void romInit() { 175 | #if defined(HAS_ROM) 176 | ROM_SDA = 1; 177 | ROM_SCL = 1; 178 | ROM_WP = 0; delay_us(5); 179 | __eeprom_reset(); 180 | ROM_WP = 1; delay_us(5); 181 | #endif 182 | } 183 | 184 | /* 185 | * 从内部存储器读取一个字节 186 | */ 187 | uint8_t romRead8i(uint8_t addr) { 188 | return __flash_read(addr); 189 | } 190 | 191 | /* 192 | * 向内部存储器写入一个字节 193 | */ 194 | void romWrite8i(uint8_t addr, uint8_t data) { 195 | __flash_write(addr, data); 196 | } 197 | 198 | /* 199 | * 从内部存储器读取一个字 200 | */ 201 | uint16_t romRead16i(uint8_t addr) { 202 | return ((uint16_t) __flash_read(addr)) | (((uint16_t) __flash_read(addr + 1)) << 8); 203 | } 204 | 205 | /* 206 | * 向内部存储器写入一个字 207 | */ 208 | void romWrite16i(uint8_t addr, uint16_t data) { 209 | __flash_write(addr, data & 0xFF); 210 | __flash_write(addr + 1, (data >> 8) & 0xFF); 211 | } 212 | 213 | /* 214 | * 从外部存储器读取一个字节 215 | */ 216 | uint8_t romRead8e(uint16_t addr) { 217 | #if defined(HAS_ROM) 218 | return __eeprom_read(addr); 219 | #else 220 | return addr == 0; // Dummy thing 221 | #endif 222 | } 223 | 224 | /* 225 | * 向外部存储器写入一个字节 226 | */ 227 | void romWrite8e(uint16_t addr, uint8_t data) { 228 | #if defined(HAS_ROM) 229 | __eeprom_write(addr, data); 230 | #else 231 | __rom_dummy = addr == 0 && data == 0; // Dummy thing 232 | #endif 233 | } 234 | 235 | /* 236 | * 从外部存储器读取一个字 237 | */ 238 | uint16_t romRead16e(uint16_t addr) { 239 | #if defined(HAS_ROM) 240 | return ((uint16_t) __eeprom_read(addr)) | (((uint16_t) __eeprom_read(addr + 1)) << 8); 241 | #else 242 | return addr == 0; // Dummy thing 243 | #endif 244 | } 245 | 246 | /* 247 | * 向外部存储器写入一个字 248 | */ 249 | void romWrite16e(uint16_t addr, uint16_t data) { 250 | #if defined(HAS_ROM) 251 | __eeprom_write(addr, data & 0xFF); 252 | __eeprom_write(addr + 1, (data >> 8) & 0xFF); 253 | #else 254 | __rom_dummy = addr == 0 && data == 0; // Dummy thing 255 | #endif 256 | } 257 | -------------------------------------------------------------------------------- /ROM/rom.h: -------------------------------------------------------------------------------- 1 | #ifndef __ROM_H 2 | #define __ROM_H 3 | 4 | #include "ch552.h" 5 | 6 | void romInit(); 7 | uint8_t romRead8i(uint8_t addr); 8 | void romWrite8i(uint8_t addr, uint8_t data); 9 | uint16_t romRead16i(uint8_t addr); 10 | void romWrite16i(uint8_t addr, uint16_t data); 11 | uint8_t romRead8e(uint16_t addr); 12 | void romWrite8e(uint16_t addr, uint8_t data); 13 | uint16_t romRead16e(uint16_t addr); 14 | void romWrite16e(uint16_t addr, uint16_t data); 15 | 16 | #endif -------------------------------------------------------------------------------- /ROM/simpad_instruction_table.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/ROM/simpad_instruction_table.xlsx -------------------------------------------------------------------------------- /ROM/sys.c: -------------------------------------------------------------------------------- 1 | #include "sys.h" 2 | 3 | #include "ch552.h" 4 | #include "bsp.h" 5 | #include "rom.h" 6 | 7 | #include 8 | 9 | volatile uint32_i sysTickCount = 0; // 系统刻计数器 10 | static __xdata SysConfig sysConfig; // 系统配置存储 11 | 12 | /* 13 | * 系统时钟配置 14 | */ 15 | void sysClockConfig() { 16 | SAFE_MOD = 0x55; 17 | SAFE_MOD = 0xAA; 18 | CLOCK_CFG |= bOSC_EN_INT; 19 | 20 | #if OSC_EN_XT 21 | SAFE_MOD = 0x55; 22 | SAFE_MOD = 0xAA; 23 | CLOCK_CFG |= bOSC_EN_XT; // 使能外部晶振 24 | CLOCK_CFG &= ~bOSC_EN_INT; // 关闭内部晶振 25 | #endif 26 | 27 | SAFE_MOD = 0x55; 28 | SAFE_MOD = 0xAA; 29 | CLOCK_CFG &= ~MASK_SYS_CK_SEL; 30 | 31 | SAFE_MOD = 0x55; 32 | SAFE_MOD = 0xAA; 33 | #if FREQ_SYS == 24000000 34 | CLOCK_CFG |= 0x06; // 24MHz 35 | #endif 36 | #if FREQ_SYS == 16000000 37 | CLOCK_CFG |= 0x05; // 16MHz 38 | #endif 39 | #if FREQ_SYS == 12000000 40 | CLOCK_CFG |= 0x04; // 12MHz 41 | #endif 42 | #if FREQ_SYS == 6000000 43 | CLOCK_CFG |= 0x03; // 6MHz 44 | #endif 45 | #if FREQ_SYS == 3000000 46 | CLOCK_CFG |= 0x02; // 3MHz 47 | #endif 48 | #if FREQ_SYS == 750000 49 | CLOCK_CFG |= 0x01; // 750KHz 50 | #endif 51 | #if FREQ_SYS == 187500 52 | CLOCK_CFG |= 0x00; // 187.5KHz 53 | #endif 54 | 55 | SAFE_MOD = 0x00; 56 | } 57 | 58 | /* 59 | * 微秒延时 60 | */ 61 | void delay_us(uint16_t n) { 62 | #ifdef FREQ_SYS 63 | #if FREQ_SYS <= 6000000 64 | n >>= 2; 65 | #endif 66 | #if FREQ_SYS <= 3000000 67 | n >>= 2; 68 | #endif 69 | #if FREQ_SYS <= 750000 70 | n >>= 4; 71 | #endif 72 | #endif 73 | while (n) { // total = 12~13 Fsys cycles, 1uS @Fsys=12MHz 74 | ++ SAFE_MOD; // 2 Fsys cycles, for higher Fsys, add operation here 75 | #ifdef FREQ_SYS 76 | #if FREQ_SYS >= 14000000 77 | ++ SAFE_MOD; 78 | #endif 79 | #if FREQ_SYS >= 16000000 80 | ++ SAFE_MOD; 81 | #endif 82 | #if FREQ_SYS >= 18000000 83 | ++ SAFE_MOD; 84 | #endif 85 | #if FREQ_SYS >= 20000000 86 | ++ SAFE_MOD; 87 | #endif 88 | #if FREQ_SYS >= 22000000 89 | ++ SAFE_MOD; 90 | #endif 91 | #if FREQ_SYS >= 24000000 92 | ++ SAFE_MOD; 93 | #endif 94 | #endif 95 | -- n; 96 | } 97 | } 98 | 99 | /* 100 | * 毫秒延时 101 | */ 102 | void delay(uint16_t n) { 103 | while (n) { 104 | delay_us(1000); 105 | -- n; 106 | } 107 | } 108 | 109 | /* 110 | * 刻计数器更新中断 111 | * 需要注意的是,非总线LED驱动也使用此中断,这种情况下刻计数器更新在 rgb.c 内实现 112 | */ 113 | #if !defined(SIMPAD_V2) 114 | void __tim2Interrupt() __interrupt (INT_NO_TMR2) __using (2) { 115 | if (TF2) { 116 | TF2 = 0; 117 | sysTickCount += 1; 118 | } 119 | } 120 | #endif 121 | 122 | /* 123 | * 系统刻计数初始化 124 | */ 125 | void sysTickConfig() { 126 | #if !defined(SIMPAD_V2) 127 | T2MOD &= ~bT2_CLK; C_T2 = 0; 128 | RCAP2 = T2COUNT = 0xFFFF - (uint16_t) (FREQ_SYS / 12L / 1000L); // 1000Hz 129 | TR2 = 1; 130 | ET2 = 1; 131 | #endif 132 | } 133 | 134 | /* 135 | * 获取当前刻 136 | */ 137 | uint32_t sysGetTickCount() { 138 | return sysTickCount; 139 | } 140 | 141 | /* 142 | * 通过RGB565数据和一个字节的扩展数据得到完整的RGB888 143 | */ 144 | uint32_t sysGetRGB(uint16_t color, uint8_t extend) { 145 | uint32_t val = 0; 146 | val = ((uint32_t) ((color & 0xF800) | ((extend & 0xE0) << 3))) << 8; 147 | val |= ((uint32_t) ((color & 0x07E0) | (extend & 0x18))) << 5; 148 | val |= ((color & 0x001F) << 3) | (extend & 0x07); 149 | return val; 150 | } 151 | 152 | #define KEY_CFG(i) (sysConfig.keyConfig[i]) 153 | #define LED_CFG(i) (sysConfig.ledConfig[i]) 154 | 155 | /* 156 | * 加载系统配置 157 | */ 158 | void sysLoadConfig() { 159 | memset(&sysConfig, 0x00, sizeof(SysConfig)); 160 | 161 | uint16_t btc = 0, tmp = 0, addr = 0; 162 | btc = romRead16i(0x00); // BTC 163 | for (uint8_t i = 0; i < KEY_COUNT; i++) { 164 | KEY_CFG(i).mode = (KeyMode) ((btc >> (2 * i)) & 0x3); 165 | tmp = romRead16i(0x02 + i * 4); // BTx 166 | KEY_CFG(i).marco = (tmp & 0x8000) != 0; 167 | if (!KEY_CFG(i).marco) { 168 | KEY_CFG(i).code = tmp & 0xFF; 169 | } else { 170 | addr = tmp & 0x7FFF; 171 | tmp = romRead16i(0x04 + i * 4); // BTxL 172 | for (uint16_t j = 0; j < tmp; j++) { 173 | if (addr + j < FLASH_SIZE) 174 | KEY_CFG(i).program[j] = romRead8i(addr + j); 175 | else 176 | KEY_CFG(i).program[j] = romRead8e(addr + j); 177 | } 178 | KEY_CFG(i).length = tmp; 179 | } 180 | } 181 | 182 | for (uint8_t i = 0; i < LED_COUNT; i++) { 183 | addr = romRead16i(0x16 + i * 4); // LEDx 184 | tmp = romRead16i(0x18 + i * 4); // LEDxL 185 | LED_CFG(i).marco = (addr != 0xFFFF); 186 | if (!LED_CFG(i).marco) { 187 | addr = romRead8i(0x26 + i * 1); // LEDxEX 188 | LED_CFG(i).color = sysGetRGB(tmp, addr); 189 | } else { 190 | for (uint16_t j = 0; j < tmp; j++) { 191 | if (addr + j < FLASH_SIZE) 192 | LED_CFG(i).program[j] = romRead8i(addr + j); 193 | else 194 | LED_CFG(i).program[j] = romRead8e(addr + j); 195 | } 196 | LED_CFG(i).length = tmp; 197 | } 198 | } 199 | } 200 | 201 | /* 202 | * 获取系统配置指针 203 | */ 204 | SysConfig* sysGetConfig() { 205 | return &sysConfig; 206 | } 207 | -------------------------------------------------------------------------------- /ROM/sys.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS_H 2 | #define __SYS_H 3 | 4 | #include 5 | #include 6 | 7 | #include "bsp.h" 8 | 9 | #define FREQ_SYS 24000000 // 系统主频24MHz 10 | #define OSC_EN_XT 0 // 外部晶振使能,默认开启内部晶振 11 | #define MARCO_MAX 48 // 单个宏指令大小 12 | 13 | void sysClockConfig(); // 时钟选择和配置 14 | void delay_us(uint16_t n); // 以uS为单位延时 15 | void delay(uint16_t n); // 以mS为单位延时 16 | 17 | void sysTickConfig(); 18 | uint32_t sysGetTickCount(); 19 | 20 | // 无宏功能 按下触发宏 抬起触发宏 按住触发宏 21 | typedef enum { KeyNone = 0, KeyDown = 1, KeyUp = 2, KeyPress = 3 } KeyMode; 22 | 23 | typedef struct { // 按键配置结构体 24 | KeyMode mode; 25 | bool marco; 26 | uint8_t code; 27 | uint8_t program[MARCO_MAX]; 28 | uint16_t length; 29 | } KeyConfig; 30 | 31 | typedef struct { // LED配置结构体 32 | bool marco; 33 | uint32_t color; 34 | uint8_t program[MARCO_MAX]; 35 | uint16_t length; 36 | } LEDConfig; 37 | 38 | typedef struct { // 系统配置结构体 39 | KeyConfig keyConfig[KEY_COUNT]; 40 | LEDConfig ledConfig[LED_COUNT]; 41 | } SysConfig; 42 | 43 | uint32_t sysGetRGB(uint16_t color, uint8_t extend); 44 | void sysLoadConfig(); 45 | SysConfig* sysGetConfig(); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /ROM/usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_H 2 | #define __USB_H 3 | 4 | #include 5 | 6 | void usbDevInit(); // USB设备初始化 7 | 8 | void usbSetKeycode(uint8_t i, uint8_t key); // 设置键值 9 | void usbReleaseAll(); // 抬起所有按键 10 | void usbPushKeydata(); // 上传按键数据 11 | 12 | #define HID_BUF 32 // HID数据缓冲大小 13 | //#define USE_EXT_STR // 是否启用额外的字符串描述符 14 | 15 | uint8_t getHIDData(uint8_t index); // 从HID接收缓冲中读取一个字节 16 | void setHIDData(uint8_t index, uint8_t data); // 设置HID发送缓冲区对应偏移的数据 17 | __bit hasHIDData(); // 是否有数据下发 18 | void requestHIDData(); // 请求数据下发 19 | void pushHIDData(); // 将HID发送缓冲区内的数据上传 20 | uint8_t* fetchHIDData(); // 获取HID接收缓冲区的数据 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /Schematic Design/SimPad_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Schematic Design/SimPad_2.pdf -------------------------------------------------------------------------------- /Schematic Design/SimPad_2_Anniversary_Edition.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Schematic Design/SimPad_2_Anniversary_Edition.pdf -------------------------------------------------------------------------------- /Schematic Design/SimPad_Nano.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Schematic Design/SimPad_Nano.pdf -------------------------------------------------------------------------------- /Schematic Design/SimPad_Nano_Anniversary_Edition.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/Schematic Design/SimPad_Nano_Anniversary_Edition.pdf -------------------------------------------------------------------------------- /SimHost/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | -------------------------------------------------------------------------------- /SimHost/HID.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Diagnostics; 4 | using System.Collections.Generic; 5 | using Microsoft.Win32.SafeHandles; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace HID 9 | { 10 | public class Report : EventArgs 11 | { 12 | public readonly byte reportID; 13 | public readonly byte[] reportBuff; 14 | public Report(byte id, byte[] arrayBuff) 15 | { 16 | reportID = id; 17 | reportBuff = arrayBuff; 18 | } 19 | } 20 | public class Hid : Object 21 | { 22 | //public 23 | public const uint GENERIC_READ = 0x80000000; 24 | public const uint GENERIC_WRITE = 0x40000000; 25 | public const uint FILE_SHARE_READ = 0x00000001; 26 | public const uint FILE_SHARE_WRITE = 0x00000002; 27 | public const int OPEN_EXISTING = 3; 28 | 29 | static private IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); 30 | private const int MAX_USB_DEVICES = 64; 31 | //私有变量 32 | private bool deviceOpened = false; //指示设备打开与否 33 | private FileStream hidDevice = null; //异步IO流 34 | IAsyncResult readResult = null; //异步IO流控制 35 | int outputReportLength = 0;//输出报告长度,包括一个字节的报告ID 36 | int inputReportLength = 0;//输入报告长度,包括一个字节的报告ID 37 | //属性 38 | public int OutputReportLength { get { return outputReportLength; } } 39 | public int InputReportLength { get { return inputReportLength; } } 40 | 41 | public Hid() 42 | { 43 | } 44 | 45 | static public HID_RETURN GetDeviceSerialList(UInt16 vID, UInt16 pID, ref List serialList) 46 | { 47 | //列表清空 48 | serialList.Clear(); 49 | //获取所有当前连接的HID列表 50 | List deviceList = new List(); 51 | GetHidDeviceList(ref deviceList); 52 | if (deviceList.Count == 0) 53 | return HID_RETURN.NO_DEVICE_CONECTED; 54 | //依次打开各设备查询设备信息 55 | for (int i = 0; i < deviceList.Count; i++) 56 | { 57 | IntPtr device = CreateFile(deviceList[i], DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE, 0, 0, CREATIONDISPOSITION.OPEN_EXISTING, 0x40000000, 0); 58 | if (device != INVALID_HANDLE_VALUE) 59 | { 60 | //查询设备信息 61 | HIDD_ATTRIBUTES attributes; 62 | IntPtr serialBuff = Marshal.AllocHGlobal(512); 63 | HidD_GetAttributes(device, out attributes); 64 | HidD_GetSerialNumberString(device, serialBuff, 512); 65 | string deviceStr = Marshal.PtrToStringAuto(serialBuff); 66 | Marshal.FreeHGlobal(serialBuff); 67 | if (attributes.VendorID == vID && attributes.ProductID == pID) 68 | { 69 | serialList.Add(deviceStr); 70 | } 71 | //关闭打开的句柄 72 | CloseHandle(device); 73 | } 74 | } 75 | //返回 76 | return HID_RETURN.SUCCESS; 77 | } 78 | 79 | public IntPtr show_List(UInt16 vID, UInt16 pID) 80 | { 81 | int a = 0; 82 | List deviceList = new List(); 83 | GetHidDeviceList(ref deviceList); 84 | if (deviceList.Count == 0) 85 | { 86 | return INVALID_HANDLE_VALUE; 87 | } 88 | for (int i = 0; i < deviceList.Count; i++) 89 | { 90 | IntPtr device = CreateFile(deviceList[i], DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE, 91 | 0, 0, CREATIONDISPOSITION.OPEN_EXISTING, 0x40000000, 0); 92 | if (device != INVALID_HANDLE_VALUE) 93 | { 94 | HIDD_ATTRIBUTES attributes; 95 | IntPtr serialBuff = Marshal.AllocHGlobal(512); 96 | if (!HidD_GetAttributes(device, out attributes)) 97 | { 98 | CloseHandle(device); 99 | return INVALID_HANDLE_VALUE; 100 | } 101 | HidD_GetSerialNumberString(device, serialBuff, 512); 102 | string deviceStr = Marshal.PtrToStringAuto(serialBuff); 103 | Marshal.FreeHGlobal(serialBuff); 104 | if (attributes.VendorID == vID && attributes.ProductID == pID) 105 | { 106 | //Debug.WriteLine(a+"a:"+attributes.ToString()); 107 | //a++; 108 | //IntPtr pre 109 | } 110 | } 111 | CloseHandle(device); 112 | } 113 | return INVALID_HANDLE_VALUE; 114 | } 115 | 116 | /// 117 | /// 打开指定信息的设备 118 | /// 119 | /// 设备的vID 120 | /// 设备的pID 121 | /// 设备的serial 122 | /// 123 | public IntPtr OpenDevice(UInt16 vID, UInt16 pID, Byte mID) 124 | { 125 | Debug.WriteLine(deviceOpened); 126 | Debug.WriteLine("设备未打开,开始打开设备:" + " " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); 127 | if (deviceOpened == false) 128 | { 129 | Debug.WriteLine("开始获取HID设备:"); 130 | //获取连接的HID列表 131 | List deviceList = new List(); 132 | 133 | GetHidDeviceList(ref deviceList); 134 | Debug.WriteLine("获取HID设备完成."); 135 | if (deviceList.Count == 0) 136 | { 137 | return INVALID_HANDLE_VALUE; 138 | } 139 | 140 | for (int i = 0; i < deviceList.Count; i++) 141 | { 142 | Debug.WriteLine("deviceList[" + i + "] " + deviceList[i] + " " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); 143 | IntPtr device = CreateFile(deviceList[i], DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE, 144 | 0, 0, CREATIONDISPOSITION.OPEN_EXISTING, 0x40000000, 0); 145 | Debug.WriteLine(deviceList[i]); 146 | if (device != INVALID_HANDLE_VALUE) 147 | { 148 | HIDD_ATTRIBUTES attributes; 149 | IntPtr serialBuff = Marshal.AllocHGlobal(512); 150 | //HidD_GetAttributes(device, out attributes); 151 | 152 | if (!HidD_GetAttributes(device, out attributes)) 153 | { 154 | CloseHandle(device); 155 | return INVALID_HANDLE_VALUE; 156 | } 157 | 158 | HidD_GetSerialNumberString(device, serialBuff, 512); 159 | 160 | 161 | string deviceStr = Marshal.PtrToStringAuto(serialBuff); 162 | Marshal.FreeHGlobal(serialBuff); 163 | 164 | Debug.WriteLine("VID: " + attributes.VendorID.ToString("x4")); 165 | Debug.WriteLine("PID: " + attributes.ProductID.ToString("x4")); 166 | 167 | if (attributes.VendorID == vID && attributes.ProductID == pID) 168 | { 169 | IntPtr preparseData; 170 | HIDP_CAPS caps; 171 | HidD_GetPreparsedData(device, out preparseData); 172 | HidP_GetCaps(preparseData, out caps); 173 | HidD_FreePreparsedData(preparseData); 174 | outputReportLength = caps.OutputReportByteLength; 175 | inputReportLength = caps.InputReportByteLength; 176 | 177 | hidDevice = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite, inputReportLength, true); 178 | deviceOpened = true; 179 | //开始异步读 180 | BeginAsyncRead(); 181 | return device; 182 | } 183 | } 184 | 185 | CloseHandle(device); 186 | } 187 | 188 | return INVALID_HANDLE_VALUE; 189 | } 190 | else 191 | return INVALID_HANDLE_VALUE; 192 | } 193 | 194 | public bool Opened 195 | { 196 | get 197 | { 198 | return deviceOpened; 199 | } 200 | } 201 | /// 202 | /// 关闭打开的设备 203 | /// 204 | public void CloseDevice(IntPtr device) 205 | { 206 | if (deviceOpened == true) 207 | { 208 | deviceOpened = false; 209 | hidDevice.Close(); 210 | CloseHandle(device); 211 | } 212 | } 213 | 214 | /// 215 | /// 开始一次异步读,开始读数据之前,必须加个判断,不然卡死。 216 | /// 关闭设备的时候有可能导致无法读取关闭的数据。 217 | /// 218 | private void BeginAsyncRead() 219 | { 220 | byte[] inputBuff = new byte[InputReportLength]; 221 | //.BeginRead为异步读操作 222 | if (deviceOpened == true) 223 | readResult = hidDevice.BeginRead(inputBuff, 0, InputReportLength, new AsyncCallback(ReadCompleted), inputBuff); 224 | 225 | } 226 | /// 227 | /// 异步读取结束,发出有数据到达事件 228 | /// 229 | /// 这里是输入报告的数组 230 | private void ReadCompleted(IAsyncResult iResult) 231 | { 232 | byte[] readBuff = (byte[])(iResult.AsyncState); 233 | try 234 | { 235 | if (deviceOpened == true) 236 | { 237 | hidDevice.EndRead(iResult);//读取结束,如果读取错误就会产生一个异常 238 | byte[] reportData = new byte[readBuff.Length - 1]; 239 | for (int i = 1; i < readBuff.Length; i++) 240 | reportData[i - 1] = readBuff[i]; 241 | Report e = new Report(readBuff[0], reportData); 242 | OnDataReceived(e); //发出数据到达消息 243 | BeginAsyncRead();//启动下一次读操作 244 | } 245 | } 246 | catch (IOException e)//读写错误,设备可能已经被移除 247 | { 248 | EventArgs ex = new EventArgs(); 249 | OnDeviceRemoved(ex);//发出设备移除消息 250 | } 251 | } 252 | 253 | /// 254 | /// 事件:数据到达,处理此事件以接收输入数据 255 | /// 256 | public event EventHandler DataReceived; 257 | protected virtual void OnDataReceived(Report e) 258 | { 259 | DataReceived.Invoke(this, e); 260 | } 261 | 262 | /// 263 | /// 事件:设备断开 264 | /// 265 | public event EventHandler DeviceRemoved; 266 | protected virtual void OnDeviceRemoved(EventArgs e) 267 | { 268 | deviceOpened = false; 269 | if (DeviceRemoved != null) 270 | { 271 | DeviceRemoved(this, e); 272 | } 273 | } 274 | 275 | /// 276 | /// 277 | /// 278 | /// 279 | /// 280 | public HID_RETURN Write(Report r) 281 | { 282 | if (deviceOpened) 283 | { 284 | try 285 | { 286 | byte[] buffer = new byte[outputReportLength]; 287 | buffer[0] = r.reportID; 288 | int maxBufferLength = 0; 289 | if (r.reportBuff.Length < outputReportLength - 1) 290 | maxBufferLength = r.reportBuff.Length; 291 | else 292 | maxBufferLength = outputReportLength - 1; 293 | for (int i = 1; i <= maxBufferLength; i++) 294 | buffer[i] = r.reportBuff[i - 1]; 295 | hidDevice.Write(buffer, 0, OutputReportLength); 296 | return HID_RETURN.SUCCESS; 297 | } 298 | catch 299 | { 300 | EventArgs ex = new EventArgs(); 301 | OnDeviceRemoved(ex);//发出设备移除消息 302 | } 303 | } 304 | return HID_RETURN.WRITE_FAILD; 305 | } 306 | 307 | /// 308 | /// 获取所有连接的hid的设备路径 309 | /// 310 | /// 包含每个设备路径的字符串数组 311 | public static void GetHidDeviceList(ref List deviceList) 312 | { 313 | Guid hUSB = Guid.Empty; 314 | uint index = 0; 315 | Debug.WriteLine("清除上一次的设备列表."); 316 | deviceList.Clear(); 317 | Debug.WriteLine("清除Ok."); 318 | Debug.WriteLine("开始获取HID设备全局ID."); 319 | // 取得hid设备全局id 320 | HidD_GetHidGuid(ref hUSB); 321 | Debug.WriteLine("获取HID设备全局ID OK."); 322 | Debug.WriteLine("GUID: " + hUSB); 323 | //取得一个包含所有HID接口信息集合的句柄 324 | IntPtr hidInfoSet = SetupDiGetClassDevs(ref hUSB, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE); 325 | if (hidInfoSet != IntPtr.Zero) 326 | { 327 | SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA(); 328 | interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo); 329 | //查询集合中每一个接口 330 | Debug.WriteLine("查询HID详细接口信息."); 331 | for (index = 0; index < MAX_USB_DEVICES; index++) 332 | { 333 | //得到第index个接口信息 334 | if (SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUSB, index, ref interfaceInfo)) 335 | { 336 | 337 | int buffsize = 0; 338 | // 取得接口详细信息:第一次读取错误,但可以取得信息缓冲区的大小 339 | SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, IntPtr.Zero, buffsize, ref buffsize, null); 340 | //构建接收缓冲 341 | IntPtr pDetail = Marshal.AllocHGlobal(buffsize); 342 | SP_DEVICE_INTERFACE_DETAIL_DATA detail = new SP_DEVICE_INTERFACE_DETAIL_DATA(); 343 | detail.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA)); 344 | Marshal.StructureToPtr(detail, pDetail, false); 345 | if (SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null)) 346 | { 347 | Debug.WriteLine("往deviceList " + index + 1 + " 中加入HID详细接口信息. " + (Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4)))); 348 | deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4))); 349 | } 350 | Marshal.FreeHGlobal(pDetail); 351 | } 352 | //else 353 | // Debug.WriteLine("查询第 " + index + " 个HID设备接口信息." + SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUSB, index, ref interfaceInfo)); 354 | } 355 | } 356 | SetupDiDestroyDeviceInfoList(hidInfoSet); 357 | //return deviceList.ToArray(); 358 | } 359 | 360 | public enum HID_RETURN 361 | { 362 | SUCCESS = 0, 363 | NO_DEVICE_CONECTED, 364 | DEVICE_NOT_FIND, 365 | DEVICE_OPENED, 366 | WRITE_FAILD, 367 | READ_FAILD 368 | 369 | } 370 | 371 | 372 | // 以下是调用windows的API的函数 373 | /// 374 | /// The HidD_GetHidGuid routine returns the device interface GUID for HIDClass devices. 375 | /// 376 | /// a caller-allocated GUID buffer that the routine uses to return the device interface GUID for HIDClass devices. 377 | // 获得GUID 378 | [DllImport("hid.dll")] 379 | public static extern void HidD_GetHidGuid(ref Guid HidGuid); 380 | 381 | /// 382 | /// The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local machine. 383 | /// 384 | /// GUID for a device setup class or a device interface class. 385 | /// A pointer to a NULL-terminated string that supplies the name of a PnP enumerator or a PnP device instance identifier. 386 | /// A handle of the top-level window to be used for a user interface 387 | /// A variable that specifies control options that filter the device information elements that are added to the device information set. 388 | /// a handle to a device information set 389 | //过滤设备,获取需要的设备 390 | [DllImport("setupapi.dll", SetLastError = true)] 391 | public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags); 392 | 393 | /// 394 | /// The SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory. 395 | /// 396 | /// A handle to the device information set to delete. 397 | /// returns TRUE if it is successful. Otherwise, it returns FALSE 398 | [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] 399 | public static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); 400 | 401 | /// 402 | /// The SetupDiEnumDeviceInterfaces function enumerates the device interfaces that are contained in a device information set. 403 | /// 404 | /// A pointer to a device information set that contains the device interfaces for which to return information 405 | /// A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet 406 | /// a GUID that specifies the device interface class for the requested interface 407 | /// A zero-based index into the list of interfaces in the device information set 408 | /// a caller-allocated buffer that contains a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters 409 | /// 410 | //获取设备,true获取到 411 | [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] 412 | public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); 413 | 414 | /// 415 | /// The SetupDiGetDeviceInterfaceDetail function returns details about a device interface. 416 | /// 417 | /// A pointer to the device information set that contains the interface for which to retrieve details 418 | /// A pointer to an SP_DEVICE_INTERFACE_DATA structure that specifies the interface in DeviceInfoSet for which to retrieve details 419 | /// A pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information about the specified interface 420 | /// The size of the DeviceInterfaceDetailData buffer 421 | /// A pointer to a variable that receives the required size of the DeviceInterfaceDetailData buffer 422 | /// A pointer buffer to receive information about the device that supports the requested interface 423 | /// 424 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 425 | public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData); 426 | 427 | /// 428 | /// The HidD_GetAttributes routine returns the attributes of a specified top-level collection. 429 | /// 430 | /// Specifies an open handle to a top-level collection 431 | /// a caller-allocated HIDD_ATTRIBUTES structure that returns the attributes of the collection specified by HidDeviceObject 432 | /// 433 | [DllImport("hid.dll")] 434 | public static extern Boolean HidD_GetAttributes(IntPtr hidDeviceObject, out HIDD_ATTRIBUTES attributes); 435 | /// 436 | /// The HidD_GetSerialNumberString routine returns the embedded string of a top-level collection that identifies the serial number of the collection's physical device. 437 | /// 438 | /// Specifies an open handle to a top-level collection 439 | /// a caller-allocated buffer that the routine uses to return the requested serial number string 440 | /// Specifies the length, in bytes, of a caller-allocated buffer provided at Buffer 441 | /// 442 | [DllImport("hid.dll")] 443 | public static extern Boolean HidD_GetSerialNumberString(IntPtr hidDeviceObject, IntPtr buffer, int bufferLength); 444 | 445 | /// 446 | /// The HidD_GetPreparsedData routine returns a top-level collection's preparsed data. 447 | /// 448 | /// Specifies an open handle to a top-level collection. 449 | /// Pointer to the address of a routine-allocated buffer that contains a collection's preparsed data in a _HIDP_PREPARSED_DATA structure. 450 | /// HidD_GetPreparsedData returns TRUE if it succeeds; otherwise, it returns FALSE. 451 | [DllImport("hid.dll")] 452 | public static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData); 453 | 454 | [DllImport("hid.dll")] 455 | public static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData); 456 | 457 | [DllImport("hid.dll")] 458 | public static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities); 459 | 460 | 461 | /// 462 | /// This function creates, opens, or truncates a file, COM port, device, service, or console. 463 | /// 464 | /// a null-terminated string that specifies the name of the object 465 | /// Type of access to the object 466 | /// Share mode for object 467 | /// Ignored; set to NULL 468 | /// Action to take on files that exist, and which action to take when files do not exist 469 | /// File attributes and flags for the file 470 | /// Ignored 471 | /// An open handle to the specified file indicates success 472 | [DllImport("kernel32.dll", SetLastError = true)] 473 | public static extern IntPtr CreateFile(string fileName, uint desiredAccess, uint shareMode, uint securityAttributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile); 474 | 475 | /// 476 | /// This function closes an open object handle. 477 | /// 478 | /// Handle to an open object 479 | /// 480 | [DllImport("kernel32.dll")] 481 | public static extern int CloseHandle(IntPtr hObject); 482 | 483 | /// 484 | /// This function reads data from a file, starting at the position indicated by the file pointer. 485 | /// 486 | /// Handle to the file to be read 487 | /// Pointer to the buffer that receives the data read from the file 488 | /// Number of bytes to be read from the file 489 | /// Pointer to the number of bytes read 490 | /// Unsupported; set to NULL 491 | /// 492 | [DllImport("Kernel32.dll", SetLastError = true)] 493 | public static extern bool ReadFile(IntPtr file, byte[] buffer, uint numberOfBytesToRead, out uint numberOfBytesRead, IntPtr lpOverlapped); 494 | 495 | /// 496 | /// This function writes data to a file 497 | /// 498 | /// Handle to the file to be written to 499 | /// Pointer to the buffer containing the data to write to the file 500 | /// Number of bytes to write to the file 501 | /// Pointer to the number of bytes written by this function call 502 | /// Unsupported; set to NULL 503 | /// 504 | [DllImport("Kernel32.dll", SetLastError = true)] 505 | public static extern bool WriteFile(IntPtr file, byte[] buffer, uint numberOfBytesToWrite, out uint numberOfBytesWritten, IntPtr lpOverlapped); 506 | 507 | /// 508 | /// Registers the device or type of device for which a window will receive notifications 509 | /// 510 | /// A handle to the window or service that will receive device events for the devices specified in the NotificationFilter parameter 511 | /// A pointer to a block of data that specifies the type of device for which notifications should be sent 512 | /// A Flags that specify the handle type 513 | /// If the function succeeds, the return value is a device notification handle 514 | [DllImport("User32.dll", SetLastError = true)] 515 | public static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags); 516 | [StructLayout(LayoutKind.Explicit)] 517 | public struct DevBroadcastDeviceInterfaceBuffer 518 | { 519 | public DevBroadcastDeviceInterfaceBuffer(Int32 deviceType) 520 | { 521 | dbch_size = Marshal.SizeOf(typeof(DevBroadcastDeviceInterfaceBuffer)); 522 | dbch_devicetype = deviceType; 523 | dbch_reserved = 0; 524 | } 525 | 526 | [FieldOffset(0)] 527 | public Int32 dbch_size; 528 | [FieldOffset(4)] 529 | public Int32 dbch_devicetype; 530 | [FieldOffset(8)] 531 | public Int32 dbch_reserved; 532 | } 533 | 534 | static public IntPtr RegisterHIDNotification(IntPtr recipient) 535 | { 536 | IntPtr dbch = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DevBroadcastDeviceInterfaceBuffer))); 537 | Marshal.StructureToPtr(new DevBroadcastDeviceInterfaceBuffer(5), dbch, false); //devicetype == DBT_DEVTYP_DEVICEINTERFACE(0x00000005) 538 | return RegisterDeviceNotification(recipient, dbch, 0); 539 | } 540 | 541 | /// 542 | /// Closes the specified device notification handle. 543 | /// 544 | /// Device notification handle returned by the RegisterDeviceNotification function 545 | /// 546 | [DllImport("user32.dll", SetLastError = true)] 547 | public static extern bool UnregisterDeviceNotification(IntPtr handle); 548 | static public bool UnRegisterHIDNotification(IntPtr hDEVNotify) 549 | { 550 | return UnregisterDeviceNotification(hDEVNotify); 551 | } 552 | } 553 | #region 554 | /// 555 | /// SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set. 556 | /// 557 | public struct SP_DEVICE_INTERFACE_DATA 558 | { 559 | public int cbSize; 560 | public Guid interfaceClassGuid; 561 | public int flags; 562 | public int reserved; 563 | } 564 | 565 | /// 566 | /// SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface. 567 | /// 568 | [StructLayout(LayoutKind.Sequential, Pack = 2)] 569 | internal struct SP_DEVICE_INTERFACE_DETAIL_DATA 570 | { 571 | internal int cbSize; 572 | internal short devicePath; 573 | } 574 | 575 | /// 576 | /// SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set. 577 | /// 578 | [StructLayout(LayoutKind.Sequential)] 579 | public class SP_DEVINFO_DATA 580 | { 581 | public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); 582 | public Guid classGuid = Guid.Empty; // temp 583 | public int devInst = 0; // dumy 584 | public int reserved = 0; 585 | } 586 | /// 587 | /// Flags controlling what is included in the device information set built by SetupDiGetClassDevs 588 | /// 589 | public enum DIGCF 590 | { 591 | DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE 592 | DIGCF_PRESENT = 0x00000002, 593 | DIGCF_ALLCLASSES = 0x00000004, 594 | DIGCF_PROFILE = 0x00000008, 595 | DIGCF_DEVICEINTERFACE = 0x00000010 596 | } 597 | /// 598 | /// The HIDD_ATTRIBUTES structure contains vendor information about a HIDClass device 599 | /// 600 | public struct HIDD_ATTRIBUTES 601 | { 602 | public int Size; 603 | public ushort VendorID; 604 | public ushort ProductID; 605 | public ushort VersionNumber; 606 | } 607 | 608 | public struct HIDP_CAPS 609 | { 610 | public ushort Usage; 611 | public ushort UsagePage; 612 | public ushort InputReportByteLength; 613 | public ushort OutputReportByteLength; 614 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] 615 | public ushort[] Reserved; 616 | public ushort NumberLinkCollectionNodes; 617 | public ushort NumberInputButtonCaps; 618 | public ushort NumberInputValueCaps; 619 | public ushort NumberInputDataIndices; 620 | public ushort NumberOutputButtonCaps; 621 | public ushort NumberOutputValueCaps; 622 | public ushort NumberOutputDataIndices; 623 | public ushort NumberFeatureButtonCaps; 624 | public ushort NumberFeatureValueCaps; 625 | public ushort NumberFeatureDataIndices; 626 | } 627 | /// 628 | /// Type of access to the object. 629 | /// 630 | static class DESIREDACCESS 631 | { 632 | public const uint GENERIC_READ = 0x80000000; 633 | public const uint GENERIC_WRITE = 0x40000000; 634 | public const uint GENERIC_EXECUTE = 0x20000000; 635 | public const uint GENERIC_ALL = 0x10000000; 636 | } 637 | /// 638 | /// Action to take on files that exist, and which action to take when files do not exist. 639 | /// 640 | static class CREATIONDISPOSITION 641 | { 642 | public const uint CREATE_NEW = 1; 643 | public const uint CREATE_ALWAYS = 2; 644 | public const uint OPEN_EXISTING = 3; 645 | public const uint OPEN_ALWAYS = 4; 646 | public const uint TRUNCATE_EXISTING = 5; 647 | } 648 | /// 649 | /// File attributes and flags for the file. 650 | /// 651 | static class FLAGSANDATTRIBUTES 652 | { 653 | public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; 654 | public const uint FILE_FLAG_OVERLAPPED = 0x40000000; 655 | public const uint FILE_FLAG_NO_BUFFERING = 0x20000000; 656 | public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000; 657 | public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; 658 | public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; 659 | public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; 660 | public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000; 661 | public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; 662 | public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000; 663 | public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000; 664 | } 665 | /// 666 | /// Serves as a standard header for information related to a device event reported through the WM_DEVICECHANGE message. 667 | /// 668 | [StructLayout(LayoutKind.Sequential)] 669 | public struct DEV_BROADCAST_HDR 670 | { 671 | public int dbcc_size; 672 | public int dbcc_devicetype; 673 | public int dbcc_reserved; 674 | } 675 | /// 676 | /// Contains information about a class of devices 677 | /// 678 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 679 | public struct DEV_BROADCAST_DEVICEINTERFACE 680 | { 681 | public int dbcc_size; 682 | public int dbcc_devicetype; 683 | public int dbcc_reserved; 684 | public Guid dbcc_classguid; 685 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 686 | public string dbcc_name; 687 | } 688 | #endregion 689 | } 690 | -------------------------------------------------------------------------------- /SimHost/HelpForm.Designer.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace SimHost 3 | { 4 | partial class HelpForm 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Windows Form Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HelpForm)); 33 | this.infoBox = new System.Windows.Forms.RichTextBox(); 34 | this.SuspendLayout(); 35 | // 36 | // infoBox 37 | // 38 | this.infoBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 39 | | System.Windows.Forms.AnchorStyles.Left) 40 | | System.Windows.Forms.AnchorStyles.Right))); 41 | this.infoBox.Location = new System.Drawing.Point(12, 12); 42 | this.infoBox.Name = "infoBox"; 43 | this.infoBox.ReadOnly = true; 44 | this.infoBox.Size = new System.Drawing.Size(710, 537); 45 | this.infoBox.TabIndex = 0; 46 | this.infoBox.Text = resources.GetString("infoBox.Text"); 47 | // 48 | // HelpForm 49 | // 50 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 51 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 52 | this.ClientSize = new System.Drawing.Size(734, 561); 53 | this.Controls.Add(this.infoBox); 54 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 55 | this.MinimumSize = new System.Drawing.Size(750, 600); 56 | this.Name = "HelpForm"; 57 | this.ShowInTaskbar = false; 58 | this.Text = "SimCore Help | using NSASM"; 59 | this.TopMost = true; 60 | this.Load += new System.EventHandler(this.HelpForm_Load); 61 | this.ResumeLayout(false); 62 | 63 | } 64 | 65 | #endregion 66 | 67 | private System.Windows.Forms.RichTextBox infoBox; 68 | } 69 | } -------------------------------------------------------------------------------- /SimHost/HelpForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | using dotNSASM; 5 | 6 | namespace SimHost 7 | { 8 | public partial class HelpForm : Form 9 | { 10 | public HelpForm() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void HelpForm_Load(object sender, EventArgs e) 16 | { 17 | Text += (" ver" + NSASM.Version); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SimHost/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace SimHost 3 | { 4 | partial class MainForm 5 | { 6 | /// 7 | /// 必需的设计器变量。 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// 清理所有正在使用的资源。 13 | /// 14 | /// 如果应释放托管资源,为 true;否则为 false。 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Windows 窗体设计器生成的代码 25 | 26 | /// 27 | /// 设计器支持所需的方法 - 不要修改 28 | /// 使用代码编辑器修改此方法的内容。 29 | /// 30 | private void InitializeComponent() 31 | { 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); 33 | this.statusBar = new System.Windows.Forms.StatusStrip(); 34 | this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel(); 35 | this.codeBox = new System.Windows.Forms.RichTextBox(); 36 | this.btnRun = new System.Windows.Forms.Button(); 37 | this.outputBox = new System.Windows.Forms.RichTextBox(); 38 | this.devList = new System.Windows.Forms.ComboBox(); 39 | this.btnConnect = new System.Windows.Forms.Button(); 40 | this.statusBar.SuspendLayout(); 41 | this.SuspendLayout(); 42 | // 43 | // statusBar 44 | // 45 | this.statusBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 46 | this.statusLabel}); 47 | this.statusBar.Location = new System.Drawing.Point(0, 419); 48 | this.statusBar.Name = "statusBar"; 49 | this.statusBar.Size = new System.Drawing.Size(304, 22); 50 | this.statusBar.TabIndex = 0; 51 | // 52 | // statusLabel 53 | // 54 | this.statusLabel.Name = "statusLabel"; 55 | this.statusLabel.Size = new System.Drawing.Size(151, 17); 56 | this.statusLabel.Text = "SimHost | NSDN © 2021"; 57 | this.statusLabel.Click += new System.EventHandler(this.statusLabel_Click); 58 | // 59 | // codeBox 60 | // 61 | this.codeBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 62 | | System.Windows.Forms.AnchorStyles.Left) 63 | | System.Windows.Forms.AnchorStyles.Right))); 64 | this.codeBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 65 | this.codeBox.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 66 | this.codeBox.Location = new System.Drawing.Point(12, 12); 67 | this.codeBox.Name = "codeBox"; 68 | this.codeBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; 69 | this.codeBox.Size = new System.Drawing.Size(280, 297); 70 | this.codeBox.TabIndex = 1; 71 | this.codeBox.Text = ""; 72 | // 73 | // btnRun 74 | // 75 | this.btnRun.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 76 | this.btnRun.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); 77 | this.btnRun.Location = new System.Drawing.Point(228, 315); 78 | this.btnRun.Name = "btnRun"; 79 | this.btnRun.Size = new System.Drawing.Size(64, 24); 80 | this.btnRun.TabIndex = 2; 81 | this.btnRun.Text = "Execute"; 82 | this.btnRun.UseVisualStyleBackColor = true; 83 | this.btnRun.Click += new System.EventHandler(this.btnRun_Click); 84 | // 85 | // outputBox 86 | // 87 | this.outputBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 88 | | System.Windows.Forms.AnchorStyles.Right))); 89 | this.outputBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 90 | this.outputBox.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 91 | this.outputBox.Location = new System.Drawing.Point(12, 345); 92 | this.outputBox.Name = "outputBox"; 93 | this.outputBox.ReadOnly = true; 94 | this.outputBox.Size = new System.Drawing.Size(280, 64); 95 | this.outputBox.TabIndex = 3; 96 | this.outputBox.Text = ""; 97 | // 98 | // devList 99 | // 100 | this.devList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 101 | | System.Windows.Forms.AnchorStyles.Right))); 102 | this.devList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 103 | this.devList.FormattingEnabled = true; 104 | this.devList.Items.AddRange(new object[] { 105 | "SimPad v2", 106 | "SimPad v2 - Extra", 107 | "SimPad v2 - Lite", 108 | "SimPad Nano", 109 | "SimPad 3", 110 | "SimPad v2 - AE", 111 | "SimPad Nano - AE", 112 | "SimKey", 113 | "SimPad Boot"}); 114 | this.devList.Location = new System.Drawing.Point(12, 317); 115 | this.devList.Name = "devList"; 116 | this.devList.Size = new System.Drawing.Size(140, 20); 117 | this.devList.TabIndex = 4; 118 | // 119 | // btnConnect 120 | // 121 | this.btnConnect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 122 | this.btnConnect.Location = new System.Drawing.Point(158, 315); 123 | this.btnConnect.Name = "btnConnect"; 124 | this.btnConnect.Size = new System.Drawing.Size(64, 24); 125 | this.btnConnect.TabIndex = 5; 126 | this.btnConnect.Text = "Connect"; 127 | this.btnConnect.UseVisualStyleBackColor = true; 128 | this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click); 129 | // 130 | // MainForm 131 | // 132 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 133 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 134 | this.ClientSize = new System.Drawing.Size(304, 441); 135 | this.Controls.Add(this.btnConnect); 136 | this.Controls.Add(this.devList); 137 | this.Controls.Add(this.outputBox); 138 | this.Controls.Add(this.btnRun); 139 | this.Controls.Add(this.codeBox); 140 | this.Controls.Add(this.statusBar); 141 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 142 | this.MinimumSize = new System.Drawing.Size(320, 480); 143 | this.Name = "MainForm"; 144 | this.Text = "SimHost"; 145 | this.statusBar.ResumeLayout(false); 146 | this.statusBar.PerformLayout(); 147 | this.ResumeLayout(false); 148 | this.PerformLayout(); 149 | 150 | } 151 | 152 | #endregion 153 | 154 | private System.Windows.Forms.StatusStrip statusBar; 155 | private System.Windows.Forms.RichTextBox codeBox; 156 | private System.Windows.Forms.Button btnRun; 157 | private System.Windows.Forms.RichTextBox outputBox; 158 | private System.Windows.Forms.ToolStripStatusLabel statusLabel; 159 | private System.Windows.Forms.ComboBox devList; 160 | private System.Windows.Forms.Button btnConnect; 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /SimHost/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Windows.Forms; 4 | using System.Collections.Generic; 5 | 6 | using dotNSASM; 7 | using HID; 8 | 9 | namespace SimHost 10 | { 11 | public partial class MainForm : Form 12 | { 13 | class SimCore : NSASM 14 | { 15 | readonly List byteCode; 16 | 17 | SimCore(string[][] code) : base(16, 16, 8, code) 18 | { 19 | byteCode = new List(); 20 | } 21 | 22 | public static SimCore GetSimCore(string code) 23 | { 24 | var c = Util.GetSegments(code); 25 | return new SimCore(c); 26 | } 27 | 28 | protected override NSASM Instance(NSASM super, string[][] code) 29 | { 30 | return new SimCore(code); 31 | } 32 | 33 | public byte[][] GetBytes() 34 | { 35 | return byteCode.ToArray(); 36 | } 37 | 38 | protected override void LoadFuncList() 39 | { 40 | funcList.Add("nop", (dst, src, ext) => 41 | { 42 | if (dst == null && src == null) 43 | { 44 | byteCode.Add(new byte[] { 0x00 }); 45 | return Result.OK; 46 | } 47 | return Result.ERR; 48 | }); 49 | 50 | funcList.Add("jmp", (dst, src, ext) => 51 | { 52 | if (src != null) return Result.ERR; 53 | if (dst == null) return Result.ERR; 54 | if (dst.type != RegType.INT) return Result.ERR; 55 | 56 | ushort i = (ushort)(((int)dst.data) & 0xFFFF); 57 | byteCode.Add(new byte[] { 58 | 0x01, 59 | 0x00, 60 | (byte)(i & 0x00FF), 61 | (byte)((i & 0xFF00) >> 8) 62 | }); 63 | 64 | return Result.OK; 65 | }); 66 | 67 | funcList.Add("clr", (dst, src, ext) => 68 | { 69 | if (dst == null && src == null) 70 | { 71 | byteCode.Add(new byte[] { 0x02 }); 72 | return Result.OK; 73 | } 74 | return Result.ERR; 75 | }); 76 | 77 | funcList.Add("prt", (dst, src, ext) => 78 | { 79 | if (src != null) return Result.ERR; 80 | if (dst == null) return Result.ERR; 81 | if (dst.type != RegType.CHAR && dst.type != RegType.INT && dst.type != RegType.STR) 82 | return Result.ERR; 83 | 84 | if (dst.type == RegType.STR) 85 | { 86 | string str = (string)dst.data; 87 | for (int i = 0; i < str.Length; i++) 88 | { 89 | byteCode.Add(new byte[] { 90 | 0x03, 91 | (byte)str[i] 92 | }); 93 | } 94 | } 95 | else 96 | { 97 | byte i; 98 | if (dst.type == RegType.CHAR) 99 | i = (byte)(((char)dst.data) & 0xFF); 100 | else 101 | i = (byte)(((int)dst.data) & 0xFF); 102 | byteCode.Add(new byte[] { 103 | 0x03, 104 | i 105 | }); 106 | } 107 | 108 | return Result.OK; 109 | }); 110 | 111 | funcList.Add("hidp", (dst, src, ext) => 112 | { 113 | if (dst == null && src == null) 114 | { 115 | byteCode.Add(new byte[] { 0x04 }); 116 | return Result.OK; 117 | } 118 | return Result.ERR; 119 | }); 120 | 121 | funcList.Add("strp", (dst, src, ext) => 122 | { 123 | if (src != null) return Result.ERR; 124 | if (dst == null) return Result.ERR; 125 | if (dst.type != RegType.INT) return Result.ERR; 126 | 127 | byte i = (byte)(((int)dst.data) & 0xFF); 128 | byteCode.Add(new byte[] { 129 | 0x05, 130 | i 131 | }); 132 | 133 | return Result.OK; 134 | }); 135 | 136 | funcList.Add("out", (dst, src, ext) => 137 | { 138 | if (src == null) return Result.ERR; 139 | if (dst == null) return Result.ERR; 140 | if (dst.type != RegType.INT) return Result.ERR; 141 | if (src.type != RegType.INT) return Result.ERR; 142 | 143 | byte i = (byte)(((int)dst.data) & 0xFF); 144 | byte j = (byte)(((int)src.data) & 0xFF); 145 | byteCode.Add(new byte[] { 146 | 0x06, 147 | i, 148 | j, 149 | 0x00 150 | }); 151 | 152 | return Result.OK; 153 | }); 154 | 155 | funcList.Add("keyp", (dst, src, ext) => 156 | { 157 | if (dst == null && src == null) 158 | { 159 | byteCode.Add(new byte[] { 0x07 }); 160 | return Result.OK; 161 | } 162 | return Result.ERR; 163 | }); 164 | 165 | funcList.Add("ldi", (dst, src, ext) => 166 | { 167 | if (src == null) return Result.ERR; 168 | if (dst == null) return Result.ERR; 169 | if (dst.type != RegType.INT) return Result.ERR; 170 | if (src.type != RegType.INT) return Result.ERR; 171 | 172 | byte i = (byte)(((int)dst.data) & 0xFF); 173 | ushort j = (ushort)(((int)src.data) & 0xFFFF); 174 | byteCode.Add(new byte[] { 175 | 0x08, 176 | i, 177 | (byte)(j & 0x00FF), 178 | (byte)((j & 0xFF00) >> 8) 179 | }); 180 | 181 | return Result.OK; 182 | }); 183 | 184 | funcList.Add("lde", (dst, src, ext) => 185 | { 186 | if (src == null) return Result.ERR; 187 | if (dst == null) return Result.ERR; 188 | if (dst.type != RegType.INT) return Result.ERR; 189 | if (src.type != RegType.INT) return Result.ERR; 190 | 191 | byte i = (byte)(((int)dst.data) & 0xFF); 192 | ushort j = (ushort)(((int)src.data) & 0xFFFF); 193 | byteCode.Add(new byte[] { 194 | 0x09, 195 | i, 196 | (byte)(j & 0x00FF), 197 | (byte)((j & 0xFF00) >> 8) 198 | }); 199 | 200 | return Result.OK; 201 | }); 202 | 203 | funcList.Add("wri", (dst, src, ext) => 204 | { 205 | if (src == null) return Result.ERR; 206 | if (dst == null) return Result.ERR; 207 | if (dst.type != RegType.INT) return Result.ERR; 208 | if (src.type != RegType.INT) return Result.ERR; 209 | 210 | ushort i = (ushort)(((int)src.data) & 0xFFFF); 211 | ushort j = (ushort)(((int)dst.data) & 0xFFFF); 212 | byteCode.Add(new byte[] { 213 | 0x0A, 214 | (byte)(i & 0x00FF), 215 | (byte)(j & 0x00FF), 216 | (byte)((j & 0xFF00) >> 8) 217 | }); 218 | if (i > 0xFF) 219 | { 220 | j += 1; 221 | byteCode.Add(new byte[] { 222 | 0x0A, 223 | (byte)((i & 0xFF00) >> 8), 224 | (byte)(j & 0x00FF), 225 | (byte)((j & 0xFF00) >> 8) 226 | }); 227 | } 228 | 229 | return Result.OK; 230 | }); 231 | 232 | funcList.Add("wre", (dst, src, ext) => 233 | { 234 | if (src == null) return Result.ERR; 235 | if (dst == null) return Result.ERR; 236 | if (dst.type != RegType.INT) return Result.ERR; 237 | if (src.type != RegType.INT) return Result.ERR; 238 | 239 | ushort i = (ushort)(((int)src.data) & 0xFFFF); 240 | ushort j = (ushort)(((int)dst.data) & 0xFFFF); 241 | byteCode.Add(new byte[] { 242 | 0x0B, 243 | (byte)(i & 0x00FF), 244 | (byte)(j & 0x00FF), 245 | (byte)((j & 0xFF00) >> 8) 246 | }); 247 | if (i > 0xFF) 248 | { 249 | j += 1; 250 | byteCode.Add(new byte[] { 251 | 0x0B, 252 | (byte)((i & 0xFF00) >> 8), 253 | (byte)(j & 0x00FF), 254 | (byte)((j & 0xFF00) >> 8) 255 | }); 256 | } 257 | 258 | return Result.OK; 259 | }); 260 | 261 | funcList.Add("sleep", (dst, src, ext) => 262 | { 263 | if (src != null) return Result.ERR; 264 | if (dst == null) return Result.ERR; 265 | if (dst.type != RegType.INT) return Result.ERR; 266 | 267 | ushort i = (ushort)(((int)dst.data) & 0xFFFF); 268 | byteCode.Add(new byte[] { 269 | 0x0C, 270 | 0x00, 271 | (byte)(i & 0x00FF), 272 | (byte)((i & 0xFF00) >> 8) 273 | }); 274 | 275 | return Result.OK; 276 | }); 277 | 278 | funcList.Add("led", (dst, src, ext) => 279 | { 280 | if (src == null) return Result.ERR; 281 | if (dst == null) return Result.ERR; 282 | if (dst.type != RegType.INT) return Result.ERR; 283 | if (src.type != RegType.INT) return Result.ERR; 284 | 285 | byte i = (byte)(((int)dst.data) & 0xFF); 286 | int j = ((int)src.data) & 0xFFFFFF; 287 | 288 | byte r = (byte)((j & 0xFF0000) >> 16); 289 | byte g = (byte)((j & 0x00FF00) >> 8); 290 | byte b = (byte)((j & 0x0000FF) >> 0); 291 | 292 | byte e = (byte)((r & 0x07) << 5 | (g & 0x03) << 3 | (b & 0x07)); 293 | ushort c = (ushort)((r & 0xF8) << 8 | (g & 0xFC) << 3 | (b & 0xF8) >> 3); 294 | 295 | byteCode.Add(new byte[] { 296 | 0x0D, 297 | 0x00, 298 | i, 299 | e, 300 | 0x00, 301 | (byte)(c & 0x00FF), 302 | (byte)((c & 0xFF00) >> 8), 303 | 0x00 304 | }); 305 | 306 | return Result.OK; 307 | }); 308 | 309 | funcList.Add("time", (dst, src, ext) => 310 | { 311 | if (src != null) return Result.ERR; 312 | if (dst == null) return Result.ERR; 313 | if (dst.type != RegType.INT) return Result.ERR; 314 | 315 | ushort i = (ushort)(((int)dst.data) & 0xFFFF); 316 | byteCode.Add(new byte[] { 317 | 0x0E, 318 | 0x00, 319 | (byte)(i & 0x00FF), 320 | (byte)((i & 0xFF00) >> 8) 321 | }); 322 | 323 | return Result.OK; 324 | }); 325 | 326 | funcList.Add("fade", (dst, src, ext) => 327 | { 328 | if (src == null) return Result.ERR; 329 | if (dst == null) return Result.ERR; 330 | if (dst.type != RegType.INT) return Result.ERR; 331 | if (src.type != RegType.INT) return Result.ERR; 332 | 333 | byte i = (byte)(((int)dst.data) & 0xFF); 334 | int j = ((int)src.data) & 0xFFFFFF; 335 | 336 | byte r = (byte)((j & 0xFF0000) >> 16); 337 | byte g = (byte)((j & 0x00FF00) >> 8); 338 | byte b = (byte)((j & 0x0000FF) >> 0); 339 | 340 | byte e = (byte)((r & 0x07) << 5 | (g & 0x03) << 3 | (b & 0x07)); 341 | ushort c = (ushort)((r & 0xF8) << 8 | (g & 0xFC) << 3 | (b & 0xF8) >> 3); 342 | 343 | byteCode.Add(new byte[] { 344 | 0x0F, 345 | 0x00, 346 | i, 347 | e, 348 | 0x00, 349 | (byte)(c & 0x00FF), 350 | (byte)((c & 0xFF00) >> 8), 351 | 0x00 352 | }); 353 | 354 | return Result.OK; 355 | }); 356 | 357 | funcList.Add("trig", (dst, src, ext) => 358 | { 359 | if (src == null) return Result.ERR; 360 | if (dst == null) return Result.ERR; 361 | if (dst.type != RegType.INT) return Result.ERR; 362 | if (src.type != RegType.INT) return Result.ERR; 363 | 364 | byte i = (byte)(((int)dst.data) & 0xFF); 365 | byte j = (byte)(((int)src.data) & 0xFF); 366 | byteCode.Add(new byte[] { 367 | 0x10, 368 | i, 369 | j, 370 | 0x00 371 | }); 372 | 373 | return Result.OK; 374 | }); 375 | 376 | funcList.Add("rgb", (dst, src, ext) => 377 | { 378 | if (src == null) return Result.ERR; 379 | if (dst == null) return Result.ERR; 380 | if (dst.type != RegType.INT) return Result.ERR; 381 | if (src.type != RegType.INT) return Result.ERR; 382 | 383 | byte i = (byte)(((int)dst.data) & 0xFF); 384 | byte j = (byte)(((int)src.data) & 0xFF); 385 | byteCode.Add(new byte[] { 386 | 0x11, 387 | i, 388 | j, 389 | 0x00 390 | }); 391 | 392 | return Result.OK; 393 | }); 394 | 395 | funcList.Add("sysrst", (dst, src, ext) => 396 | { 397 | if (src == null) return Result.ERR; 398 | if (dst == null) return Result.ERR; 399 | if (dst.type != RegType.INT) return Result.ERR; 400 | if (src.type != RegType.INT) return Result.ERR; 401 | 402 | byte i = (byte)(((int)dst.data) & 0xFF); 403 | ushort j = (ushort)(((int)src.data) & 0xFFFF); 404 | byteCode.Add(new byte[] { 405 | 0x12, 406 | i, 407 | (byte)(j & 0x00FF), 408 | (byte)((j & 0xFF00) >> 8) 409 | }); 410 | 411 | return Result.OK; 412 | }); 413 | 414 | funcList.Add("reload", (dst, src, ext) => 415 | { 416 | if (src == null) return Result.ERR; 417 | if (dst == null) return Result.ERR; 418 | if (dst.type != RegType.INT) return Result.ERR; 419 | if (src.type != RegType.INT) return Result.ERR; 420 | 421 | byte i = (byte)(((int)dst.data) & 0xFF); 422 | ushort j = (ushort)(((int)src.data) & 0xFFFF); 423 | byteCode.Add(new byte[] { 424 | 0x13, 425 | i, 426 | (byte)(j & 0x00FF), 427 | (byte)((j & 0xFF00) >> 8) 428 | }); 429 | 430 | return Result.OK; 431 | }); 432 | 433 | funcList.Add("iap", (dst, src, ext) => 434 | { 435 | if (src == null) return Result.ERR; 436 | if (dst == null) return Result.ERR; 437 | if (dst.type != RegType.INT) return Result.ERR; 438 | if (src.type != RegType.INT) return Result.ERR; 439 | 440 | byte i = (byte)(((int)dst.data) & 0xFF); 441 | ushort j = (ushort)(((int)src.data) & 0xFFFF); 442 | byteCode.Add(new byte[] { 443 | 0x14, 444 | i, 445 | (byte)(j & 0x00FF), 446 | (byte)((j & 0xFF00) >> 8) 447 | }); 448 | 449 | return Result.OK; 450 | }); 451 | } 452 | 453 | protected override void LoadParamList() 454 | { 455 | 456 | } 457 | } 458 | 459 | Hid hid; 460 | IntPtr ptr; 461 | 462 | const int BUF_SIZE = 32; 463 | 464 | public MainForm() 465 | { 466 | InitializeComponent(); 467 | devList.SelectedIndex = 0; 468 | 469 | hid = new Hid(); 470 | hid.DataReceived += Hid_DataReceived; 471 | hid.DeviceRemoved += Hid_DeviceRemoved; 472 | 473 | ptr = new IntPtr(-1); 474 | 475 | Util.Output = (obj) => outputBox.Text += obj.ToString(); 476 | } 477 | 478 | private void btnRun_Click(object sender, EventArgs e) 479 | { 480 | outputBox.Clear(); 481 | SimCore core = SimCore.GetSimCore(codeBox.Text); 482 | var result = core.Run(); 483 | if (result != null) 484 | { 485 | byte[][] bytes = core.GetBytes(); 486 | outputBox.Text += "Code: "; 487 | for (int i = 0; i < bytes.Length; i++) 488 | for (int j = 0; j < bytes[i].Length; j++) 489 | outputBox.Text += (bytes[i][j].ToString("x2") + " "); 490 | outputBox.Text += "\n"; 491 | 492 | if ((int)ptr != -1) 493 | { 494 | outputBox.Text += "Sending ...\n"; 495 | 496 | new Thread(new ThreadStart(() => 497 | { 498 | Report report; int index = 0; 499 | List buf = new List(); 500 | while (index < bytes.Length) 501 | { 502 | if (buf.Count + bytes[index].Length < BUF_SIZE) 503 | { 504 | buf.AddRange(bytes[index]); 505 | index += 1; 506 | if (index >= bytes.Length) 507 | { 508 | report = new Report(0x55, buf.ToArray()); 509 | hid.Write(report); 510 | buf.Clear(); 511 | break; 512 | } 513 | } 514 | else 515 | { 516 | report = new Report(0x55, buf.ToArray()); 517 | hid.Write(report); 518 | Thread.Sleep(500); 519 | buf.Clear(); 520 | } 521 | } 522 | })).Start(); 523 | } 524 | } 525 | } 526 | 527 | private void btnConnect_Click(object sender, EventArgs e) 528 | { 529 | if (btnConnect.Text == "Connect") 530 | { 531 | ushort vid = 0x8088; byte mid = 0x02; 532 | ushort pid = (ushort)(devList.SelectedIndex + 1); 533 | if (devList.SelectedItem.Equals("SimPad Boot")) 534 | pid = 0x00FF; 535 | ptr = hid.OpenDevice(vid, pid, mid); 536 | if ((int)ptr != -1) 537 | { 538 | outputBox.Clear(); 539 | outputBox.Text += ("Connected to: " + devList.SelectedItem + "\n"); 540 | devList.Enabled = false; 541 | btnConnect.Text = "Close"; 542 | } 543 | } 544 | else 545 | { 546 | if ((int)ptr != -1) 547 | hid.CloseDevice(ptr); 548 | ptr = new IntPtr(-1); 549 | devList.Enabled = true; 550 | btnConnect.Text = "Connect"; 551 | } 552 | } 553 | 554 | private void Hid_DeviceRemoved(object sender, EventArgs e) 555 | { 556 | Invoke(new ThreadStart(() => { 557 | ptr = new IntPtr(-1); 558 | devList.Enabled = true; 559 | btnConnect.Text = "Connect"; 560 | })); 561 | } 562 | 563 | private void Hid_DataReceived(object sender, Report e) 564 | { 565 | byte[] bytes = e.reportBuff; 566 | Invoke(new ThreadStart(() => { 567 | outputBox.Text += "Data: "; 568 | for (int i = 0; i < bytes.Length; i++) 569 | outputBox.Text += (bytes[i].ToString("x2") + " "); 570 | outputBox.Text += "\n"; 571 | })); 572 | } 573 | 574 | private void statusLabel_Click(object sender, EventArgs e) 575 | { 576 | new HelpForm().Show(); 577 | } 578 | } 579 | } 580 | -------------------------------------------------------------------------------- /SimHost/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 125 | 126 | AAABAAEAAAAAAAEAIABlQAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAIAAAACAAgGAAAA9HjU+gAAIABJ 127 | REFUeJzt3Xt0Hvd95/fPPBfcCYD3i0QRpCVZlOWYHHid7CZZgW7S4/Q0Np3NJk3TRGSyTU/bbUzmj7rb 128 | NqW0TbZb5ySkkuyes9ttSLe5Haeu6E1zmjTJEo4dx16HI9qxLFmKLMgXWSJFEiQBPHhuM/1j5gEegLjM 129 | g2cuz8zv/ToHRyL4YOYHgnx+n/ldvj/L8zwBAACzFNJuAAAASB4BAAAAAxEAAAAwEAEAAAADEQAAADAQ 130 | AQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAAD 131 | EQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAw 132 | EAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAA 133 | AxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAA 134 | MBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAA 135 | AAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAA 136 | ADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEA 137 | AAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEA 138 | AAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADBQKe0GROmD/+8n025C 139 | Jx4IPh4Pfv0uSbvWeW1D0uclNYNff1HSdyTdirOBLQuNhh4eG9c7Rse10GjEdp/BUknfnLurF2/f1HCp 140 | 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 392 | QAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAA 393 | DEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAA 394 | wEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAA 395 | AAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAA 396 | AMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQA 397 | AAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQA 398 | AADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAE 399 | AAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxEAAAAwEAEAAAADEQAAADAQAQAAAAMRAAAAMBABAAAAAxE 400 | AAAAwEAEAAAADEQAAADAQAQAAELqN5MAAAAUSURBVAAMRAAAAMBABAAAAAz0/wORnNkMQtfneQAAAABJ 401 | RU5ErkJggg== 402 | 403 | 404 | -------------------------------------------------------------------------------- /SimHost/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace SimHost 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// 应用程序的主入口点。 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new MainForm()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SimHost/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("SimHost")] 9 | [assembly: AssemblyDescription("SimPad Host Software")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("NSDN")] 12 | [assembly: AssemblyProduct("SimHost")] 13 | [assembly: AssemblyCopyright("Copyright © NSDN 2014 - 2021")] 14 | [assembly: AssemblyTrademark("SimHost")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("06a2c4a0-5683-47ce-bd2a-74cec0add906")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SimHost/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SimHost.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SimHost.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SimHost/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /SimHost/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SimHost.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SimHost/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SimHost/SimHost.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {06A2C4A0-5683-47CE-BD2A-74CEC0ADD906} 8 | WinExe 9 | SimHost 10 | SimHost 11 | v4.7.2 12 | 512 13 | true 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | SimHost.Program 39 | 40 | 41 | icon.ico 42 | 43 | 44 | 45 | packages\dotNSASM.0.6.1\lib\netstandard2.0\dotNSASM.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Form 59 | 60 | 61 | HelpForm.cs 62 | 63 | 64 | 65 | Form 66 | 67 | 68 | MainForm.cs 69 | 70 | 71 | 72 | 73 | HelpForm.cs 74 | 75 | 76 | MainForm.cs 77 | 78 | 79 | ResXFileCodeGenerator 80 | Resources.Designer.cs 81 | Designer 82 | 83 | 84 | True 85 | Resources.resx 86 | True 87 | 88 | 89 | 90 | 91 | SettingsSingleFileGenerator 92 | Settings.Designer.cs 93 | 94 | 95 | True 96 | Settings.settings 97 | True 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /SimHost/SimHost.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30626.31 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimHost", "SimHost.csproj", "{06A2C4A0-5683-47CE-BD2A-74CEC0ADD906}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {06A2C4A0-5683-47CE-BD2A-74CEC0ADD906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {06A2C4A0-5683-47CE-BD2A-74CEC0ADD906}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {06A2C4A0-5683-47CE-BD2A-74CEC0ADD906}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {06A2C4A0-5683-47CE-BD2A-74CEC0ADD906}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {07085C30-99F8-4B21-8917-D9B8AB1DDCD4} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /SimHost/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SimHost/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/SimHost/icon.ico -------------------------------------------------------------------------------- /SimHost/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/SimHost/icon.png -------------------------------------------------------------------------------- /SimHost/icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimDevices-Project/SimPad_firmware_8051/524aa5287cd9bd15701d19a999a1eae1b1881525/SimHost/icon.psd -------------------------------------------------------------------------------- /SimHost/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------