17 Commits

Author SHA1 Message Date
a54c554342 feat(apds9960): 功能恢复。 2023-04-02 19:29:12 +08:00
eaedd765ed feat(apds9960): 防中断导致假死。 2023-03-11 12:05:25 +08:00
895aa3058d feat(apds9960): 手势解析。 2023-03-11 10:46:24 +08:00
33e08edeed feat(apds9960): 手势原始数据读取 2023-03-08 23:02:48 +08:00
e426829aa6 feat: 测试中断功能(接近) 2023-03-08 14:19:35 +08:00
f6b7a398cd feat: 将环境光、距离传感器从 9930 升级到 APDS9960. #4. 2023-03-06 20:57:25 +08:00
93e8f2beda pref: 减少编码器输入的中断触发次数。 close #3. 2023-03-05 21:58:22 +08:00
d3adb8cd56 feat: 支持 IO 扩展芯片 PCA9555 与 EC11 编码器的集成。 issue #3. 2023-03-05 21:47:20 +08:00
66307c14a2 feat(pca9555): 编码器数据读取。 2023-03-04 17:40:26 +08:00
bce9548aba fix: 温度传感器扫描不到。 2023-03-04 16:24:35 +08:00
4b716751a2 fix: 温度传感器不识别。 2023-03-04 13:50:18 +08:00
58d0cc55ae chore: ignore vscode dir. 2023-02-26 23:44:51 +08:00
a869036d34 feat: 启动时检测在线的 I2C 设备,避免不在线时崩溃。 2023-02-26 23:43:17 +08:00
ded155d9b5 feat: 语音模块氛围灯控制及亮度调整动画。 2023-02-25 23:13:56 +08:00
13a00fbe1b feat: 支持语音模块。 2023-02-24 21:29:15 +08:00
0b1e0ef67c feat: 完善显示器、氛围灯亮度调整。#2. 2023-02-18 15:19:26 +08:00
fbbf31e4e3 style: 代码样式调整。 2023-02-07 23:49:43 +08:00
23 changed files with 1474 additions and 673 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
build/ build/
sdkconfig sdkconfig
sdkconfig.old sdkconfig.old
.vscode/

View File

@@ -1,30 +0,0 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "/Users/ivan/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch5-8.4.0/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
"cStandard": "c11",
"cppStandard": "c++17",
"includePath": [
"${config:idf.espIdfPath}/components/**",
"${config:idf.espIdfPathWin}/components/**",
"${config:idf.espAdfPath}/components/**",
"${config:idf.espAdfPathWin}/components/**",
"${workspaceFolder}/**"
],
"browse": {
"path": [
"/Users/ivan/esp/esp-idf/components",
"${config:idf.espIdfPathWin}/components",
"/Users/ivan/esp/esp-idf/components/**",
"${config:idf.espAdfPathWin}/components/**",
"${workspaceFolder}"
],
"limitSymbolsToIncludedHeaders": false
},
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}

10
.vscode/launch.json vendored
View File

@@ -1,10 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "espidf",
"name": "Launch",
"request": "launch"
}
]
}

51
.vscode/settings.json vendored
View File

@@ -1,51 +0,0 @@
{
"C_Cpp.intelliSenseEngine": "Tag Parser",
"idf.adapterTargetName": "esp32c3",
"idf.customExtraPaths": "/Users/ivan/.espressif/tools/xtensa-esp32-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32-elf/bin:/Users/ivan/.espressif/tools/xtensa-esp32s2-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32s2-elf/bin:/Users/ivan/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32s3-elf/bin:/Users/ivan/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch5-8.4.0/riscv32-esp-elf/bin:/Users/ivan/.espressif/tools/esp32ulp-elf/2.35_20220830/esp32ulp-elf/bin:/Users/ivan/.espressif/tools/cmake/3.23.1/CMake.app/Contents/bin:/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20220706/openocd-esp32/bin:/Users/ivan/.espressif/tools/ninja/1.10.2",
"idf.customExtraVars": "{\"OPENOCD_SCRIPTS\":\"/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20220706/openocd-esp32/share/openocd/scripts\"}",
"idf.espIdfPath": "/Users/ivan/esp/esp-idf",
"idf.openOcdConfigs": [
"board/esp32c3-builtin.cfg"
],
"idf.port": "/dev/cu.usbmodem149201",
"idf.pythonBinPath": "/Users/ivan/.espressif/python_env/idf4.4_py3.8_env/bin/python",
"idf.toolsPath": "/Users/ivan/.espressif",
"idf.gitPath": "/usr/bin/git",
"idf.flashType": "UART",
"files.associations": {
"*.ejs": "html",
"css": "postcss",
"scss": "postcss",
"*.cjson": "jsonc",
"*.wxss": "css",
"*.wxs": "javascript",
"*.inc": "c",
"*.tcc": "c",
"*.ipp": "c",
"cstring": "cpp",
"system_error": "c",
"chrono": "c",
"random": "c",
"limits": "c",
"array": "c",
"string": "c",
"string_view": "c",
"esp_bit_defs.h": "c",
"bitset": "c",
"initializer_list": "c",
"regex": "c",
"utility": "c",
"deque": "c",
"list": "c",
"unordered_map": "c",
"unordered_set": "c",
"vector": "c",
"freertos.h": "c",
"task.h": "c",
"led_strip.h": "c",
"esp_event.h": "c",
"string.h": "c",
"i2c.h": "c",
"esp_log.h": "c"
}
}

300
.vscode/tasks.json vendored
View File

@@ -1,300 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build - Build project",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py build",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py build",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
},
{
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Set ESP-IDF Target",
"type": "shell",
"command": "${command:espIdf.setTarget}",
"problemMatcher": {
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^(.*):(//d+):(//d+)://s+(warning|error)://s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "Clean - Clean the project",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py fullclean",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py fullclean",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
},
{
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
]
},
{
"label": "Flash - Flash the device",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} -b ${config:idf.flashBaudRate} flash",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py flash -p ${config:idf.portWin} -b ${config:idf.flashBaudRate}",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
},
{
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
]
},
{
"label": "Monitor: Start the monitor",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} monitor",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py -p ${config:idf.portWin} monitor",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
},
{
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
],
"dependsOn": "Flash - Flash the device"
},
{
"label": "OpenOCD: Start openOCD",
"type": "shell",
"presentation": {
"echo": true,
"reveal": "never",
"focus": false,
"panel": "new"
},
"command": "openocd -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}",
"windows": {
"command": "openocd.exe -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "adapter",
"type": "shell",
"command": "${config:idf.pythonBinPath}",
"isBackground": true,
"options": {
"env": {
"PATH": "${env:PATH}:${config:idf.customExtraPaths}",
"PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter"
}
},
"problemMatcher": {
"background": {
"beginsPattern": "\bDEBUG_ADAPTER_STARTED\b",
"endsPattern": "DEBUG_ADAPTER_READY2CONNECT",
"activeOnStart": true
},
"pattern": {
"regexp": "(\\d+)-(\\d+)-(\\d+)\\s(\\d+):(\\d+):(\\d+),(\\d+)\\s-(.+)\\s(ERROR)",
"file": 8,
"line": 2,
"column": 3,
"severity": 4,
"message": 9
}
},
"args": [
"${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter_main.py",
"-e",
"${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
"-s",
"${command:espIdf.getOpenOcdScriptValue}",
"-ip",
"localhost",
"-dn",
"${config:idf.adapterTargetName}",
"-om",
"connect_to_instance"
],
"windows": {
"command": "${config:idf.pythonBinPathWin}",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}",
"PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter"
}
}
}
}
]
}

View File

@@ -1,2 +1,2 @@
idf_component_register(SRCS "ambient_light.c" "temperature.c" "embedded_display.c" "ui.c" "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c" idf_component_register(SRCS "hw-ms03.c" "apds_9960.c" "pca9555.c" "i2c.c" "asr_pro.c" "ci_03t.c" "ui_input.c" "ambient_light.c" "temperature.c" "embedded_display.c" "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c"
INCLUDE_DIRS ".") INCLUDE_DIRS ".")

View File

@@ -65,57 +65,57 @@ menu "MQTT Configuration"
endmenu endmenu
menu "Encoder Configuration" menu "Encoder Configuration"
config ENCODER_0_CLK_PIN config ENCODER_0_CLK_PORT_IO
int "encoder 0 click GPIO" int "encoder 0 clock IO"
range 1 32 range 0 7
default 1
help
Encoder 0 clock io on PCA9555 port 1
config ENCODER_0_DT_PORT_IO
int "encoder 0 data IO"
range 0 7
default 2 default 2
help
Encoder 0 clock pin
config ENCODER_0_DT_PIN
int "encoder 0 data GPIO"
range 1 32
default 3
help help
Encoder 0 clock data Encoder 0 clock data
config ENCODER_0_SW_PIN config ENCODER_0_SW_PORT_IO
int "encoder 0 switch GPIO" int "encoder 0 switch IO"
range 1 32 range 0 7
default 0
help
Encoder 0 switch io on PCA9555 port 1
config ENCODER_1_CLK_PORT_IO
int "encoder 1 clock IO"
range 0 7
default 4 default 4
help help
Encoder 0 switch pin Encoder 1 clock io on PCA9555 port 1
config ENCODER_1_DT_PORT_IO
config ENCODER_1_CLK_PIN int "encoder 1 data IO"
int "encoder 1 click GPIO" range 0 7
range 1 32
default 5 default 5
help
Encoder 1 clock pin
config ENCODER_1_DT_PIN
int "encoder 1 data GPIO"
range 1 32
default 6
help help
Encoder 1 clock data Encoder 1 clock data
config ENCODER_1_SW_PIN config ENCODER_1_SW_PORT_IO
int "encoder 1 switch GPIO" int "encoder 1 switch IO"
range 1 32 range 0 7
default 7 default 3
help help
Encoder 1 switch pin Encoder 1 switch io on PCA9555 port 1
endmenu endmenu
menu "I2C Configuration" menu "I2C Configuration"
config I2C_SCL config I2C_SCL
int "I2C SCL GPIO" int "I2C SCL GPIO"
range 1 32 range 0 32
default 8 default 5
help help
I2C SCL GPIO I2C SCL GPIO
config I2C_SDA config I2C_SDA
int "I2C SDA GPIO" int "I2C SDA GPIO"
range 1 32 range 0 32
default 10 default 4
help help
I2C SDA GPIO I2C SDA GPIO
config I2C_NUM config I2C_NUM
@@ -124,4 +124,34 @@ menu "I2C Configuration"
default 0 default 0
help help
I2C NUM I2C NUM
endmenu
menu "UART Configuration"
config UART_TX
int "UART TX GPIO"
range 0 32
default 21
help
UART TX GPIO
config UART_RX
int "UART RX GPIO"
range 0 32
default 20
help
UART RX GPIO
config UART_NUM
int "UART NUM"
range 0 1
default 0
help
UART NUM
endmenu
menu "ADPS 9960"
config APDS_9960_INT_GPIO
int "APDS 996O INT GPIO"
range 0 32
default 2
help
APDS 996O INT GPIO
endmenu endmenu

View File

