diff --git a/BootLoader&Firmware/source code/include/README b/BootLoader&Firmware/source code/include/README new file mode 100644 index 0000000..45496b1 --- /dev/null +++ b/BootLoader&Firmware/source code/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/BootLoader&Firmware/source code/lib/README b/BootLoader&Firmware/source code/lib/README new file mode 100644 index 0000000..8c9c29c --- /dev/null +++ b/BootLoader&Firmware/source code/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/BootLoader&Firmware/source code/platformio.ini b/BootLoader&Firmware/source code/platformio.ini new file mode 100644 index 0000000..8d52170 --- /dev/null +++ b/BootLoader&Firmware/source code/platformio.ini @@ -0,0 +1,18 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:sparkfun_samd21_dev_usb] +platform = atmelsam +board = sparkfun_samd21_dev_usb +framework = arduino +lib_deps = + nicohood/HID-Project@^2.8.2 + fastled/FastLED@^3.4.0 + cmaglie/FlashStorage@^1.0.0 diff --git a/BootLoader&Firmware/source code/src/Air.h b/BootLoader&Firmware/source code/src/Air.h new file mode 100644 index 0000000..3834c1c --- /dev/null +++ b/BootLoader&Firmware/source code/src/Air.h @@ -0,0 +1,177 @@ +////基础定义//// +#include "HID-Project.h" +#include "FastLED.h" +#include +#define Serial SerialUSB + +////Air定义//// +int calibrationCounter; +bool calibrated; +uint16_t thresholds[6]; +uint16_t maxReadings[6]; + +#define AIR_LED_DELAY 96//轮询延迟 +#define AIR_INPUT_SENSITIVITY 0.3//红外敏感度 +#define CALIBRATION_SAMPLES 256//校准采样数 +#define SKIP_SAMPLES 256//校准跳过采样数 + +int ir_input_pins[6] = {3,4,5,2,6,11};//定义轮询发射红外针脚 +int ir_sensor_pins[6] = {A0,A1,A2,A3,A4,A5};//定义轮询接收红外针脚 +////按键定义//// +KeyboardKeycode AirKeys[6] = {KEY_SLASH, KEY_PERIOD, KEY_QUOTE, KEY_SEMICOLON, KEY_RIGHT_BRACE, KEY_LEFT_BRACE}; +uint8_t AirState[6]; +////灯光定义//// +#define air_right_pin 8 //R灯引脚 +#define air_right_num 6 //R灯数量 +CRGB AIR_RIGHT[air_right_num]; + +#define air_left_pin 10 //L灯引脚 +#define air_left_num 6 //L灯数量 +CRGB AIR_LEFT[air_left_num]; + + +uint8_t colorIndex; + +void CloudboardAirLED(){//键盘Air灯效1 + colorIndex++; + fill_palette(AIR_LEFT, 6 , colorIndex, 5, CloudColors_p, 100, LINEARBLEND); + fill_palette(AIR_RIGHT, 6 , colorIndex, 5, CloudColors_p, 100, LINEARBLEND); + for (uint8_t i = 0; i < 6; i++) { + if (AirState[i]) { + AIR_RIGHT[i] = CRGB::White; + AIR_LEFT[i] = CRGB::White; + } + FastLED[1].show(AIR_RIGHT,6, 150); + FastLED[2].show(AIR_LEFT,6, 150); + } +} + +//////////Air////////// +void AirSetup() { + calibrated = false; + for (int i = 0; i < 6; i++) { + maxReadings[i] = 0; + } + for (int i = 0; i < 6; i++) { + pinMode(ir_sensor_pins[i], INPUT_PULLUP); + pinMode(ir_input_pins[i], OUTPUT); + AirState[i] = 0; + } +} + +void turnOffLight() {//关闭发射函数 + for(int i = 0;i < 6;i++){ + digitalWrite(ir_input_pins[i], LOW); + } +} + +void changeLight(int light) {//红外发射轮询 + switch (light) { + case 0: + digitalWrite(ir_input_pins[light], HIGH);//#1 + break; + case 1: + digitalWrite(ir_input_pins[light], HIGH);//#2 + break; + case 2: + digitalWrite(ir_input_pins[light], HIGH);//#3 + break; + case 3: + digitalWrite(ir_input_pins[light], HIGH);//#4 + break; + case 4: + digitalWrite(ir_input_pins[light], HIGH);//#5 + break; + case 5: + digitalWrite(ir_input_pins[light], HIGH);//#6 + break; + default: + turnOffLight(); + break; + } +} + +uint16_t getValue(int sensor) {//获取开灯数值函数 + changeLight(sensor);// 开灯 + delayMicroseconds(AIR_LED_DELAY/2);// 加上延迟保证完全开启 + return analogRead(ir_sensor_pins[sensor]);//读数值 +} + +bool getSensorState(int sensor) {//返回Air状态 + turnOffLight();//关灯 + delayMicroseconds(AIR_LED_DELAY/2);//加上延迟保证完全关闭 + int enviroment = analogRead(ir_sensor_pins[sensor]);//读取环境数值 + int value = getValue(sensor);//读取开灯数值 + + //调试AIR用输出 + // Serial.print(sensor); + // Serial.print("\t"); + // Serial.print(value); + // Serial.print("\t"); + // Serial.print(enviroment); + // Serial.print("\t"); + // Serial.print(value - enviroment); + // Serial.print("\t"); + // Serial.print(value - enviroment + 200); + // Serial.print("\t"); + // Serial.print(maxReadings[sensor]); + // Serial.print("\t"); + // Serial.print(thresholds[sensor]); + // Serial.println(); + + //把读数减去环境数值和校准数值比较后返回布尔值,+200为防止负数的比较 + return (value - enviroment + 200) < (thresholds[sensor] + 200); + +} + +void AirCalibrate() {//校准接收端 + // 跳过开头采样 + for (int i = 0; i < SKIP_SAMPLES; i++) { + for (int sensor = 0; sensor < 6; sensor++) { + getValue(sensor); + turnOffLight(); + } + } + //开始校准 + for (int i = 0; i < CALIBRATION_SAMPLES; i++) { + for (int sensor = 0; sensor < 6; sensor++) { + turnOffLight();//关灯 + delayMicroseconds(AIR_LED_DELAY/2);//加上延迟保证完全关闭 + int enviroment = analogRead(ir_sensor_pins[sensor]);//读取环境数值 + int value = getValue(sensor) - enviroment;//读取开灯数值 + if (value > maxReadings[sensor])//记录最高读数 + maxReadings[sensor] = value; + } + Serial.println(); + } + for (int i = 0; i < 6; i++) {//通过敏感度生成阈值 + thresholds[i] = (AIR_INPUT_SENSITIVITY * maxReadings[i]); + } + calibrated = true;//完成校准 +} + +void AirCheck(){ + if (calibrated){ + for (int i = 0; i < 6; i++){ + if (getSensorState(i)){ + NKROKeyboard.press(AirKeys[i]); + AirState[i] = 1; + } else if (!getSensorState(i)){ + NKROKeyboard.release(AirKeys[i]); + AirState[i] = 0; + } + } + } +} + +void NoAirCheck(){ + if (calibrated){ + for (int i = 0; i < 6; i++){ + if (getSensorState(i)){ + AirState[i] = 1; + } else if (!getSensorState(i)){ + AirState[i] = 0; + } + } + } +} diff --git a/BootLoader&Firmware/source code/src/Touch.h b/BootLoader&Firmware/source code/src/Touch.h new file mode 100644 index 0000000..f6eeb23 --- /dev/null +++ b/BootLoader&Firmware/source code/src/Touch.h @@ -0,0 +1,117 @@ +////基础定义//// +#include "mpr121-helper.h" +#include "mpr121-config.h" +#include "serial.h" +#include "HID-Project.h" +#include "FastLED.h" +#define Serial SerialUSB +////MPR定义//// +#define CA_ADDR 0x5A//mpr121A +#define CB_ADDR 0x5B//mpr121B +#define CC_ADDR 0x5C//mpr121C + +uint16_t LastA = -1, CurrA, LastB = -1, CurrB, LastC = -1, CurrC; //存储触摸的状态 +static MPR121 capA, capB, capC; //mpr121定义 + +////串口定义//// +#define CLAMP(val, lo, hi) (val < lo ? lo : (val > hi ? hi : val)) +uint8_t checkrelease[32]; +static bool auto_scan = false;//串口用标记 +////按键定义//// +KeyboardKeycode KeyCode[32] = {//键值列表 + KEY_I, KEY_COMMA, KEY_8, KEY_K, KEY_U, KEY_M, KEY_7, KEY_J, KEY_Y, KEY_N, + KEY_6, KEY_H, KEY_T, KEY_B, KEY_5, KEY_G, KEY_R, KEY_V, KEY_4, KEY_F, KEY_E, KEY_C, + KEY_3, KEY_D, KEY_W, KEY_X, KEY_2, KEY_S, KEY_Q, KEY_Z, KEY_1, KEY_A, + }; +////灯光定义//// +uint16_t LED_BRI = 255; //灯亮度 +#define LED_PIN 7 //灯针脚 +#define LED_NUM 31 //灯数量 +CRGB leds[LED_NUM]; + +uint32_t MiddleLED=CRGB::Black; //中缝灯色 +uint32_t GroundLED=CRGB::Aqua; //触摸区常态灯色 +uint32_t PressLED=CRGB::Red; //触摸时灯色 + +////函数指针//// +void (*AirSensor)(); +void (*AirLED)(); +void (*TouchCheck)(); +void (*TouchLEDCheck)(); + + +void TouchSetup() {//触摸初始化 + capA.begin(CA_ADDR); + capA.init(); + capA.run(); + + capB.begin(CB_ADDR); + capB.init(); + capB.run(); + + capC.begin(CC_ADDR); + capC.init(); + capC.run(); + + Wire.setClock(800000);//I2C波特率 +} + +//直连触摸函数部分// +int CalCheck(int bl, int fd) {//触摸数值计算 + int cal = bl - fd; + return cal > 4 ? 5 * cal : (cal > 0 ? cal : 0) ; +} + +//键盘触摸函数部分// +uint8_t ledindex = 0; +uint8_t TouchState[32]; +uint8_t val = 30; +void K32Check() { + int16_t bl, fl, cal, calpress[32]; + for (uint8_t i = 0; i < 12; i++) {//计算数值 + if (i < 10) { + bl = capA.baselineData(i); + fl = capA.filteredData(i); + cal = CalCheck(bl, fl); + calpress[i] = CLAMP(cal, 0, 255); + } + bl = capB.baselineData(i); + fl = capB.filteredData(i); + cal = CalCheck(bl, fl); + calpress[i + 10] = CLAMP(cal, 0, 255); + if (i < 10) { + bl = capC.baselineData(i); + fl = capC.filteredData(i); + cal = CalCheck(bl, fl); + calpress[i + 10 + 12] = CLAMP(cal, 0, 255); + } + } + for (uint8_t i = 0; i < 32; i++) { + uint8_t calkeypress = calpress[i]; + Serial.println(calpress[i]); + if (ledindex <= 15) {//初始化完成后的灯 + leds[31 - i * 2] = MiddleLED; + leds[30 - i * 2] = GroundLED; + FastLED[0].showLeds(255); + ledindex++; + } + if (calkeypress >= val) {//Check + checkrelease[i] = SLIDER_CMD_AUTO_SCAN; + NKROKeyboard.press(KeyCode[i]); + i%2==0?leds[i] = PressLED:leds[i-1] = PressLED; + } + else { + if (checkrelease[i]) { + checkrelease[i] = 0; + NKROKeyboard.release(KeyCode[i]); + i%2==0?leds[i] = GroundLED:leds[i-1] = GroundLED; + } + continue; + } + } + leds[7] = PressLED; + leds[15] = PressLED; + leds[23] = PressLED; + FastLED[0].showLeds(255); +} + diff --git a/BootLoader&Firmware/source code/src/main.cpp b/BootLoader&Firmware/source code/src/main.cpp new file mode 100644 index 0000000..2dc945d --- /dev/null +++ b/BootLoader&Firmware/source code/src/main.cpp @@ -0,0 +1,134 @@ +#include "Touch.h" +#include "Air.h" +#define Serial SerialUSB + +////核心函数//// +static void slider_set_led() {//串口读取led数据 + if (slider_tx_pending) { + return; + } + for (int i = 0; i < 31; i++) {//BRG + uint8_t t1 = i; + uint8_t t2 = i * 3; + leds[t1].r = slider_req.leds[t2 + 1]; + leds[t1].g = slider_req.leds[t2 + 2]; + leds[t1].b = slider_req.leds[t2 + 0]; + } + FastLED[0].show(leds, LED_NUM, LED_BRI); + slider_req.cmd = 0; +} + + +static void slider_scan() {//直连触摸扫描 + if (!auto_scan || slider_tx_pending) {//分支选择,非直连状态 + TouchCheck();//各状态的触摸板检测 + NoAirCheck();//无HID输入的Air + AirLED(); + return; + }//分支选择,直连状态 + slider_resp.syn = 0xff; + slider_resp.cmd = SLIDER_CMD_AUTO_SCAN; + slider_resp.size = sizeof(slider_resp.pressure); + int16_t bv, fd, clp; + for (int i = 0; i < 12; i++) {//直连触摸数值计算 + if (i < 10) { + bv = capA.baselineData(i); + fd = capA.filteredData(i); + clp = CalCheck(bv, fd); + slider_resp.pressure[i] = CLAMP(clp, 0, 255); + } + bv = capB.baselineData(i); + fd = capB.filteredData(i); + clp = CalCheck(bv, fd); + slider_resp.pressure[i + 10] = CLAMP(clp, 0, 255); + if (i < 10) { + bv = capC.baselineData(i); + fd = capC.filteredData(i); + clp = CalCheck(bv, fd); + slider_resp.pressure[i + 10 + 12] = CLAMP(clp, 0, 255); + } + } + AirCheck();//有HID输入的Air + AirLED(); + } + +static void slider_scan_start() {//启动slider + auto_scan = true; + slider_scan(); +} +static void slider_scan_stop() {//停止slider + auto_scan = false; + slider_resp.syn = 0xff; + slider_resp.cmd = SLIDER_CMD_AUTO_SCAN_STOP; + slider_resp.size = 0; + slider_req.cmd = 0; +} +static void slider_reset() {//重置slider,重新初始化触摸 + capA.init(); + capA.run(); + capB.init(); + capB.run(); + capC.init(); + capC.run(); + slider_resp.syn = 0xff; + slider_resp.cmd = SLIDER_CMD_RESET; + slider_resp.size = 0; + slider_req.cmd = 0; +} +static void slider_get_board_info() {//返回版本信息,勿修改 + slider_resp.syn = 0xff; + slider_resp.cmd = SLIDER_CMD_GET_BOARD_INFO; + slider_resp.size = sizeof(slider_resp.version); + strcpy(slider_resp.version, "15330 \xA0""06712\xFF""\x90"); + slider_req.cmd = 0; +} + +void SerialCheck() {//串口模式的loop函数 + switch (sliderserial_readreq()) { + case SLIDER_CMD_SET_LED: + slider_set_led(); + break; + case SLIDER_CMD_AUTO_SCAN_START: + slider_scan_start(); + break; + case SLIDER_CMD_AUTO_SCAN_STOP: + slider_scan_stop(); + break; + case SLIDER_CMD_RESET: + slider_reset(); + break; + case SLIDER_CMD_GET_BOARD_INFO: + slider_get_board_info(); + break; + default: + slider_scan(); + } + sliderserial_writeresp(); +} + +void LEDset() {//灯光初始化 + FastLED.addLeds(leds, LED_NUM); + FastLED.addLeds(AIR_RIGHT, air_right_num); + FastLED.addLeds(AIR_LEFT, air_left_num); +} + + + +////主进程函数//// +void setup() { + //串口启动// + SerialUSB.begin(115200); + SerialUSB.setTimeout(0); + + LEDset();//灯带添加 + TouchSetup();//触摸启动 + AirSetup();//Air启动 + AirLED = CloudboardAirLED; + TouchCheck = K32Check; + AirCalibrate();//Air校准 + +} + +void loop() { + SerialCheck();//主循环 +} diff --git a/BootLoader&Firmware/source code/src/mpr121-config.h b/BootLoader&Firmware/source code/src/mpr121-config.h new file mode 100644 index 0000000..9890691 --- /dev/null +++ b/BootLoader&Firmware/source code/src/mpr121-config.h @@ -0,0 +1,58 @@ +#ifndef _MPR121_CONFIG_H +#define _MPR121_CONFIG_H + +#include "mpr121-helper.h" + +// Thresholds +#define MPR121CONF_TTH 6///< 触发阈值 +#define MPR121CONF_RTH 3///< 释放阈值 +// De-bounce +#define MPR121CONF_DR 3 ///< 松开样本采集数 +#define MPR121CONF_DT 2 ///< 按下样本采集数 +// AFE Configurations +#define MPR121CONF_FFI MPR121_FFI_6 ///< 一层过滤采样数 +#define MPR121CONF_CDC 16 ///< 充放电电流 +#define MPR121CONF_CDT MPR121_CDT_500NS ///< 充放电时间 +#define MPR121CONF_SFI MPR121_SFI_4 ///< 二层过滤 +#define MPR121CONF_ESI MPR121_ESI_1MS ///< 二层过滤采样间隔时间 +// ECR Configurations +#define MPR121CONF_CL MPR121_CL_INIT1 ///< 启用基线动态校准 +#define MPR121CONF_ELEPROX MPR121_ELEPROX_0 ///< 接近检测电极,禁用 +#define MPR121CONF_ELE 12 ///< touch detection electrodes +// 基线动态校准 +#define MPR121CONF_MHDR 1 ///< 上升最大变化值 +#define MPR121CONF_NHDR 8 ///< 上升幅度 +#define MPR121CONF_NCLR 1 ///< 上升修正样本个数 +#define MPR121CONF_FDLR 0 ///< 修正前等待样本个数 +#define MPR121CONF_MHDF 1 ///< 下降最大变化值 +#define MPR121CONF_NHDF 1 ///< 下降幅度 +#define MPR121CONF_NCLF 16 ///< 下降修正样本个数 +#define MPR121CONF_FDLF 2 ///< 修正前等待样本个数 +#define MPR121CONF_NHDT 0 ///< Touched Noise Half Delta +#define MPR121CONF_NCLT 0 ///< Touched Noise Count Limit +#define MPR121CONF_FDLT 0 ///< Touched Filter Delay Count Limit +// 自动初始化 +// #define MPR121CONF_USL 200 ///< 上限,MPR121_UPLIMIT,((Vdd - 0.7)/Vdd) * 256,200 +// #define MPR121CONF_LSL 130 ///< 下限,MPR121_LOWLIMIT,UPLIMIT * 0.65,130 +// #define MPR121CONF_TL 180 ///< 目标,MPR121_TARGETLIMIT,UPLIMIT * 0.9,180 + +#define MPR121CONF_USL 156 ///< 上限,MPR121_UPLIMIT,((Vdd - 0.7)/Vdd) * 256 +#define MPR121CONF_LSL 101 ///< 下限,MPR121_LOWLIMIT,UPLIMIT * 0.65 +#define MPR121CONF_TL 140 ///< 目标,MPR121_TARGETLIMIT,UPLIMIT * 0.9 + +// #define MPR121CONF_USL 166 ///< 上限,MPR121_UPLIMIT,((Vdd - 0.7)/Vdd) * 256,200 +// #define MPR121CONF_LSL 108 ///< 下限,MPR121_LOWLIMIT,UPLIMIT * 0.65,130 +// #define MPR121CONF_TL 149 ///< 目标,MPR121_TARGETLIMIT,UPLIMIT * 0.9,180 + +#define MPR121CONF_AFES MPR121CONF_FFI ///< 必须设置为FFI +#define MPR121CONF_RETRY MPR121_RETRY_0 ///< 重试次数 +#define MPR121CONF_BVA MPR121CONF_CL ///< 必须设置为CL +#define MPR121CONF_ARE 1 ///< 开启自动重配置 +#define MPR121CONF_ACE 1 ///< 开启自动配置 +#define MPR121CONF_SCTS 1 ///< 跳过充电时间 +//中断用,全部关闭 +#define MPR121CONF_ACFIE 0 ///< Auto-configuration fail interrupt enable +#define MPR121CONF_ARFIE 0 ///< Auto-reconfiguration fail interrupt enable +#define MPR121CONF_OORIE 0 ///< Out-of-range interrupt enable + +#endif diff --git a/BootLoader&Firmware/source code/src/mpr121-helper.cpp b/BootLoader&Firmware/source code/src/mpr121-helper.cpp new file mode 100644 index 0000000..60533d4 --- /dev/null +++ b/BootLoader&Firmware/source code/src/mpr121-helper.cpp @@ -0,0 +1,134 @@ +/* + Support class for MPR121, giving full control over the device efficiently. + + Modifications licensed under University of Illinois/NCSA Open Source License + + Copyright (c) 2020 Fang Lu + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal with the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the documentation + and/or other materials provided with the distribution. + - Neither the names of Fang Lu, nor the names of its contributors may be + used to endorse or promote products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + WITH THE SOFTWARE. + + Original license text from Adafruit + + @file Adafruit_MPR121.cpp + + This is a library for the MPR121 12-Channel Capacitive Sensor + + Designed specifically to work with the MPR121 board. + + Pick one up today in the adafruit shop! + ------> https://www.adafruit.com/product/1982 + + These sensors use I2C to communicate, 2+ pins are required to interface + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Limor Fried/Ladyada (Adafruit Industries). + + BSD license, all text above must be included in any redistribution +*/ + +#include "mpr121-helper.h" +#include "mpr121-config.h" + + + +void MPR121::begin(uint8_t addr, TwoWire *wire) { + _i2caddr = addr; + _wire = wire; + _wire->begin(); +} + +void MPR121::init() { + // 软件重置 + reset(); + delay(1); + stop(); + + writeRegisterRaw(MPR121_MHDR, MPR121CONF_MHDR, false); + writeRegisterRaw(MPR121_NHDR, MPR121CONF_NHDR, false); + writeRegisterRaw(MPR121_NCLR, MPR121CONF_NCLR, false); + writeRegisterRaw(MPR121_FDLR, MPR121CONF_FDLR, false); + writeRegisterRaw(MPR121_MHDF, MPR121CONF_MHDF, false); + writeRegisterRaw(MPR121_NHDF, MPR121CONF_NHDF, false); + writeRegisterRaw(MPR121_NCLF, MPR121CONF_NCLF, false); + writeRegisterRaw(MPR121_FDLF, MPR121CONF_FDLF, false); + writeRegisterRaw(MPR121_NHDT, MPR121CONF_NHDT, false); + writeRegisterRaw(MPR121_NCLT, MPR121CONF_NCLT, false); + writeRegisterRaw(MPR121_FDLT, MPR121CONF_FDLT, false); + // Skip ELEPROX baseline controls + for (int i = 0; i < 12; i++) {//设置触发阈值和充放电流时间 + writeRegisterRaw(MPR121_TOUCHTH(i), MPR121CONF_TTH, false); + writeRegisterRaw(MPR121_RELEASETH(i), MPR121CONF_RTH, false); + writeRegisterRaw(MPR121_CDC(i), 0, false); + writeRegisterRaw(MPR121_CDT(i), 0, false); + } + writeRegisterRaw(MPR121_DEBOUNCE, (MPR121CONF_DR << 4) | MPR121CONF_DT, false); //设置采样数 + writeRegisterRaw(MPR121_AFE1, (MPR121CONF_FFI << 6) | MPR121CONF_CDC, false); + writeRegisterRaw(MPR121_AFE2, (MPR121CONF_CDT << 5) | (MPR121CONF_SFI << 3) | MPR121CONF_ESI, false); + _ecr = (MPR121CONF_CL << 6) | (MPR121CONF_ELEPROX << 4) | MPR121CONF_ELE; // Write when start + // Skip GPIO configurations + writeRegisterRaw(MPR121_AUTOCONF0, + (MPR121CONF_AFES << 6) | (MPR121CONF_RETRY << 4) | (MPR121CONF_BVA << 2) | (MPR121CONF_ARE << 1) | MPR121CONF_ACE, + false); + writeRegisterRaw(MPR121_AUTOCONF1, + (MPR121CONF_SCTS << 7) | (MPR121CONF_OORIE << 2) | (MPR121CONF_ARFIE << 1) | MPR121CONF_ACFIE, + false); + writeRegisterRaw(MPR121_USL, MPR121CONF_USL, false); + writeRegisterRaw(MPR121_LSL, MPR121CONF_LSL, false); + writeRegisterRaw(MPR121_TL, MPR121CONF_TL, false); + + // Manually call run to start +} + +void MPR121::writeRegister(uint8_t reg, uint8_t value) {//相同 + // MPR121 must be put in Stop Mode to write to most registers + bool stop_required = true; + if (reg == MPR121_ECR || (0x73 <= reg && reg <= 0x7A)) { + stop_required = false; + } + if (stop_required) { + _wire->beginTransmission(_i2caddr); + _wire->write(MPR121_ECR); + _wire->write(0x00); // clear this register to set stop modus + _wire->endTransmission(false); + } + + _wire->beginTransmission(_i2caddr); + _wire->write((uint8_t)reg); + _wire->write((uint8_t)value); + _wire->endTransmission(!stop_required); + + if (stop_required) { + _wire->beginTransmission(_i2caddr); + _wire->write(MPR121_ECR); + _wire->write(_ecr); // restore ECR + _wire->endTransmission(true); + } +} + +//#endif diff --git a/BootLoader&Firmware/source code/src/mpr121-helper.h b/BootLoader&Firmware/source code/src/mpr121-helper.h new file mode 100644 index 0000000..f79c780 --- /dev/null +++ b/BootLoader&Firmware/source code/src/mpr121-helper.h @@ -0,0 +1,227 @@ +/* + Support class for MPR121, giving full control over the device efficiently. + + Modifications licensed under University of Illinois/NCSA Open Source License + + Copyright (c) 2020 Fang Lu + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal with the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the documentation + and/or other materials provided with the distribution. + - Neither the names of Fang Lu, nor the names of its contributors may be + used to endorse or promote products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + WITH THE SOFTWARE. + + Original license text from Adafruit + + @file Adafruit_MPR121.h + + This is a library for the MPR121 12-Channel Capacitive Sensor + + Designed specifically to work with the MPR121 board. + + Pick one up today in the adafruit shop! + ------> https://www.adafruit.com/product/1982 + + These sensors use I2C to communicate, 2+ pins are required to interface + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Limor Fried/Ladyada (Adafruit Industries). + + BSD license, all text above must be included in any redistribution +*/ + +#ifndef _MPR121_HELPER_H +#define _MPR121_HELPER_H + +#include "Arduino.h" +#include + +// Configuration values + +#define MPR121_FFI_6 0 +#define MPR121_FFI_10 1 +#define MPR121_FFI_18 2 +#define MPR121_FFI_34 3 + +#define MPR121_CDT_INHERIT 0 +#define MPR121_CDT_500NS 1 +#define MPR121_CDT_1US 2 +#define MPR121_CDT_2US 3 +#define MPR121_CDT_4US 4 +#define MPR121_CDT_8US 5 +#define MPR121_CDT_16US 6 +#define MPR121_CDT_32US 7 + +#define MPR121_SFI_4 0 +#define MPR121_SFI_6 0 +#define MPR121_SFI_10 0 +#define MPR121_SFI_18 0 + +#define MPR121_ESI_1MS 0 +#define MPR121_ESI_2MS 1 +#define MPR121_ESI_4MS 2 +#define MPR121_ESI_8MS 3 +#define MPR121_ESI_16MS 4 +#define MPR121_ESI_32MS 5 +#define MPR121_ESI_64MS 6 +#define MPR121_ESI_128MS 7 + +#define MPR121_CL_NONE 0 +#define MPR121_CL_LOCK 1 +#define MPR121_CL_INIT1 2 +#define MPR121_CL_INTI2 3 + +#define MPR121_ELEPROX_0 0 +#define MPR121_ELEPROX_2 1 +#define MPR121_ELEPROX_4 2 +#define MPR121_ELEPROX_12 3 + +#define MPR121_AFES_6 0 +#define MPR121_AFES_10 1 +#define MPR121_AFES_18 2 +#define MPR121_AFES_34 3 + +#define MPR121_RETRY_0 0 +#define MPR121_RETRY_2 1 +#define MPR121_RETRY_4 2 +#define MPR121_RETRY_8 3 + +// Device register map + +#define MPR121_TOUCHSTATUS_L 0x00 +#define MPR121_TOUCHSTATUS_H 0x01 +#define MPR121_OOR_L 0x02 +#define MPR121_OOR_R 0x03 +#define MPR121_FILTDATA(ch) (0x04 + 2*(ch)) +#define MPR121_BASELINE(ch) (0x1E + (ch)) +#define MPR121_MHDR 0x2B +#define MPR121_NHDR 0x2C +#define MPR121_NCLR 0x2D +#define MPR121_FDLR 0x2E +#define MPR121_MHDF 0x2F +#define MPR121_NHDF 0x30 +#define MPR121_NCLF 0x31 +#define MPR121_FDLF 0x32 +#define MPR121_NHDT 0x33 +#define MPR121_NCLT 0x34 +#define MPR121_FDLT 0x35 +#define MPR121_MHDPROXR 0x36 +#define MPR121_HHDPROXR 0x37 +#define MPR121_NCLPROXR 0x38 +#define MPR121_FDLPROXR 0x39 +#define MPR121_MHDPROXF 0x3A +#define MPR121_NHDPROXF 0x3B +#define MPR121_NCLPROXF 0x3C +#define MPR121_FDLPROXF 0x3D +#define MPR121_NHDPROXT 0x3E +#define MPR121_NCLPROXT 0x3F +#define MPR121_FDLPROXT 0x40 +#define MPR121_TOUCHTH(ch) (0x41 + 2*(ch)) +#define MPR121_RELEASETH(ch) (0x42 + 2*(ch)) +#define MPR121_DEBOUNCE 0x5B +#define MPR121_AFE1 0x5C +#define MPR121_AFE2 0x5D +#define MPR121_ECR 0x5E +#define MPR121_CDC(ch) (0x5F + (ch)) +#define MPR121_CDT(ch) (0x6C + ((ch)>>1)) +#define MPR121_CTL0 0x73 +#define MPR121_CTL1 0x74 +#define MPR121_DAT 0x75 +#define MPR121_DIR 0x76 +#define MPR121_EN 0x77 +#define MPR121_SET 0x78 +#define MPR121_CLR 0x79 +#define MPR121_TOG 0x7A +#define MPR121_AUTOCONF0 0x7B +#define MPR121_AUTOCONF1 0x7C +#define MPR121_USL 0x7D +#define MPR121_LSL 0x7E +#define MPR121_TL 0x7F +#define MPR121_SRST 0x80 + +#define MPR121_I2CADDR_DEFAULT 0x5A + +class MPR121 { + public: + MPR121() {} + + void begin(uint8_t addr = MPR121_I2CADDR_DEFAULT, TwoWire *wire = &Wire); + void init(); + + uint8_t readRegister8(uint8_t rs) {//相同 + _wire->beginTransmission(_i2caddr); + _wire->write(rs); + _wire->endTransmission(false); + _wire->requestFrom(_i2caddr, 1); + if (_wire->available() < 1) + return 0; + return _wire->read(); + } + uint16_t readRegister16(uint8_t rs) {//相同 + _wire->beginTransmission(_i2caddr); + _wire->write(rs); + _wire->endTransmission(false); + _wire->requestFrom(_i2caddr, 2); + if (_wire->available() < 2) + return 0; + uint16_t v = _wire->read(); + v |= ((uint16_t)_wire->read()) << 8; + return v; + } + void writeRegister(uint8_t rd, uint8_t value); + void writeRegisterRaw(uint8_t rd, uint8_t value, bool stop = true) { + _wire->beginTransmission(_i2caddr); + _wire->write(rd); + _wire->write(value); + _wire->endTransmission(stop); + } + + void stop() { + writeRegisterRaw(MPR121_ECR, 0x00); + } + void run() { + writeRegisterRaw(MPR121_ECR, _ecr); + } + void reset() { + writeRegisterRaw(MPR121_SRST, 0x63); + } + + uint16_t filteredData(uint8_t ch) { + return readRegister16(MPR121_FILTDATA(ch)); + } + uint16_t baselineData(uint8_t ch) { + return ((uint16_t)readRegister8(MPR121_BASELINE(ch))) << 2; + } + uint16_t touched() { + return readRegister16(MPR121_TOUCHSTATUS_L); + } + + private: + int8_t _i2caddr; + TwoWire *_wire; + uint8_t _ecr; +}; + +#endif diff --git a/BootLoader&Firmware/source code/src/serial.cpp b/BootLoader&Firmware/source code/src/serial.cpp new file mode 100644 index 0000000..fe13385 --- /dev/null +++ b/BootLoader&Firmware/source code/src/serial.cpp @@ -0,0 +1,111 @@ +#include "serial.h" +#include + +slider_packet_t slider_req, slider_resp; +int slider_tx_pending = 0; + +// int checkcom = 0; + +uint8_t sliderserial_readreq() { + static short ptr = 0; + static uint8_t checksum; + static bool esc = false; + uint8_t c; + while (SerialUSB.available()) { + + // checkcom = SLIDER_CMD_AUTO_SCAN; + + c = SerialUSB.read(); + // SYN + if (c == 0xff) { +// SerialUSB.println("SYN"); + ptr = 0; + slider_req.syn = c; + slider_req.cmd = 0; // Unset cmd + slider_req.size = 0xff; // Unset size + checksum = 0xff; + esc = false; + continue; + } + + // Escape + if (esc) { + esc = false; + c++; + } else if (c == 0xfd) { + esc = true; + continue; + } + // Checksum + checksum += c; + // Byte 2 (opcode) + if (!slider_req.cmd) { +// SerialUSB.print("Cmd: "); +// SerialUSB.println(c, HEX); + slider_req.cmd = c; + continue; + } + // Byte 3 (size) + if (slider_req.size == 0xff) { +// SerialUSB.print("Size: "); +// SerialUSB.println(c); + slider_req.size = c; + ptr = 3; + continue; + } + // Payload Body + if (ptr >= 128) { + // Buffer full. Invalidate. Wait for next SYN. + continue; + } + slider_req.data[ptr++] = c; + if (ptr-3 == slider_req.size+1) { + // End + if (checksum == 0) { +// SerialUSB.println("OK"); + return slider_req.cmd; + } +// SerialUSB.println("Checksum Error!"); + } + } + return 0; +} + +void sliderserial_writeresp() { + static short ptr = 0; + static uint8_t checksum; + // Detect new response + if (!slider_tx_pending) { + if (slider_resp.cmd) { + slider_tx_pending = slider_resp.size + 4; + ptr = 0; + checksum = 0; + } else { + return; + } + } + while (slider_tx_pending) { + uint8_t c; + if (slider_tx_pending == 1) { + c = -checksum; + } else { + c = slider_resp.data[ptr]; + } + checksum += c; + if ((ptr != 0 && c == 0xff) || c == 0xfd) { + // Escape required + if (SerialUSB.availableForWrite() < 2) + return; + SerialUSB.write(0xfd); + c--; + } else { + // Normal + if (SerialUSB.availableForWrite() < 1) + return; + } + SerialUSB.write(c); + ptr++; + slider_tx_pending--; + } + slider_resp.cmd = 0; +} diff --git a/BootLoader&Firmware/source code/src/serial.h b/BootLoader&Firmware/source code/src/serial.h new file mode 100644 index 0000000..342f924 --- /dev/null +++ b/BootLoader&Firmware/source code/src/serial.h @@ -0,0 +1,64 @@ +#ifndef SERIAL_H +#define SERIAL_H +#include + +enum { + SLIDER_CMD_AUTO_SCAN = 0x01, + SLIDER_CMD_SET_LED = 0x02, + SLIDER_CMD_AUTO_SCAN_START = 0x03, + SLIDER_CMD_AUTO_SCAN_STOP = 0x04, + SLIDER_CMD_DIVA_UNK_09 = 0x09, + SLIDER_CMD_DIVA_UNK_0A = 0x0A, + SLIDER_CMD_RESET = 0x10, + SLIDER_CMD_GET_BOARD_INFO = 0xF0 +}; + +typedef union slider_packet { + struct { + uint8_t syn; + uint8_t cmd; + uint8_t size; + union { + struct { + uint8_t led_unk; + uint8_t leds[96]; + }; + char version[32]; + uint8_t pressure[32]; + }; + }; + uint8_t data[128]; +} slider_packet_t; + +/// Request and response data +extern slider_packet_t slider_req, slider_resp; +/// A message is being sent. Serial buffers should not be changed. FastLED or +/// any other library should not mask interrupts. +extern int slider_tx_pending; + +// extern int checkcom; + +/** + * Read slider request from serial + * + * Reads from `Serial` and decodes the incoming request when a complete packet + * is correctly received. Writes the decoded request into `slider_req`. Call to + * this function will invalidate `slider_req` until a valid opcode is returned. + * @note This function is stateful! Carefully examine its implementation if you + * wish to reuse it! + * @return The opcode, or 0 if a complete request is not yet received. + */ +uint8_t sliderserial_readreq();//读取数据 + +/** + * Send response to host + * + * Encodes the response stored in `slider_resp` and send over `Serial`. + * `slider_resp` should not be modified until `slider_tx_pending` is zeroed. + * This function should be called on each loop iteration. + * @note This function is stateful! Carefully examine its implementation if you + * wish to reuse it! + */ +void sliderserial_writeresp();//写入数据 + +#endif diff --git a/BootLoader&Firmware/source code/test/README b/BootLoader&Firmware/source code/test/README new file mode 100644 index 0000000..e7d1588 --- /dev/null +++ b/BootLoader&Firmware/source code/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html