@@ -3,17 +3,8 @@
#include "driver/i2c.h" #include "driver/i2c.h"
#include "embedded_display.c" #include "embedded_display.c"
#include "esp_log.h" #include "esp_log.h"
#include "i2c.c"
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
#define I2C_MASTER_NUM CONFIG_I2C_NUM
#define APDS_9930_ADDRESS 0x39
#define APDS_9930_CMD_REPEATED 0x80 // 命令重复地址 #define APDS_9930_CMD_REPEATED 0x80 // 命令重复地址
#define APDS_9930_CMD_AUTO_INCREMENT 0x90 // 命令自动递增地址 #define APDS_9930_CMD_AUTO_INCREMENT 0x90 // 命令自动递增地址
@@ -24,7 +15,7 @@
#define APDS_9930_REG_PTIME 0x02 // Proximity ADC 时间 0xff #define APDS_9930_REG_PTIME 0x02 // Proximity ADC 时间 0xff
#define APDS_9930_REG_WTIME 0x03 // Wait 时间 0xff #define APDS_9930_REG_WTIME 0x03 // Wait 时间 0xff
#define APDS_9930_REG_PPULSE 0x0e // Proximity 脉冲计数 0x00 #define APDS_9930_REG_PPULSE 0x0e // Proximity 脉冲计数 0x00
#define APDS_9930_REG_CONTROL 0x0f // 增益控制 0x00 #define APDS_9930_REG_CONTROL 0x0f // 增益控制 0x00
#define APDS_9930_REG_Ch0DATAL 0x14 // Ch0 ADC Low data 0x00 #define APDS_9930_REG_Ch0DATAL 0x14 // Ch0 ADC Low data 0x00
#define APDS_9930_REG_Ch0DATAH 0x15 // Ch0 ADC High data 0x00 #define APDS_9930_REG_Ch0DATAH 0x15 // Ch0 ADC High data 0x00
#define APDS_9930_REG_Ch1DATAL 0x16 // Ch1 ADC Low data 0x00 #define APDS_9930_REG_Ch1DATAL 0x16 // Ch1 ADC Low data 0x00
@@ -124,6 +115,7 @@ esp_err_t apds_9930_read_word(uint8_t command, uint8_t* data_l,
} }
void ambient_light_fetch(void* arg) { void ambient_light_fetch(void* arg) {
ESP_LOGI(AMBIENT_LIGHT_TAG, "ambient_light_fetch");
esp_err_t error; esp_err_t error;
uint16_t als_ch0_raw; uint16_t als_ch0_raw;
uint16_t als_ch1_raw; uint16_t als_ch1_raw;
@@ -164,30 +156,38 @@ void ambient_light_fetch(void* arg) {
als_ch0_raw); als_ch0_raw);
} }
// als ch1 // als ch1
error = apds_9930_read_word( // error = apds_9930_read_word(
APDS_9930_CMD_AUTO_INCREMENT | APDS_9930_REG_Ch1DATAL, // APDS_9930_CMD_AUTO_INCREMENT | APDS_9930_REG_Ch1DATAL,
&(als_ch1_buffer[1]), &(als_ch1_buffer[0])); // &(als_ch1_buffer[1]), &(als_ch1_buffer[0]));
if (error != ESP_OK) { // if (error != ESP_OK) {
ESP_LOGW(AMBIENT_LIGHT_TAG, "read failed. %x", error); // ESP_LOGW(AMBIENT_LIGHT_TAG, "read failed. %x", error);
} else { // } else {
als_ch1_raw = als_ch1_buffer[0] << 8 | als_ch1_buffer[1]; // als_ch1_raw = als_ch1_buffer[0] << 8 | als_ch1_buffer[1];
sprintf(als_ch1_str, "Ch1: % 5d ", als_ch1_raw); // sprintf(als_ch1_str, "Ch1: % 5d ", als_ch1_raw);
display_print8_str(8, 6, als_ch1_str); // display_print8_str(8, 6, als_ch1_str);
ESP_LOGD(AMBIENT_LIGHT_TAG, "ALS Ch1: %d, %x", als_ch1_raw, // ESP_LOGD(AMBIENT_LIGHT_TAG, "ALS Ch1: %d, %x", als_ch1_raw,
als_ch1_raw); // als_ch1_raw);
} // }
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(1000));
} }
display_fill_rect(0, 2, 128, 8, 0x00); display_fill_rect(0, 2, 128, 8, 0x00);
} }
void ambient_light_auto_fetch() { void ambient_light_auto_fetch() {
xTaskCreate(ambient_light_fetch, "ui_input_event", 2048, NULL, 10, NULL); if (is_apds_9930_online == 0) {
return;
}
xTaskCreate(ambient_light_fetch, "ambient-light", 2048, NULL, 10, NULL);
} }
void ambient_light_init() { void ambient_light_init() {
// esp_log_level_set(AMBIENT_LIGHT_TAG, ESP_LOG_DEBUG); if (is_apds_9930_online == 0) {
ESP_LOGI(AMBIENT_LIGHT_TAG, "APDS 9930 is offline");
return;
}
ESP_LOGI(AMBIENT_LIGHT_TAG, "Initializing APDS-9930");
// esp_log_level_set(AMBIENT_LIGHT_TAG, ESP_LOG_ERROR);
ESP_ERROR_CHECK(apds_9930_write(APDS_9930_CMD_REPEATED | APDS_9930_REG_ATIME, ESP_ERROR_CHECK(apds_9930_write(APDS_9930_CMD_REPEATED | APDS_9930_REG_ATIME,
APDS_9930_ATIME_VALUE)); APDS_9930_ATIME_VALUE));
ESP_ERROR_CHECK(apds_9930_write(APDS_9930_CMD_REPEATED | APDS_9930_REG_PTIME, ESP_ERROR_CHECK(apds_9930_write(APDS_9930_CMD_REPEATED | APDS_9930_REG_PTIME,

524
main/apds_9960.c Normal file
View File

@@ -0,0 +1,524 @@
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "embedded_display.c"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "i2c.c"
#define APDS_9960_INT_GPIO CONFIG_APDS_9960_INT_GPIO
// ===============================================
// Register addresses
// ===============================================
// 0x80 ENABLE R/W Enable states and interrupts 0x00
// 0x81 ATIME R/W ADC integration time 0xFF
// 0x83 WTIME R/W Wait time (non-gesture) 0xFF
// 0x84 AILTL R/W ALS interrupt low threshold low byte --
// 0x85 AILTH R/W ALS interrupt low threshold high byte --
// 0x86 AIHTL R/W ALS interrupt high threshold low byte 0x00
// 0x87 AIHTH R/W ALS interrupt high threshold high byte 0x00
// 0x89 PILT R/W Proximity interrupt low threshold 0x00
// 0x8B PIHT R/W Proximity interrupt high threshold 0x00
// 0x8C PERS R/W Interrupt persistence filters (non-gesture) 0x00
// 0x8D CONFIG1 R/W Configuration register one 0x60
// 0x8E PPULSE R/W Proximity pulse count and length 0x40
// 0x8F CONTROL R/W Gain control 0x00
// 0x90 CONFIG2 R/W Configuration register two 0x01
// 0x92 ID R Device ID ID
// 0x93 STATUS R Device status 0x00
// 0x94 CDATAL R Low byte of clear channel data 0x00
// 0x95 CDATAH R High byte of clear channel data 0x00
// 0x96 RDATAL R Low byte of red channel data 0x00
// 0x97 RDATAH R High byte of red channel data 0x00
// 0x98 GDATAL R Low byte of green channel data 0x00
// 0x99 GDATAH R High byte of green channel data 0x00
// 0x9A BDATAL R Low byte of blue channel data 0x00
// 0x9B BDATAH R High byte of blue channel data 0x00
// 0x9C PDATA R Proximity data 0x00
// 0x9D POFFSET_UR R/W Proximity offset for UP and RIGHT photodiodes 0x00
// 0x9E POFFSET_DL R/W Proximity offset for DOWN and LEFT photodiodes 0x00
// 0x9F CONFIG3 R/W Configuration register three 0x00
// 0xA0 GPENTH R/W Gesture proximity enter threshold 0x00
// 0xA1 GEXTH R/W Gesture exit threshold 0x00
// 0xA2 GCONF1 R/W Gesture configuration one 0x00
// 0xA3 GCONF2 R/W Gesture configuration two 0x00
// 0xA4 GOFFSET_U R/W Gesture UP offset register 0x00
// 0xA5 GOFFSET_D R/W Gesture DOWN offset register 0x00
// 0xA7 GOFFSET_L R/W Gesture LEFT offset register 0x00
// 0xA9 GOFFSET_R R/W Gesture RIGHT offset register 0x00
// 0xA6 GPULSE R/W Gesture pulse count and length 0x40
// 0xAA GCONF3 R/W Gesture configuration three 0x00
// 0xAB GCONF4 R/W Gesture configuration four 0x00
// 0xAE GFLVL R Gesture FIFO level 0x00
// 0xAF GSTATUS R Gesture status 0x00
// 0xE4 (1) IFORCE W Force interrupt 0x00
// 0xE5 (1) PICLEAR W Proximity interrupt clear 0x00
// 0xE6 (1) CICLEAR W ALS clear channel interrupt clear 0x00
// 0xE7 (1) AICLEAR W All non-gesture interrupts clear 0x00
// 0xFC GFIFO_U R Gesture FIFO UP value 0x00
// 0xFD GFIFO_D R Gesture FIFO DOWN value 0x00
// 0xFE GFIFO_L R Gesture FIFO LEFT value 0x00
// 0xFF GFIFO_R R Gesture FIFO RIGHT value 0x00
// ----------------------------------- 描述 默认值
#define APDS_9960_REG_ENABLE 0x80 // 状态和中断的启用 0x00
#define APDS_9960_REG_ATIME 0x81 // ADC 积分时间 0xff
#define APDS_9960_REG_WTIME 0x83 // 等待时间(非手势) 0xff
#define APDS_9960_REG_AILTL 0x84 // ALS 中断低阈值低字节 --
#define APDS_9960_REG_AILTH 0x85 // ALS 中断低阈值高字节 --
#define APDS_9960_REG_AIHTL 0x86 // ALS 中断高阈值低字节 0x00
#define APDS_9960_REG_AIHTH 0x87 // ALS 中断高阈值高字节 0x00
#define APDS_9960_REG_PILT 0x89 // 接近中断低阈值 0x00
#define APDS_9960_REG_PIHT 0x8B // 接近中断高阈值 0x00
#define APDS_9960_REG_PERS 0x8C // 中断持续性过滤器(非手势) 0x00
#define APDS_9960_REG_CONFIG1 0x8D // 配置寄存器一 0x60
#define APDS_9960_REG_PPULSE 0x8E // 接近脉冲计数和长度 0x40
#define APDS_9960_REG_CONTROL 0x8F // 增益控制 0x00
#define APDS_9960_REG_CONFIG2 0x90 // 配置寄存器二 0x01
#define APDS_9960_REG_ID 0x92 // 设备 ID ID
#define APDS_9960_REG_STATUS 0x93 // 设备状态 0x00
#define APDS_9960_REG_CDATAL 0x94 // 清除通道数据低字节 0x00
#define APDS_9960_REG_CDATAH 0x95 // 清除通道数据高字节 0x00
#define APDS_9960_REG_RDATAL 0x96 // 红色通道数据低字节 0x00
#define APDS_9960_REG_RDATAH 0x97 // 红色通道数据高字节 0x00
#define APDS_9960_REG_GDATAL 0x98 // 绿色通道数据低字节 0x00
#define APDS_9960_REG_GDATAH 0x99 // 绿色通道数据高字节 0x00
#define APDS_9960_REG_BDATAL 0x9A // 蓝色通道数据低字节 0x00
#define APDS_9960_REG_BDATAH 0x9B // 蓝色通道数据高字节 0x00
#define APDS_9960_REG_PDATA 0x9C // 接近数据 0x00
#define APDS_9960_REG_POFFSET_UR 0x9D // 接近偏移量上和右 0x00
#define APDS_9960_REG_POFFSET_DL 0x9E // 接近偏移量下和左 0x00
#define APDS_9960_REG_CONFIG3 0x9F // 配置寄存器三 0x00
#define APDS_9960_REG_GPENTH 0xA0 // 手势进入阈值 0x28
#define APDS_9960_REG_GEXTH 0xA1 // 手势退出阈值 0x1E
#define APDS_9960_REG_GCONF1 0xA2 // 手势配置寄存器一 0x40
#define APDS_9960_REG_GCONF2 0xA3 // 手势配置寄存器二 0x66
#define APDS_9960_REG_GOFFSET_U 0xA4 // 手势偏移量上 0x00
#define APDS_9960_REG_GOFFSET_D 0xA5 // 手势偏移量下 0x00
#define APDS_9960_REG_GOFFSET_L 0xA7 // 手势偏移量左 0x00
#define APDS_9960_REG_GOFFSET_R 0xA9 // 手势偏移量右 0x00
#define APDS_9960_REG_GPULSE 0xA6 // 手势脉冲计数和长度 0xC5
#define APDS_9960_REG_GCONF3 0xAA // 手势配置寄存器三 0x00
#define APDS_9960_REG_GCONF4 0xAB // 手势配置寄存器四 0x00
#define APDS_9960_REG_GFLVL 0xAE // 手势 FIFO 级别 0x00
#define APDS_9960_REG_GSTATUS 0xAF // 手势状态 0x00
#define APDS_9960_REG_IFORCE 0xE4 // 强制中断 0x00
#define APDS_9960_REG_PICLEAR 0xE5 // 清除接近中断 0x00
#define APDS_9960_REG_CICLEAR 0xE6 // 清除 ALS 中断 0x00
#define APDS_9960_REG_AICLEAR 0xE7 // 清除手势中断 0x00
#define APDS_9960_REG_GFIFO_U 0xFC // 手势 FIFO 数据上 0x00
#define APDS_9960_REG_GFIFO_D 0xFD // 手势 FIFO 数据下 0x00
#define APDS_9960_REG_GFIFO_L 0xFE // 手势 FIFO 数据左 0x00
#define APDS_9960_REG_GFIFO_R 0xFF // 手势 FIFO 数据右 0x00
#define APDS_9960_GVALID 0b00000001 // GVALID
#define APDS_9960_GFOV 0b00000010 // GFOV
#define APDS_9960_PINT 0x20 // PINT
#define APDS_9960_AINT 0x10 // AINT
#define APDS_9960_GINT 0x04 // GINT
// 50 mA LED, Reserved, 2x PGAIN, 4x ALS/Cain GAIN
#define APDS_9960_CONTROL_VALUE 0b00001010
// Enable Gesture, Proximity, ALS, Power
// X, GEN, PIEN, AIEN, WEN, PEN, AEN, PON
#define APDS_9960_ENABLE_VALUE 0b01100111
#define APDS_9960_TAG "APDS-9960"
static xQueueHandle apds_9960_int_evt_queue = NULL;
static int64_t last_apds_9960_int_time = 0;
esp_err_t apds_9960_write_empty(uint8_t command) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, command, ACK_CHECK_DIS);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "write failed. %d", error);
}
return error;
}
esp_err_t apds_9960_write(uint8_t command, uint8_t data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, command, ACK_CHECK_EN);
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "write failed. %d", error);
}
return error;
}
esp_err_t apds_9960_read_byte(uint8_t command, uint8_t* data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, command, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ,
ACK_CHECK_EN);
i2c_master_read_byte(cmd, data, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
}
return error;
}
// read word
esp_err_t apds_9960_read_word(uint8_t command, uint16_t* data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, command, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ,
ACK_CHECK_EN);
i2c_master_read_byte(cmd, (uint8_t*)data, ACK_VAL);
i2c_master_read_byte(cmd, (uint8_t*)data + 1, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
}
return error;
}
// read bytes by length
esp_err_t apds_9960_read_bytes_len(uint8_t command, uint8_t* data,
uint8_t len) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, command, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, APDS_9960_ADDRESS << 1 | I2C_MASTER_READ,
ACK_CHECK_EN);
for (int i = 0; i < len; i++) {
if (i == len - 1) {
i2c_master_read_byte(cmd, (uint8_t*)data + i, NACK_VAL);
} else {
i2c_master_read_byte(cmd, (uint8_t*)data + i, ACK_VAL);
}
}
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
}
return error;
}
void apds_9960_clear_all_int(void) {
ESP_LOGI(APDS_9960_TAG, "apds_9960_clear_all_int");
ESP_ERROR_CHECK_WITHOUT_ABORT(apds_9960_write_empty(APDS_9960_REG_AICLEAR));
ESP_ERROR_CHECK_WITHOUT_ABORT(apds_9960_write(APDS_9960_REG_GCONF4, 0x06));
}
void apds_9960_fetch(void* arg) {
ESP_LOGI(APDS_9960_TAG, "apds_9960_fetch");
esp_err_t error;
uint16_t red_raw;
uint16_t green_raw;
uint16_t blue_raw;
uint16_t clear_raw;
uint8_t byte_buffer;
uint8_t gesture_status_raw;
uint8_t status_raw;
char red_str[20];
char green_str[20];
char blue_str[20];
char clear_str[20];
char status_str[20];
uint8_t interrupt = 0;
display_fill_rect(0, 2, 128, 8, 0x00);
for (;;) {
if (last_apds_9960_int_time + 1000000 < esp_timer_get_time()) {
interrupt = gpio_get_level(APDS_9960_INT_GPIO);
if (interrupt == 1 ||
last_apds_9960_int_time + 10000000 < esp_timer_get_time()) {
apds_9960_clear_all_int();
}
}
// clear
error = apds_9960_read_word(APDS_9960_REG_CDATAL, &clear_raw);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
} else {
sprintf(clear_str, "C:% 5d", clear_raw);
display_print8_str(64, 6, clear_str);
ESP_LOGD(APDS_9960_TAG, "Clear: %d", clear_raw);
}
// red
error = apds_9960_read_word(APDS_9960_REG_RDATAL, &red_raw);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
} else {
sprintf(red_str, "R:% 5d", red_raw);
display_print8_str(0, 4, red_str);
ESP_LOGD(APDS_9960_TAG, "Red: %d", red_raw);
}
// green
error = apds_9960_read_word(APDS_9960_REG_GDATAL, &green_raw);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
} else {
sprintf(green_str, "G:% 5d", green_raw);
display_print8_str(64, 4, green_str);
ESP_LOGD(APDS_9960_TAG, "Green: %d", green_raw);
}
// blue
error = apds_9960_read_word(APDS_9960_REG_BDATAL, &blue_raw);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read failed. %d", error);
} else {
sprintf(blue_str, "B:% 5d", blue_raw);
display_print8_str(0, 6, blue_str);
ESP_LOGD(APDS_9960_TAG, "Blue: %d", blue_raw);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
display_fill_rect(0, 2, 128, 8, 0x00);
}
void apds_9960_auto_fetch() {
if (is_apds_9960_online == 0) {
return;
}
xTaskCreate(apds_9960_fetch, "APDS-9960-fetch", 2048, NULL, 10, NULL);
}
void apds_9960_read_gesture() {
ESP_LOGI(APDS_9960_TAG, "apes_9960_gesture_fetch");
uint8_t byte_buffer;
esp_err_t error;
uint32_t gesture_values_raw_arr[32];
char gesture_values_str_arr[20];
error = apds_9960_read_byte(APDS_9960_REG_GSTATUS, &byte_buffer);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read APDS_9960_REG_GSTATUS failed. %d", error);
return;
}
ESP_LOGD(APDS_9960_TAG, "APDS-9960 interrupt. status: %x", byte_buffer);
if (!(byte_buffer & APDS_9960_GVALID)) {
ESP_LOGI(APDS_9960_TAG, "Gesture no valid");
return;
}
ESP_LOGD(APDS_9960_TAG, "Gesture interrupt");
error = apds_9960_read_byte(APDS_9960_REG_GFLVL, &byte_buffer);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read APDS_9960_REG_GFLVL failed. %d", error);
apds_9960_write(APDS_9960_REG_GCONF4, 0x06);
return;
}
if (byte_buffer < 4) {
ESP_LOGD(APDS_9960_TAG, "Gesture FIFO level too low: %d", byte_buffer);
apds_9960_write(APDS_9960_REG_GCONF4, 0x06);
return;
}
ESP_LOGD(APDS_9960_TAG, "Gesture FIFO Level: %d", byte_buffer);
error = apds_9960_read_bytes_len(
APDS_9960_REG_GFIFO_U, (uint8_t*)gesture_values_raw_arr, byte_buffer * 4);
apds_9960_write(APDS_9960_REG_GCONF4, 0x06);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read APDS_9960_REG_GFIFO(len: %d) failed. % d",
byte_buffer * 4, error);
} else {
int16_t before_ud = 0, before_lr = 0, after_ud = 0, after_lr = 0;
int16_t u = 0, d = 0, l = 0, r = 0;
uint8_t last_2_index = byte_buffer - 2;
// head 2
for (int i = 0; i < 2; i++) {
u = gesture_values_raw_arr[i] & 0xff;
d = gesture_values_raw_arr[i] >> 8 & 0xff;
l = gesture_values_raw_arr[i] >> 16 & 0xff;
r = gesture_values_raw_arr[i] >> 24 & 0xff;
before_ud += (u - d) * 100 / u + d;
before_lr += (l - r) * 100 / l + r;
}
// last 2
for (int i = last_2_index; i < byte_buffer; i++) {
u = gesture_values_raw_arr[i] & 0xff;
d = gesture_values_raw_arr[i] >> 8 & 0xff;
l = gesture_values_raw_arr[i] >> 16 & 0xff;
r = gesture_values_raw_arr[i] >> 24 & 0xff;
after_ud += (u - d) * 100 / u + d;
after_lr += (l - r) * 100 / l + r;
}
for (int i = 0; i < byte_buffer; i++) {
if (i < 2) {
u = gesture_values_raw_arr[i] & 0xff;
d = gesture_values_raw_arr[i] >> 8 & 0xff;
l = gesture_values_raw_arr[i] >> 16 & 0xff;
r = gesture_values_raw_arr[i] >> 24 & 0xff;
before_ud += (u - d) * 100 / u + d;
before_lr += (l - r) * 100 / l + r;
} else if (i >= last_2_index) {
u = gesture_values_raw_arr[i] & 0xff;
d = gesture_values_raw_arr[i] >> 8 & 0xff;
l = gesture_values_raw_arr[i] >> 16 & 0xff;
r = gesture_values_raw_arr[i] >> 24 & 0xff;
after_ud += (u - d) * 100 / u + d;
after_lr += (l - r) * 100 / l + r;
}
}
printf("Δud: %d, Δlr: %d \n", after_ud - before_ud, after_lr - before_lr);
display_fill_rect(0, 0, 128, 2, 0x00);
if (abs(after_ud - before_ud) * 2 > abs(after_lr - before_lr)) {
if (after_ud - before_ud < -80) {
display_print8_str(0, 0, "Gesture: up");
} else if (after_ud - before_ud > 80) {
display_print8_str(0, 0, "Gesture: down");
}
} else {
if (after_lr - before_lr < -120) {
display_print8_str(0, 0, "Gesture: left");
} else if (after_lr - before_lr > 120) {
display_print8_str(0, 0, "Gesture: right");
}
}
// display_print8_str(0, 0, gesture_str);
}
}
void apds_9960_read_proximity() {
uint8_t proximity_raw;
char proximity_str[20];
esp_err_t error;
// Proximity
error = apds_9960_read_byte(APDS_9960_REG_PDATA, &proximity_raw);
if (error != ESP_OK) {
ESP_LOGW(APDS_9960_TAG, "read proximity failed. %x", error);
} else {
ESP_LOGD(APDS_9960_TAG, "Prox: % 5d ", proximity_raw);
sprintf(proximity_str, "Prox: % 5d ", proximity_raw);
display_print8_str(8, 2, proximity_str);
}
}
void apds_9960_int_handler(void* arg) {
xQueueSendFromISR(apds_9960_int_evt_queue, &arg, NULL);
}
void apds_9960_int_evt_handler() {
if (is_apds_9960_online == 0) {
return;
}
apds_9960_clear_all_int();
esp_err_t error;
uint8_t status_raw;
while (xQueueReceive(apds_9960_int_evt_queue, NULL, portMAX_DELAY)) {
last_apds_9960_int_time = esp_timer_get_time();
ESP_ERROR_RETRY(apds_9960_read_byte(APDS_9960_REG_STATUS, &status_raw), 10);
ESP_ERROR_RETRY(apds_9960_write_empty(APDS_9960_REG_AICLEAR), 10);
ESP_LOGD(
APDS_9960_TAG, "[apds_9960_int_evt_handler] status %d%d%d%d %d%d%d%d",
(status_raw >> 7) & 1, (status_raw >> 6) & 1, (status_raw >> 5) & 1,
(status_raw >> 4) & 1, (status_raw >> 3) & 1, (status_raw >> 2) & 1,
(status_raw >> 1) & 1, status_raw & 1);
if (status_raw & APDS_9960_PINT) {
apds_9960_read_proximity();
}
if (status_raw & APDS_9960_GINT) {
apds_9960_read_gesture();
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void apds_9960_init() {
if (is_apds_9960_online == 0) {
ESP_LOGI(APDS_9960_TAG, "APDS-9960 is offline");
return;
}
ESP_LOGI(APDS_9960_TAG, "Initializing APDS-9960");
// esp_log_level_set(APDS_9960_TAG, ESP_LOG_DEBUG);
gpio_config_t io_conf = {};
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 0;
io_conf.pull_down_en = 0;
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.pin_bit_mask = 1ULL << APDS_9960_INT_GPIO;
gpio_config(&io_conf);
gpio_isr_handler_add(APDS_9960_INT_GPIO, apds_9960_int_handler, NULL);
// 环境光 ADC 积分时间
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_ATIME, 246)); // 27.8ms
// 增益
ESP_ERROR_CHECK(
apds_9960_write(APDS_9960_REG_CONTROL, APDS_9960_CONTROL_VALUE));
// enable gesture interrupt
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GCONF4, 0x06));
// 累积的手势数据达到 4 组时触发中断
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GCONF1, 0x40));
// Gesture Enter Threshold
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GPENTH, 3));
// Gesture Exit Threshold
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GEXTH, 3));
// Gesture Drive Strength
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_GCONF2, 0b0110000));
// // set wait time
// ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_WTIME, 171));
// set interrupt persistence
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_PERS, 0x44));
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_PILT, 0x80));
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_PIHT, 0x40));
ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_CONFIG2, 0x80));
// // enable sleep after interrupt
// ESP_ERROR_CHECK(apds_9960_write(APDS_9960_REG_CONFIG3, 0x10));
ESP_ERROR_CHECK(
apds_9960_write(APDS_9960_REG_ENABLE, APDS_9960_ENABLE_VALUE));
apds_9960_int_evt_queue = xQueueCreate(10, NULL);
xTaskCreate(apds_9960_int_evt_handler, "apds_9960_gesture_fetch", 2048, NULL,
10, NULL);
}

87
main/asr_pro.c Normal file
View File

@@ -0,0 +1,87 @@
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "light.c"
#include "string.h"
static const int RX_BUF_SIZE = 1024;
#define TXD_PIN (GPIO_NUM_12)
#define RXD_PIN (GPIO_NUM_13)
int sendData(const char *logName, const char *data) {
const int len = strlen(data);
const int txBytes = uart_write_bytes(UART_NUM_1, data, len);
ESP_LOGI(logName, "Wrote %d bytes", txBytes);
return txBytes;
}
static void tx_task(void *arg) {
static const char *TX_TASK_TAG = "TX_TASK";
esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
while (1) {
sendData(TX_TASK_TAG, "Hello world");
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
static void rx_task(void *arg) {
static const char *RX_TASK_TAG = "RX_TASK";
esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
uint8_t *data = (uint8_t *)malloc(RX_BUF_SIZE + 1);
uint8_t tx_buff[4] = {0};
while (1) {
const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX_BUF_SIZE,
100 / portTICK_PERIOD_MS);
if (rxBytes > 0) {
data[rxBytes] = 0;
ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
if (data[0] == 0x11 && rxBytes >= 2) {
if (data[1] <= 6) {
light_mode = data[1];
}
tx_buff[0] = data[0];
tx_buff[1] = light_mode;
uart_write_bytes(UART_NUM_1, tx_buff, 2);
} else if (data[0] == 0x12 && rxBytes >= 2) {
tx_buff[0] = 0x12;
tx_buff[1] = data[1];
led_strip_set_brightness(data[1]);
uart_write_bytes(UART_NUM_1, tx_buff, 2);
} else if (data[0] == 0x13 && rxBytes >= 2) {
tx_buff[0] = 0x12;
tx_buff[1] = display_ambient_lighting_level + (int8_t)data[1];
led_strip_set_brightness(tx_buff[1]);
uart_write_bytes(UART_NUM_1, tx_buff, 2);
}
}
}
free(data);
}
void asr_pro_init() {
const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
// We won't use a buffer for sending data.
uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
uart_param_config(UART_NUM_1, &uart_config);
uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE,
UART_PIN_NO_CHANGE);
xTaskCreate(rx_task, "uart_rx_task", 1024 * 2, NULL, configMAX_PRIORITIES,
NULL);
// xTaskCreate(tx_task, "uart_tx_task", 1024 * 2, NULL, configMAX_PRIORITIES -
// 1,
// NULL);
}

118
main/ci_03t.c Normal file
View File

@@ -0,0 +1,118 @@
#pragma once
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "light.c"
#include "string.h"
static const int UART_1_RX_BUF_SIZE = 1024;
#define CI_03T_TXD_PIN (CONFIG_UART_TX)
#define CI_03T_RXD_PIN (CONFIG_UART_RX)
#define CI_03T_UART_NUM (CONFIG_UART_NUM)
#define SEND_DATA_FRAME_HEAD \
(uint8_t[]) { 0xaa, 0x55 }
#define SEND_DATA_FRAME_TAIL \
(uint8_t[]) { 0x55, 0xaa }
#define CI_O3T_LOG_TAG "CI_03T"
// emtpy buffer for sending data
uint8_t ci_03t_tx_buffer[20] = {0};
int ci_03t_send_data(const uint8_t *data, uint8_t data_len) {
memcpy(ci_03t_tx_buffer, SEND_DATA_FRAME_HEAD, sizeof(SEND_DATA_FRAME_HEAD));
memcpy(ci_03t_tx_buffer + sizeof(SEND_DATA_FRAME_HEAD), data, data_len);
memcpy(ci_03t_tx_buffer + sizeof(SEND_DATA_FRAME_HEAD) + data_len,
SEND_DATA_FRAME_TAIL, sizeof(SEND_DATA_FRAME_TAIL));
const int len =
sizeof(SEND_DATA_FRAME_HEAD) + data_len + sizeof(SEND_DATA_FRAME_TAIL);
const int txBytes = uart_write_bytes(CI_03T_UART_NUM, ci_03t_tx_buffer, len);
ESP_LOGI(CI_O3T_LOG_TAG, "Wrote %d bytes", txBytes);
ESP_LOG_BUFFER_HEXDUMP(CI_O3T_LOG_TAG, ci_03t_tx_buffer, len, ESP_LOG_INFO);
return txBytes;
}
int sendData(const char *data) {
const int len = strlen(data);
const int txBytes = uart_write_bytes(CI_03T_UART_NUM, data, len);
ESP_LOGI("TEST", "Wrote %d bytes", txBytes);
return txBytes;
}
static void tx_task(void *arg) {
static const char *TX_TASK_TAG = "TX_TASK";
esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
while (1) {
vTaskDelay(100 / portTICK_PERIOD_MS);
// sendData(TX_TASK_TAG, "Hello world");
}
}
static void rx_task(void *arg) {
static const char *RX_TASK_TAG = "RX_TASK";
esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
uint8_t *data = (uint8_t *)malloc(UART_1_RX_BUF_SIZE + 1);
uint8_t tx_buff[4] = {0};
while (1) {
const int rxBytes = uart_read_bytes(
CI_03T_UART_NUM, data, UART_1_RX_BUF_SIZE, 100 / portTICK_PERIOD_MS);
if (rxBytes > 0) {
data[rxBytes] = 0;
ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
if (data[0] == 0x98 && data[1] == 0x77 && data[rxBytes - 1] == 0x98 &&
data[rxBytes - 2] == 0x77) {
if (data[2] == 0x10) { // 氛围灯模式
if (data[3] == 0x02) { // 开灯、正常模式
tx_buff[0] = 0x05;
led_strip_set_brightness(150);
ci_03t_send_data(tx_buff, 1);
continue;
}
if (data[3] == 0x01) { // 开灯、正常模式
tx_buff[0] = 0x06;
led_strip_set_brightness(20);
ci_03t_send_data(tx_buff, 1);
continue;
}
if (data[3] == 0x00) { // 关灯
led_strip_set_brightness(0);
tx_buff[0] = 0x04;
ci_03t_send_data(tx_buff, 1);
continue;
}
}
ESP_LOGW(RX_TASK_TAG, "Unknow command");
} else {
ESP_LOGW(RX_TASK_TAG, "Invalid data");
}
}
}
free(data);
}
void ci_03t_init() {
const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_ODD,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
// We won't use a buffer for sending data.
uart_driver_install(CI_03T_UART_NUM, UART_1_RX_BUF_SIZE * 2, 0, 0, NULL, 0);
uart_param_config(CI_03T_UART_NUM, &uart_config);
uart_set_pin(CI_03T_UART_NUM, CI_03T_TXD_PIN, CI_03T_RXD_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
xTaskCreate(rx_task, "uart_rx_task", 1024 * 2, NULL, configMAX_PRIORITIES,
NULL);
}

20
main/common.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "esp_log.h"
#define ESP_ERROR_RETRY(action, max_retries) \
{ \
uint8_t retry_count = 0; \
esp_err_t error; \
while (retry_count < max_retries) { \
error = action; \
if (error == ESP_OK) break; \
retry_count++; \
ESP_LOGI("RETRY", "Retrying... (%d/%d)\n", retry_count + 1, \
max_retries); \
} \
if (error != ESP_OK) { \
ESP_LOGE("RETRY", "retry failed. %d", error); \
ESP_ERROR_CHECK(error); \
} \
}

26
main/config_key.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
typedef enum e_ui_input_key {
ui_input_key_display_0_brightness = 0,
ui_input_key_display_1_brightness = 1,
ui_input_key_computer_volume = 2,
ui_input_key_display_ambient_lighting_level = 3,
ui_input_key_display_ambient_lighting_mode = 4,
ui_input_key_display_0_mode = 5,
ui_input_key_display_1_mode = 6,
} e_ui_input_key_t;
typedef struct s_ui_input {
e_ui_input_key_t key;
int16_t value;
} s_ui_input_t;
typedef enum e_ui_input_raw_key {
ui_input_raw_key_encoder_0 = 0,
ui_input_raw_key_encoder_1 = 1,
} e_ui_input_raw_key_t;
typedef struct s_ui_input_raw {
e_ui_input_raw_key_t key;
uint8_t value;
} s_ui_input_raw_t;

View File

@@ -1,22 +1,22 @@
#pragma once #pragma once
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "codetab.h" #include "codetab.h"
#include "config_key.h"
#include "driver/i2c.h" #include "driver/i2c.h"
#include "esp_log.h" #include "esp_log.h"
#include "i2c.c"
#define Brightness 0xCF #define Brightness 0xCF
#define X_WIDTH 128 #define X_WIDTH 128
#define Y_WIDTH 64 #define Y_WIDTH 64
#define I2C_ADDRESS 0x78
#define I2C_MASTER_NUM CONFIG_I2C_NUM
void i2cWriteByte(uint8_t reg, uint8_t data) { void i2cWriteByte(uint8_t reg, uint8_t data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd); i2c_master_start(cmd);
i2c_master_write_byte(cmd, I2C_ADDRESS | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, SSD1306_ADDRESS << 1 | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg, true); i2c_master_write_byte(cmd, reg, true);
i2c_master_write_byte(cmd, data, true); i2c_master_write_byte(cmd, data, true);
i2c_master_stop(cmd); i2c_master_stop(cmd);
@@ -57,6 +57,9 @@ void display_set_pos(uint8_t x, uint8_t y) {
} }
void display_print8_str(uint8_t x, uint8_t y, char str[]) { void display_print8_str(uint8_t x, uint8_t y, char str[]) {
if (!is_embedded_display_online) {
return;
}
uint8_t c; uint8_t c;
for (uint8_t ch, ci = 0; ch = str[ci], ch != '\0'; ci++, x += 8) { for (uint8_t ch, ci = 0; ch = str[ci], ch != '\0'; ci++, x += 8) {
c = ch - 0x20; c = ch - 0x20;
@@ -72,6 +75,11 @@ void display_print8_str(uint8_t x, uint8_t y, char str[]) {
} }
void init_display() { void init_display() {
if (is_embedded_display_online == 0) {
ESP_LOGE("display", "display is offline");
return;
}
i2cWriteCommand(0xAE); // display off i2cWriteCommand(0xAE); // display off
i2cWriteCommand(0x00); // set lower column address i2cWriteCommand(0x00); // set lower column address
i2cWriteCommand(0x10); // set higher column address i2cWriteCommand(0x10); // set higher column address
@@ -101,4 +109,37 @@ void init_display() {
display_fill(0x00); display_fill(0x00);
display_set_pos(0, 0); display_set_pos(0, 0);
}
void gui_update_config_uint8(uint8_t key, uint8_t value) {
char changing_str[12] = "NC";
switch (key) {
case ui_input_key_display_0_brightness:
sprintf(changing_str, "Dis0: % 3d", value);
break;
case ui_input_key_display_1_brightness:
sprintf(changing_str, "Dis1: % 3d", value);
break;
case ui_input_key_computer_volume:
sprintf(changing_str, "CVol: % 3d", value);
break;
case ui_input_key_display_ambient_lighting_level:
sprintf(changing_str, "ALLv: % 3d", value);
break;
case ui_input_key_display_ambient_lighting_mode:
sprintf(changing_str, "ALMd: % 3d", value);
break;
case ui_input_key_display_0_mode:
sprintf(changing_str, "Dis0M: % 2d", value);
break;
case ui_input_key_display_1_mode:
sprintf(changing_str, "Dis1M: % 2d", value);
break;
default:
strcpy(changing_str, "NC");
break;
}
display_fill_rect(0, 6, 128, 8, 0);
display_print8_str(8, 6, changing_str);
} }

27
main/hw-ms03.c Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include "driver/gpio.h"
#include "freeRTOS/FreeRTOS.h"
#define HW_MS03_INT_GPIO 6
#define BEEP_GPIO 7
void hw_ms03_int_handler(void *arg) {
gpio_set_level(BEEP_GPIO, gpio_get_level(HW_MS03_INT_GPIO));
}
void hw_ms03_init() {
gpio_config_t io_conf = {};
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 0;
io_conf.pull_down_en = 1;
io_conf.intr_type = GPIO_INTR_ANYEDGE;
io_conf.pin_bit_mask = 1ULL << HW_MS03_INT_GPIO;
gpio_config(&io_conf);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << BEEP_GPIO;
io_conf.pull_down_en = 0;
gpio_config(&io_conf);
gpio_isr_handler_add(HW_MS03_INT_GPIO, hw_ms03_int_handler, NULL);
}

78
main/i2c.c Normal file
View File

@@ -0,0 +1,78 @@
#pragma once
#include "driver/i2c.h"
#include "esp_log.h"
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_SDA_IO CONFIG_I2C_SDA
#define I2C_MASTER_SCL_IO CONFIG_I2C_SCL
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define I2C_MASTER_NUM CONFIG_I2C_NUM
// 0 1 0 0 A2 A1 A0
#define PCA9555_ADDRESS 0x20
#define GX21M15_ADDRESS 0x48
#define APDS_9930_ADDRESS 0x39
#define APDS_9960_ADDRESS 0x39
#define SSD1306_ADDRESS 0x3c
static const char *I2C_TAG = "APP_I2C";
static uint8_t is_temperature_online = 0;
static uint8_t is_pca9555_online = 0;
static uint8_t is_apds_9930_online = 0;
static uint8_t is_apds_9960_online = 0;
static uint8_t is_embedded_display_online = 0;
void init_i2c() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
ESP_ERROR_CHECK(i2c_driver_install(I2C_MASTER_NUM, conf.mode,
I2C_MASTER_RX_BUF_DISABLE,
I2C_MASTER_TX_BUF_DISABLE, 0));
i2c_param_config(I2C_MASTER_NUM, &conf);
ESP_LOGI(I2C_TAG, "I2C initialized");
}
uint8_t i2c_check_slave_exists(uint8_t address) {
ESP_LOGI(I2C_TAG, "Checking if slave 0x%2x exists", address);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 50 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_OK) {
ESP_LOGW(I2C_TAG, "Slave 0x%2x found", address);
return 1;
} else if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGW(I2C_TAG, "Slave 0x%2x TIMEOUT", address);
return 1;
} else {
ESP_LOGW(I2C_TAG, "Slave 0x%2x not found", address);
return 0;
}
}
void i2c_check_slaves() {
is_temperature_online = i2c_check_slave_exists(GX21M15_ADDRESS);
is_pca9555_online = i2c_check_slave_exists(PCA9555_ADDRESS);
is_apds_9930_online = i2c_check_slave_exists(APDS_9930_ADDRESS);
is_apds_9960_online = i2c_check_slave_exists(APDS_9960_ADDRESS);
is_embedded_display_online = i2c_check_slave_exists(SSD1306_ADDRESS);
}

View File

@@ -6,6 +6,7 @@
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. CONDITIONS OF ANY KIND, either express or implied.
*/ */
#pragma once
#include "driver/rmt.h" #include "driver/rmt.h"
#include "esp_log.h" #include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
@@ -27,10 +28,34 @@ typedef enum light_mode_e {
light_mode_mqtt_connected = 3, light_mode_mqtt_connected = 3,
light_mode_desktop_online = 4, light_mode_desktop_online = 4,
light_mode_desktop_sending_colors = 5, light_mode_desktop_sending_colors = 5,
light_mode_off = 6,
} light_mode_t; } light_mode_t;
led_strip_t *light_led_strip; led_strip_t *light_led_strip;
light_mode_t light_mode; light_mode_t light_mode;
float display_ambient_light_brightness = 1;
uint8_t display_ambient_lighting_level = 255;
void led_strip_fade_in_light_level(void *pvParameter) {
float target = (float)display_ambient_lighting_level / 255.0;
float step_length = (target - display_ambient_light_brightness) / 40.0;
for (int t = 0; t < 40; t++) {
display_ambient_light_brightness += step_length;
vTaskDelay(pdMS_TO_TICKS(10));
}
display_ambient_light_brightness = target;
vTaskDelete(NULL);
}
void led_strip_set_brightness(uint8_t level) {
if (display_ambient_lighting_level == level) {
return;
}
display_ambient_lighting_level = level;
xTaskCreate(led_strip_fade_in_light_level, "LED_STRIP_FADE_IN_LIGHT_LEVEL",
4096, NULL, 1, NULL);
}
/** /**
* @brief Simple helper function, converting HSV color space to RGB color * @brief Simple helper function, converting HSV color space to RGB color
@@ -94,22 +119,22 @@ void update_desktop_connection_state() {
case light_mode_desktop_online: case light_mode_desktop_online:
if (beat) { if (beat) {
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, 0, 77, 77, 77)); light_led_strip->set_pixel(light_led_strip, 0, 10, 10, 10));
} }
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, 1, 77, 77, 77)); light_led_strip->set_pixel(light_led_strip, 1, 10, 10, 10));
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, 2, 77, 77, 77)); light_led_strip->set_pixel(light_led_strip, 2, 10, 10, 10));
break; break;
case light_mode_mqtt_connected: case light_mode_mqtt_connected:
if (beat) { if (beat) {
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, 0, 77, 77, 77)); light_led_strip->set_pixel(light_led_strip, 0, 10, 10, 10));
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, 1, 77, 77, 77)); light_led_strip->set_pixel(light_led_strip, 1, 10, 10, 10));
} }
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, 2, 77, 77, 77)); light_led_strip->set_pixel(light_led_strip, 2, 22, 22, 22));
break; break;
case light_mode_idle: case light_mode_idle:
if (beat) { if (beat) {
@@ -145,6 +170,7 @@ void light_for_init() {
ESP_ERROR_CHECK(light_led_strip->refresh(light_led_strip, 100)); ESP_ERROR_CHECK(light_led_strip->refresh(light_led_strip, 100));
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
} }
vTaskDelay(pdMS_TO_TICKS(100));
} while (light_mode == light_mode_init); } while (light_mode == light_mode_init);
} }
@@ -178,7 +204,11 @@ void light_for_idle() {
for (uint16_t j = 0, hue = offset; j < STRIP_LED_NUMBER; for (uint16_t j = 0, hue = offset; j < STRIP_LED_NUMBER;
j++, hue += step_length) { j++, hue += step_length) {
// Build RGB values // Build RGB values
led_strip_hsv2rgb(hue, 100, 50, &red, &green, &blue); led_strip_hsv2rgb(hue, 50, 30, &red, &green, &blue);
red = red * display_ambient_light_brightness;
green = green * display_ambient_light_brightness;
blue = blue * display_ambient_light_brightness;
// Write RGB values to strip driver // Write RGB values to strip driver
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, j, red, green, blue)); light_led_strip->set_pixel(light_led_strip, j, red, green, blue));
@@ -246,8 +276,12 @@ void light_play_colors(uint16_t len, uint8_t *buffer) {
for (uint16_t led_index = 0, buffer_cursor = 0; for (uint16_t led_index = 0, buffer_cursor = 0;
led_index < STRIP_LED_NUMBER && buffer_cursor < len; led_index < STRIP_LED_NUMBER && buffer_cursor < len;
led_index++, buffer_cursor += 3) { led_index++, buffer_cursor += 3) {
uint8_t r = buffer[buffer_cursor], g = buffer[buffer_cursor + 1], uint8_t r = (uint8_t)((float)buffer[buffer_cursor] *
b = buffer[buffer_cursor + 2]; display_ambient_light_brightness),
g = (uint8_t)((float)buffer[buffer_cursor + 1] *
display_ambient_light_brightness),
b = (uint8_t)((float)buffer[buffer_cursor + 2] *
display_ambient_light_brightness);
ESP_ERROR_CHECK( ESP_ERROR_CHECK(
light_led_strip->set_pixel(light_led_strip, led_index, r, g, b)); light_led_strip->set_pixel(light_led_strip, led_index, r, g, b));
} }

View File

@@ -1,56 +1,39 @@
#include "ambient_light.c" #include "apds_9960.c"
#include "driver/i2c.h" #include "ci_03t.c"
#include "embedded_display.c"
#include "esp_log.h" #include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "hw-ms03.c"
#include "i2c.c"
#include "light.c" #include "light.c"
#include "mqtt.c" #include "mqtt.c"
#include "pca9555.c"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "wifi.c"
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_SDA_IO CONFIG_I2C_SDA
#define I2C_MASTER_SCL_IO CONFIG_I2C_SCL
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define I2C_MASTER_NUM CONFIG_I2C_NUM
#include "embedded_display.c"
#include "temperature.c" #include "temperature.c"
#include "ui_input.c"
void init_i2c() { #include "wifi.c"
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(i2c_master_port, &conf);
ESP_LOGI("I2C", "Enabling I2C");
ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, conf.mode,
I2C_MASTER_RX_BUF_DISABLE,
I2C_MASTER_TX_BUF_DISABLE, 0));
ESP_LOGI("SCR", "I2C initialized successfully");
}
static const char *TAG = "DisplayAmbientLight"; static const char *TAG = "DisplayAmbientLight";
void app_main(void) { void app_main(void) {
light_init_strip(); light_init_strip();
gpio_install_isr_service(0);
init_i2c(); init_i2c();
i2c_check_slaves();
init_display(); init_display();
display_print8_str(0, 0, "Ambient Light"); display_print8_str(0, 0, "Ambient Light");
ambient_light_init(); // hw_ms03_init();
ambient_light_auto_fetch(); // ci_03t_init();
apds_9960_init();
apds_9960_auto_fetch();
auto_fetch_temperature(); auto_fetch_temperature();
init_ui(); pca9555_init();
xTaskCreate(publish_ui_input, "ui_input_event", 2048, NULL, 10, NULL); ui_input_init();
xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10,
NULL);
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
light_play(light_mode_connection_wifi); light_play(light_mode_connection_wifi);
if (connect_wifi()) { if (connect_wifi()) {

View File

@@ -3,6 +3,8 @@
#include <string.h> #include <string.h>
#include "cJSON.h" #include "cJSON.h"
#include "ci_03t.c"
#include "embedded_display.c"
#include "esp_bit_defs.h" #include "esp_bit_defs.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
@@ -13,7 +15,7 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "mqtt_client.h" #include "mqtt_client.h"
#include "ui.c" #include "ui_input.c"
#define MQTT_BROKER_URL CONFIG_MQTT_BROKER_URL #define MQTT_BROKER_URL CONFIG_MQTT_BROKER_URL
#define NUMBER_OF_LEDS CONFIG_NUMBER_OF_LEDS #define NUMBER_OF_LEDS CONFIG_NUMBER_OF_LEDS
@@ -30,6 +32,7 @@
#define MQTT_DESKTOP_KEY_PREFIX "display-ambient-light/desktop/" #define MQTT_DESKTOP_KEY_PREFIX "display-ambient-light/desktop/"
#define MQTT_ONLINE_SUFFIX "online" #define MQTT_ONLINE_SUFFIX "online"
#define MQTT_COLORS_SUFFIX "colors" #define MQTT_COLORS_SUFFIX "colors"
#define MQTT_CMD_SUFFIX "cmd"
#define MQTT_ALL_SUFFIX "#" #define MQTT_ALL_SUFFIX "#"
#define MQTT_KEY_BOARD_ONLINE MQTT_BOARD_KEY_PREFIX MQTT_ONLINE_SUFFIX #define MQTT_KEY_BOARD_ONLINE MQTT_BOARD_KEY_PREFIX MQTT_ONLINE_SUFFIX
@@ -38,9 +41,16 @@
#define MQTT_KEY_DESKTOP_COLORS MQTT_DESKTOP_KEY_PREFIX MQTT_COLORS_SUFFIX #define MQTT_KEY_DESKTOP_COLORS MQTT_DESKTOP_KEY_PREFIX MQTT_COLORS_SUFFIX
#define MQTT_KEY_DESKTOP_ALL MQTT_DESKTOP_KEY_PREFIX MQTT_ALL_SUFFIX #define MQTT_KEY_DESKTOP_ALL MQTT_DESKTOP_KEY_PREFIX MQTT_ALL_SUFFIX
#define MQTT_KEY_BOARD_CMD MQTT_BOARD_KEY_PREFIX MQTT_CMD_SUFFIX
#define MQTT_KEY_DESKTOP_DISPLAY_0_BRIGHTNESS \
MQTT_DESKTOP_KEY_PREFIX "display0/brightness"
#define MQTT_KEY_DESKTOP_DISPLAY_1_BRIGHTNESS \
MQTT_DESKTOP_KEY_PREFIX "display1/brightness"
static const char *MQTT_TAG = "DisplayAmbientLight_MQTT"; static const char *MQTT_TAG = "DisplayAmbientLight_MQTT";
static EventGroupHandle_t s_mqtt_event_group; static EventGroupHandle_t s_mqtt_event_group;
static xQueueHandle mqtt_cmd_event = NULL;
static esp_mqtt_client_handle_t client = NULL; static esp_mqtt_client_handle_t client = NULL;
typedef struct colors { typedef struct colors {
@@ -100,8 +110,24 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
xEventGroupSetBits(s_mqtt_event_group, xEventGroupSetBits(s_mqtt_event_group,
MQTT_DESKTOP_SENDING_BIT | MQTT_COLORS_STAND_BY_BIT); MQTT_DESKTOP_SENDING_BIT | MQTT_COLORS_STAND_BY_BIT);
} else { } else {
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); if (strncmp(event->topic, MQTT_KEY_DESKTOP_DISPLAY_0_BRIGHTNESS,
printf("DATA=%.*s\r\n", event->data_len, event->data); event->topic_len) == 0) {
s_ui_input_t mqtt_event = {
.key = ui_input_key_display_0_brightness,
.value = (uint16_t)(event->data[0] << 8 | event->data[1]),
};
xQueueSend(mqtt_cmd_event, &mqtt_event, NULL);
} else if (strncmp(event->topic, MQTT_KEY_DESKTOP_DISPLAY_1_BRIGHTNESS,
event->topic_len) == 0) {
s_ui_input_t mqtt_event = {
.key = ui_input_key_display_1_brightness,
.value = (uint16_t)(event->data[0] << 8 | event->data[1]),
};
xQueueSend(mqtt_cmd_event, &mqtt_event, NULL);
} else {
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
}
} }
break; break;
case MQTT_EVENT_ERROR: case MQTT_EVENT_ERROR:
@@ -124,9 +150,42 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
} }
} }
static void mqtt_cmd_event_handler(void *arg) {
s_ui_input_t event;
for (;;) {
if (xQueueReceive(mqtt_cmd_event, &event, portMAX_DELAY)) {
ESP_LOGI(MQTT_TAG, "mqtt_cmd_event_handler");
gui_update_config_uint8(ui_input_key_display_0_brightness,
(uint8_t)(event.value & 0xFF));
switch (event.key) {
case ui_input_key_display_0_brightness: {
ESP_LOGI(MQTT_TAG, "ui_input_key_display_0_brightness %x",
event.value);
uint8_t data[] = {0x02, (uint8_t)(event.value & 0xFF)};
ci_03t_send_data(data, sizeof(data));
break;
}
case ui_input_key_display_1_brightness: {
ESP_LOGI(MQTT_TAG, "ui_input_key_display_0_brightness %x",
event.value);
uint8_t data[] = {0x03, (uint8_t)(event.value & 0xFF)};
ci_03t_send_data(data, sizeof(data));
break;
}
default:
break;
}
}
}
}
static void mqtt_app_start() { static void mqtt_app_start() {
mqtt_colors_buffer = (uint8_t *)malloc(sizeof(uint8_t) * NUMBER_OF_LEDS * 3); mqtt_colors_buffer = (uint8_t *)malloc(sizeof(uint8_t) * NUMBER_OF_LEDS * 3);
s_mqtt_event_group = xEventGroupCreate(); s_mqtt_event_group = xEventGroupCreate();
mqtt_cmd_event = xQueueCreate(10, sizeof(s_ui_input_t));
xTaskCreate(mqtt_cmd_event_handler, "mqtt_cmd_event", 2048, NULL, 10, NULL);
const esp_mqtt_client_config_t mqtt_cfg = { const esp_mqtt_client_config_t mqtt_cfg = {
.uri = MQTT_BROKER_URL, .uri = MQTT_BROKER_URL,
@@ -193,21 +252,21 @@ static bool waiting_and_get_colors() {
} }
} }
static void publish_ui_input(void *arg) { static void mqtt_publish_ui_input(void *arg) {
s_ui_input_t input; s_ui_input_t input;
for (;;) { for (;;) {
if (xQueueReceive(ui_input_event, &input, portMAX_DELAY)) { if (xQueueReceive(ui_input_event, &input, portMAX_DELAY)) {
switch (input.key) { switch (input.key) {
case UI_INPUT_DISPLAY_0_BRIGHTNESS: case ui_input_key_display_0_brightness:
case UI_INPUT_DISPLAY_1_BRIGHTNESS: { case ui_input_key_display_1_brightness: {
cJSON *publish_json_root, *brightness; cJSON *publish_json_root, *brightness;
publish_json_root = cJSON_CreateObject(); publish_json_root = cJSON_CreateObject();
cJSON_AddNumberToObject( cJSON_AddNumberToObject(
publish_json_root, "display_index", publish_json_root, "display_index",
UI_INPUT_DISPLAY_0_BRIGHTNESS == input.key ? 0 : 1); ui_input_key_display_0_brightness == input.key ? 0 : 1);
cJSON_AddItemToObject(publish_json_root, "brightness", cJSON_AddItemToObject(publish_json_root, "brightness",
brightness = cJSON_CreateObject()); brightness = cJSON_CreateObject());
cJSON_AddNumberToObject(brightness, "Absolute", input.value); cJSON_AddNumberToObject(brightness, "Relative", input.value);
char *publish_str = cJSON_Print(publish_json_root); char *publish_str = cJSON_Print(publish_json_root);
cJSON_Delete(publish_json_root); cJSON_Delete(publish_json_root);
esp_mqtt_client_publish(client, MQTT_KEY_DISPLAY_BRIGHTNESS_INPUT, esp_mqtt_client_publish(client, MQTT_KEY_DISPLAY_BRIGHTNESS_INPUT,

112
main/pca9555.c Normal file
View File

@@ -0,0 +1,112 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include "driver/i2c.h"
#include "embedded_display.c"
#include "esp_log.h"
#include "i2c.c"
#define PCA_9555_TAG "PCA9555"
// Register of command byte
#define PCA95555_CMD_INPUT_PORT_0 0x00
#define PCA95555_CMD_INPUT_PORT_1 0x01
#define PCA95555_CMD_OUTPUT_PORT_0 0x02
#define PCA95555_CMD_OUTPUT_PORT_1 0x03
#define PCA95555_CMD_POLARITY_INVERSION_PORT_0 0x04
#define PCA95555_CMD_POLARITY_INVERSION_PORT_1 0x05
#define PCA95555_CMD_CONFIGURATION_PORT_0 0x06
#define PCA95555_CMD_CONFIGURATION_PORT_1 0x07
esp_err_t pca9555_write_config(uint8_t cmd_byte, uint8_t data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, PCA9555_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, cmd_byte, ACK_CHECK_EN);
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(PCA_9555_TAG, "write config failed. %d", error);
}
return error;
}
esp_err_t pca9555_write_output(uint8_t cmd_byte, uint8_t data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, PCA9555_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, cmd_byte, ACK_CHECK_EN);
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(PCA_9555_TAG, "write output failed. %d", error);
}
return error;
}
esp_err_t pca9555_read_one_input(uint8_t cmd_byte, uint8_t* data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, PCA9555_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN);
i2c_master_write_byte(cmd, cmd_byte, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, PCA9555_ADDRESS << 1 | I2C_MASTER_READ,
ACK_CHECK_EN);
i2c_master_read_byte(cmd, data, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t error =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (error != ESP_OK) {
ESP_LOGW(PCA_9555_TAG, "read input failed. %d", error);
}
return error;
}
void pca9555_fetch(void* arg) {
ESP_LOGI(PCA_9555_TAG, "fetching");
esp_err_t error;
uint8_t buff;
char disp_str[17];
display_fill_rect(0, 6, 128, 8, 0x00);
for (;;) {
error = pca9555_read_one_input(PCA95555_CMD_INPUT_PORT_1, &buff);
if (error != ESP_OK) {
ESP_LOGW(PCA_9555_TAG, "read failed. %x", error);
} else {
sprintf(disp_str, "IO0: 0x%2x ", buff);
display_print8_str(8, 6, disp_str);
ESP_LOGD(PCA_9555_TAG, "IO0: 0x%2x", buff);
}
vTaskDelay(pdMS_TO_TICKS(10));
}
display_fill_rect(0, 6, 128, 8, 0x00);
}
void pca9555_auto_fetch() {
if (is_apds_9930_online == 0) {
return;
}
xTaskCreate(pca9555_fetch, "pac05555-fetching", 2048, NULL, 10, NULL);
}
void pca9555_init() {
if (is_pca9555_online == 0) {
ESP_LOGE(PCA_9555_TAG, "salve offline");
return;
}
ESP_LOGI(PCA_9555_TAG, "Initializing PCA9555");
esp_log_level_set(PCA_9555_TAG, ESP_LOG_DEBUG);
pca9555_write_config(PCA95555_CMD_CONFIGURATION_PORT_1, 0x12);
}

View File

@@ -4,23 +4,21 @@
#include "driver/i2c.h" #include "driver/i2c.h"
#include "embedded_display.c" #include "embedded_display.c"
#include "esp_log.h" #include "esp_log.h"
#include "i2c.c"
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */ #define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */ #define NACK_VAL 0x1 /*!< I2C nack value */
#define I2C_MASTER_NUM CONFIG_I2C_NUM
#define GX21M15_ADDRESS 0x90
#define GX21M15_TEMP_POINTER_VALUE 0b00 // 温度寄存器 #define GX21M15_TEMP_POINTER_VALUE 0b00 // 温度寄存器
#define GX21M15_CONF_POINTER_VALUE 0b01 // 配置寄存器 #define GX21M15_CONF_POINTER_VALUE 0b01 // 配置寄存器
#define GX21M15_THYST_POINTER_VALUE 0b10 // 回滞寄存器 #define GX21M15_THYST_POINTER_VALUE 0b10 // 回滞寄存器
#define GX21M15_TOS_POINTER_VALUE 0b11 // 过温关断寄存器 #define GX21M15_TOS_POINTER_VALUE 0b11 // 过温关断寄存器
#define DEFAULT_TEMPERATURE -999 // 过温关断寄存器 #define DEFAULT_TEMPERATURE -999 // 过温关断寄存器
#define TEMPERATURE_TAG "temperature" #define TEMPERATURE_TAG "temperature"
void fetch_temperature(void* arg) { void fetch_temperature(void* arg) {
esp_err_t error; esp_err_t error;
float temperature = DEFAULT_TEMPERATURE; float temperature = DEFAULT_TEMPERATURE;
@@ -30,11 +28,11 @@ void fetch_temperature(void* arg) {
for (;;) { for (;;) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd); i2c_master_start(cmd);
i2c_master_write_byte(cmd, GX21M15_ADDRESS | I2C_MASTER_WRITE, i2c_master_write_byte(cmd, GX21M15_ADDRESS << 1 | I2C_MASTER_WRITE,
ACK_CHECK_EN); ACK_CHECK_EN);
i2c_master_write_byte(cmd, 0, ACK_CHECK_EN); i2c_master_write_byte(cmd, 0, ACK_CHECK_EN);
i2c_master_start(cmd); i2c_master_start(cmd);
i2c_master_write_byte(cmd, GX21M15_ADDRESS | I2C_MASTER_READ, ACK_VAL); i2c_master_write_byte(cmd, GX21M15_ADDRESS << 1 | I2C_MASTER_READ, ACK_VAL);
i2c_master_read_byte(cmd, &(temperature_buffer[0]), ACK_VAL); i2c_master_read_byte(cmd, &(temperature_buffer[0]), ACK_VAL);
i2c_master_read_byte(cmd, &(temperature_buffer[1]), NACK_VAL); i2c_master_read_byte(cmd, &(temperature_buffer[1]), NACK_VAL);
i2c_master_stop(cmd); i2c_master_stop(cmd);
@@ -64,11 +62,16 @@ void fetch_temperature(void* arg) {
} }
display_print8_str(8, 0, temperature_str); display_print8_str(8, 0, temperature_str);
} }
vTaskDelay(pdMS_TO_TICKS(500)); vTaskDelay(pdMS_TO_TICKS(2000));
} }
display_fill_rect(0, 0, 128, 2, 0x00); display_fill_rect(0, 0, 128, 2, 0x00);
} }
void auto_fetch_temperature() { void auto_fetch_temperature() {
xTaskCreate(fetch_temperature, "ui_input_event", 2048, NULL, 10, NULL); if (is_temperature_online == 0) {
ESP_LOGW(TEMPERATURE_TAG, "temperature is offline");
return;
}
ESP_LOGI(TEMPERATURE_TAG, "auto_fetch_temperature");
xTaskCreate(fetch_temperature, "temperature", 2048, NULL, 10, NULL);
} }

156
main/ui.c
View File

@@ -1,156 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#define GPIO_OUTPUT_IO_0 5
#define GPIO_OUTPUT_IO_1 6
#define GPIO_OUTPUT_PIN_SEL \
((1ULL << GPIO_OUTPUT_IO_0) | (1ULL << GPIO_OUTPUT_IO_1))
#define ENCODER_0_CLK_PIN CONFIG_ENCODER_0_CLK_PIN
#define ENCODER_0_DT_PIN CONFIG_ENCODER_0_DT_PIN
#define ENCODER_0_CLK_PIN_MASK 1ULL << ENCODER_0_CLK_PIN
#define ENCODER_0_DT_PIN_MASK 1ULL << ENCODER_0_DT_PIN
#define ENCODER_1_CLK_PIN CONFIG_ENCODER_1_CLK_PIN
#define ENCODER_1_DT_PIN CONFIG_ENCODER_1_DT_PIN
#define ENCODER_1_CLK_PIN_MASK 1ULL << ENCODER_1_CLK_PIN
#define ENCODER_1_DT_PIN_MASK 1ULL << ENCODER_1_DT_PIN
#define ESP_INTR_FLAG_DEFAULT 0
#define NOT_ROTATING -1
#define CLOCKWISE 1
#define COUNTER_CLOCKWISE 0
#define UI_INPUT_DISPLAY_0_BRIGHTNESS 1
#define UI_INPUT_DISPLAY_1_BRIGHTNESS 2
typedef struct s_ui_input {
uint8_t key;
uint16_t value;
} s_ui_input_t;
static xQueueHandle ui_input_event = NULL;
static int8_t rising_edge_rotation_direction = NOT_ROTATING;
static int8_t falling_edge_rotation_direction = NOT_ROTATING;
static uint8_t display_0_brightness = 20;
static uint8_t display_1_brightness = 20;
static s_ui_input_t current_ui_input = {};
uint8_t input_key;
uint8_t clk_pin = ENCODER_0_CLK_PIN;
uint8_t dt_level;
uint8_t dt_pin = ENCODER_0_DT_PIN;
uint8_t* value = &display_0_brightness;
static void IRAM_ATTR gpio_isr_handler(void* arg) {
uint8_t input_key = (uint8_t)arg;
switch (input_key) {
case UI_INPUT_DISPLAY_0_BRIGHTNESS:
clk_pin = ENCODER_0_CLK_PIN;
dt_pin = ENCODER_0_DT_PIN;
value = &display_0_brightness;
break;
case UI_INPUT_DISPLAY_1_BRIGHTNESS:
clk_pin = ENCODER_1_CLK_PIN;
dt_pin = ENCODER_1_DT_PIN;
value = &display_1_brightness;
break;
default:
break;
}
dt_level = gpio_get_level(dt_pin);
if (gpio_get_level(clk_pin)) {
rising_edge_rotation_direction = dt_level == 0;
if (falling_edge_rotation_direction == rising_edge_rotation_direction) {
if (rising_edge_rotation_direction) {
gpio_set_level(GPIO_OUTPUT_IO_0, 1);
gpio_set_level(GPIO_OUTPUT_IO_1, 0);
*value += 1;
} else {
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
gpio_set_level(GPIO_OUTPUT_IO_1, 1);
*value -= 1;
}
falling_edge_rotation_direction = NOT_ROTATING;
current_ui_input.key = input_key;
current_ui_input.value = *value;
xQueueSendFromISR(ui_input_event, &current_ui_input, NULL);
} else {
if (falling_edge_rotation_direction != NOT_ROTATING) {
rising_edge_rotation_direction = NOT_ROTATING;
}
}
} else {
falling_edge_rotation_direction = dt_level;
// printf("F %d\t", falling_edge_rotation_direction);
if (rising_edge_rotation_direction == falling_edge_rotation_direction) {
if (falling_edge_rotation_direction) {
gpio_set_level(GPIO_OUTPUT_IO_0, 1);
gpio_set_level(GPIO_OUTPUT_IO_1, 0);
*value += 1;
} else {
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
gpio_set_level(GPIO_OUTPUT_IO_1, 1);
*value -= 1;
}
rising_edge_rotation_direction = NOT_ROTATING;
current_ui_input.key = input_key;
current_ui_input.value = *value;
xQueueSendFromISR(ui_input_event, &current_ui_input, NULL);
} else {
if (rising_edge_rotation_direction != NOT_ROTATING) {
falling_edge_rotation_direction = NOT_ROTATING;
}
}
}
}
void init_ui(void) {
// zero-initialize the config structure.
gpio_config_t io_conf = {};
// disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;
// set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
// bit mask of the pins that you want to set,e.g.GPIO18/19
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
// disable pull-down mode
io_conf.pull_down_en = 0;
// disable pull-up mode
io_conf.pull_up_en = 0;
// configure GPIO with the given settings
gpio_config(&io_conf);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;
// interrupt of rising edge
io_conf.intr_type = GPIO_INTR_ANYEDGE;
io_conf.pin_bit_mask = ENCODER_0_CLK_PIN_MASK | ENCODER_1_CLK_PIN_MASK;
gpio_config(&io_conf);
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pin_bit_mask = ENCODER_0_DT_PIN_MASK | ENCODER_1_DT_PIN_MASK;
gpio_config(&io_conf);
// start encoder task
ui_input_event = xQueueCreate(10, sizeof(s_ui_input_t));
// install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
// hook isr handler for specific gpio pin
gpio_isr_handler_add(ENCODER_0_CLK_PIN, gpio_isr_handler,
(void*)UI_INPUT_DISPLAY_0_BRIGHTNESS);
// hook isr handler for specific gpio pin
gpio_isr_handler_add(ENCODER_1_CLK_PIN, gpio_isr_handler,
(void*)UI_INPUT_DISPLAY_1_BRIGHTNESS);
}

205
main/ui_input.c Normal file
View File

@@ -0,0 +1,205 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config_key.h"
#include "driver/gpio.h"
#include "embedded_display.c"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "light.c"
#include "pca9555.c"
#define ENCODER_0_CLK_PORT_IO CONFIG_ENCODER_0_CLK_PORT_IO
#define ENCODER_0_DT_PORT_IO CONFIG_ENCODER_0_DT_PORT_IO
#define ENCODER_0_SW_PORT_IO CONFIG_ENCODER_0_SW_PORT_IO
#define ENCODER_1_CLK_PORT_IO CONFIG_ENCODER_1_CLK_PORT_IO
#define ENCODER_1_DT_PORT_IO CONFIG_ENCODER_1_DT_PORT_IO
#define ENCODER_1_SW_PORT_IO CONFIG_ENCODER_1_SW_PORT_IO
#define ENCODER_INT_GPIO GPIO_NUM_3
#define ESP_INTR_FLAG_DEFAULT 0
#define RISING_EDGE_NOT_ROTATING 0b00000000
#define RISING_EDGE_CLOCKWISE 0b10000000
#define RISING_EDGE_COUNTER_CLOCKWISE 0b11000000
#define RISING_EDGE_ROTATING_MASK 0b11000000
#define FALLING_EDGE_NOT_ROTATING 0b00000000
#define FALLING_EDGE_CLOCKWISE 0b00100000
#define FALLING_EDGE_COUNTER_CLOCKWISE 0b00110000
#define FALLING_EDGE_ROTATING_MASK 0b00110000
static const char *UI_INPUT_TAG = "UiInput";
static xQueueHandle ui_input_event = NULL;
static xQueueHandle ui_input_raw_event = NULL;
typedef struct encoder_state {
e_ui_input_raw_key_t key;
uint8_t bits; // rising_edge_rotation_direction,
// falling_edge_rotation_direction, dt, clk, sw
uint8_t value; // dt, clk, sw
} encoder_state_t;
static encoder_state_t encoder_0_state = {.key = ui_input_raw_key_encoder_0,
.bits = 0};
static encoder_state_t encoder_1_state = {.key = ui_input_raw_key_encoder_1,
.bits = 0};
uint8_t level_byte;
int8_t delta = 0;
char changing_str[12] = "NC";
static void IRAM_ATTR gpio_isr_handler(void *arg) {
xQueueSendFromISR(ui_input_raw_event, NULL, NULL);
}
static void ui_input_update_embedded_display(void *arg) {
s_ui_input_t input;
char changing_str[12] = "NC";
for (;;) {
if (xQueueReceive(ui_input_event, &input, portMAX_DELAY)) {
switch (input.key) {
case ui_input_key_display_0_brightness:
sprintf(changing_str, "Dis0: % 3d", input.value);
break;
case ui_input_key_display_1_brightness:
sprintf(changing_str, "Dis1: % 3d", input.value);
break;
case ui_input_key_computer_volume:
sprintf(changing_str, "CVol: % 3d", input.value);
break;
case ui_input_key_display_ambient_lighting_level:
sprintf(changing_str, "ALLv: % 3d", display_ambient_lighting_level);
break;
case ui_input_key_display_ambient_lighting_mode:
sprintf(changing_str, "ALMd: % 3d", input.value);
break;
case ui_input_key_display_0_mode:
sprintf(changing_str, "Dis0M: % 2d", input.value);
break;
case ui_input_key_display_1_mode:
sprintf(changing_str, "Dis1M: % 2d", input.value);
break;
default:
strcpy(changing_str, "NC");
break;
}
display_fill_rect(0, 6, 128, 8, 0);
display_print8_str(8, 6, changing_str);
}
}
}
static void encoder_value_change(encoder_state_t *state) {
if ((state->value >> 1 & 1) == (state->bits >> 1 & 1)) {
return;
}
state->bits = (state->bits & 0b11111000) | (state->value & 0b111);
if (state->value >> 1 & 1) {
state->bits = (state->bits & (~RISING_EDGE_ROTATING_MASK)) | 0x80 |
~(state->value >> 2 & 1) << 6;
if (((state->bits & FALLING_EDGE_ROTATING_MASK) >> 4) ==
((state->bits & RISING_EDGE_ROTATING_MASK) >> 6)) {
if ((state->bits & RISING_EDGE_ROTATING_MASK) == RISING_EDGE_CLOCKWISE) {
delta = -1;
} else {
delta = 1;
}
state->bits = (state->bits & (~FALLING_EDGE_ROTATING_MASK)) |
FALLING_EDGE_NOT_ROTATING;
} else {
delta = 0;
if ((state->bits & FALLING_EDGE_ROTATING_MASK) !=
FALLING_EDGE_NOT_ROTATING) {
state->bits = (state->bits & (~FALLING_EDGE_ROTATING_MASK)) |
FALLING_EDGE_NOT_ROTATING;
}
}
} else {
state->bits = (state->bits & (~FALLING_EDGE_ROTATING_MASK)) | 0x20 |
(state->value >> 2 & 1) << 4;
if (((state->bits & FALLING_EDGE_ROTATING_MASK) >> 4) ==
((state->bits & RISING_EDGE_ROTATING_MASK) >> 6)) {
if ((state->bits & FALLING_EDGE_ROTATING_MASK) ==
FALLING_EDGE_CLOCKWISE) {
delta = -1;
} else {
delta = 1;
}
state->bits = (state->bits & (~RISING_EDGE_ROTATING_MASK)) |
RISING_EDGE_NOT_ROTATING;
} else {
delta = 0;
if ((state->bits & RISING_EDGE_ROTATING_MASK) !=
RISING_EDGE_NOT_ROTATING) {
state->bits = (state->bits & (~RISING_EDGE_ROTATING_MASK)) |
RISING_EDGE_NOT_ROTATING;
}
}
}
if (delta == 0) {
return;
}
s_ui_input_t event = {.value = delta};
if (state->key == ui_input_raw_key_encoder_0) {
if (state->value & 1) {
event.key = ui_input_key_computer_volume;
} else {
event.key = ui_input_key_display_0_brightness;
}
} else if (state->key == ui_input_raw_key_encoder_1) {
if (state->value & 1) {
event.key = ui_input_key_display_ambient_lighting_level;
led_strip_set_brightness(display_ambient_lighting_level + delta);
} else {
event.key = ui_input_key_display_1_brightness;
}
}
xQueueSend(ui_input_event, &event, NULL);
}
static void ui_input_raw_handler(void *arg) {
for (;;) {
if (xQueueReceive(ui_input_raw_event, NULL, portMAX_DELAY)) {
pca9555_read_one_input(PCA95555_CMD_INPUT_PORT_1, &level_byte);
encoder_0_state.value = level_byte & 0x7;
encoder_value_change(&encoder_0_state);
encoder_1_state.value = level_byte >> 3 & 0x7;
encoder_value_change(&encoder_1_state);
}
}
}
void ui_input_init(void) {
// zero-initialize the config structure.
gpio_config_t io_conf = {};
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;
// interrupt of rising edge
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.pin_bit_mask = 1ULL << ENCODER_INT_GPIO;
gpio_config(&io_conf);
// start encoder task
ui_input_event = xQueueCreate(10, sizeof(s_ui_input_t));
ui_input_raw_event = xQueueCreate(10, 0);
// hook isr handler for specific gpio pin
gpio_isr_handler_add(ENCODER_INT_GPIO, gpio_isr_handler, NULL);
xTaskCreate(ui_input_update_embedded_display, "ui_input_event", 2048, NULL,
10, NULL);
xTaskCreate(ui_input_raw_handler, "ui_input_event", 2048, NULL, 10, NULL);
}