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/
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 ".")

View File

@@ -65,57 +65,57 @@ menu "MQTT Configuration"
endmenu
menu "Encoder Configuration"
config ENCODER_0_CLK_PIN
int "encoder 0 click GPIO"
range 1 32
config ENCODER_0_CLK_PORT_IO
int "encoder 0 clock IO"
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
help
Encoder 0 clock pin
config ENCODER_0_DT_PIN
int "encoder 0 data GPIO"
range 1 32
default 3
help
Encoder 0 clock data
config ENCODER_0_SW_PIN
int "encoder 0 switch GPIO"
range 1 32
config ENCODER_0_SW_PORT_IO
int "encoder 0 switch IO"
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
help
Encoder 0 switch pin
config ENCODER_1_CLK_PIN
int "encoder 1 click GPIO"
range 1 32
Encoder 1 clock io on PCA9555 port 1
config ENCODER_1_DT_PORT_IO
int "encoder 1 data IO"
range 0 7
default 5
help
Encoder 1 clock pin
config ENCODER_1_DT_PIN
int "encoder 1 data GPIO"
range 1 32
default 6
help
Encoder 1 clock data
config ENCODER_1_SW_PIN
int "encoder 1 switch GPIO"
range 1 32
default 7
config ENCODER_1_SW_PORT_IO
int "encoder 1 switch IO"
range 0 7
default 3
help
Encoder 1 switch pin
Encoder 1 switch io on PCA9555 port 1
endmenu
menu "I2C Configuration"
config I2C_SCL
int "I2C SCL GPIO"
range 1 32
default 8
range 0 32
default 5
help
I2C SCL GPIO
config I2C_SDA
int "I2C SDA GPIO"
range 1 32
default 10
range 0 32
default 4
help
I2C SDA GPIO
config I2C_NUM
@@ -124,4 +124,34 @@ menu "I2C Configuration"
default 0
help
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

View File

@@ -3,17 +3,8 @@
#include "driver/i2c.h"
#include "embedded_display.c"
#include "esp_log.h"
#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
#include "i2c.c"
#define APDS_9930_CMD_REPEATED 0x80 // 命令重复地址
#define APDS_9930_CMD_AUTO_INCREMENT 0x90 // 命令自动递增地址
@@ -24,7 +15,7 @@
#define APDS_9930_REG_PTIME 0x02 // Proximity ADC 时间 0xff
#define APDS_9930_REG_WTIME 0x03 // Wait 时间 0xff
#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_Ch0DATAH 0x15 // Ch0 ADC High 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) {
ESP_LOGI(AMBIENT_LIGHT_TAG, "ambient_light_fetch");
esp_err_t error;
uint16_t als_ch0_raw;
uint16_t als_ch1_raw;
@@ -164,30 +156,38 @@ void ambient_light_fetch(void* arg) {
als_ch0_raw);
}
// als ch1
error = apds_9930_read_word(
APDS_9930_CMD_AUTO_INCREMENT | APDS_9930_REG_Ch1DATAL,
&(als_ch1_buffer[1]), &(als_ch1_buffer[0]));
if (error != ESP_OK) {
ESP_LOGW(AMBIENT_LIGHT_TAG, "read failed. %x", error);
} else {
als_ch1_raw = als_ch1_buffer[0] << 8 | als_ch1_buffer[1];
sprintf(als_ch1_str, "Ch1: % 5d ", als_ch1_raw);
display_print8_str(8, 6, als_ch1_str);
ESP_LOGD(AMBIENT_LIGHT_TAG, "ALS Ch1: %d, %x", als_ch1_raw,
als_ch1_raw);
}
// error = apds_9930_read_word(
// APDS_9930_CMD_AUTO_INCREMENT | APDS_9930_REG_Ch1DATAL,
// &(als_ch1_buffer[1]), &(als_ch1_buffer[0]));
// if (error != ESP_OK) {
// ESP_LOGW(AMBIENT_LIGHT_TAG, "read failed. %x", error);
// } else {
// als_ch1_raw = als_ch1_buffer[0] << 8 | als_ch1_buffer[1];
// sprintf(als_ch1_str, "Ch1: % 5d ", als_ch1_raw);
// display_print8_str(8, 6, als_ch1_str);
// ESP_LOGD(AMBIENT_LIGHT_TAG, "ALS Ch1: %d, %x", als_ch1_raw,
// als_ch1_raw);
// }
vTaskDelay(pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(1000));
}
display_fill_rect(0, 2, 128, 8, 0x00);
}
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() {
// 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,
APDS_9930_ATIME_VALUE));
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "codetab.h"
#include "config_key.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "i2c.c"
#define Brightness 0xCF
#define X_WIDTH 128
#define Y_WIDTH 64
#define I2C_ADDRESS 0x78
#define I2C_MASTER_NUM CONFIG_I2C_NUM
void i2cWriteByte(uint8_t reg, uint8_t data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
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, data, true);
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[]) {
if (!is_embedded_display_online) {
return;
}
uint8_t c;
for (uint8_t ch, ci = 0; ch = str[ci], ch != '\0'; ci++, x += 8) {
c = ch - 0x20;
@@ -72,6 +75,11 @@ void display_print8_str(uint8_t x, uint8_t y, char str[]) {
}
void init_display() {
if (is_embedded_display_online == 0) {
ESP_LOGE("display", "display is offline");
return;
}
i2cWriteCommand(0xAE); // display off
i2cWriteCommand(0x00); // set lower column address
i2cWriteCommand(0x10); // set higher column address
@@ -101,4 +109,37 @@ void init_display() {
display_fill(0x00);
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
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "driver/rmt.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
@@ -27,10 +28,34 @@ typedef enum light_mode_e {
light_mode_mqtt_connected = 3,
light_mode_desktop_online = 4,
light_mode_desktop_sending_colors = 5,
light_mode_off = 6,
} light_mode_t;
led_strip_t *light_led_strip;
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
@@ -94,22 +119,22 @@ void update_desktop_connection_state() {
case light_mode_desktop_online:
if (beat) {
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(
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(
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;
case light_mode_mqtt_connected:
if (beat) {
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(
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(
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;
case light_mode_idle:
if (beat) {
@@ -145,6 +170,7 @@ void light_for_init() {
ESP_ERROR_CHECK(light_led_strip->refresh(light_led_strip, 100));
vTaskDelay(pdMS_TO_TICKS(10));
}
vTaskDelay(pdMS_TO_TICKS(100));
} 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;
j++, hue += step_length) {
// 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
ESP_ERROR_CHECK(
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;
led_index < STRIP_LED_NUMBER && buffer_cursor < len;
led_index++, buffer_cursor += 3) {
uint8_t r = buffer[buffer_cursor], g = buffer[buffer_cursor + 1],
b = buffer[buffer_cursor + 2];
uint8_t r = (uint8_t)((float)buffer[buffer_cursor] *
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(
light_led_strip->set_pixel(light_led_strip, led_index, r, g, b));
}

View File

@@ -1,56 +1,39 @@
#include "ambient_light.c"
#include "driver/i2c.h"
#include "apds_9960.c"
#include "ci_03t.c"
#include "embedded_display.c"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hw-ms03.c"
#include "i2c.c"
#include "light.c"
#include "mqtt.c"
#include "pca9555.c"
#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"
void init_i2c() {
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");
}
#include "ui_input.c"
#include "wifi.c"
static const char *TAG = "DisplayAmbientLight";
void app_main(void) {
light_init_strip();
gpio_install_isr_service(0);
init_i2c();
i2c_check_slaves();
init_display();
display_print8_str(0, 0, "Ambient Light");
ambient_light_init();
ambient_light_auto_fetch();
// hw_ms03_init();
// ci_03t_init();
apds_9960_init();
apds_9960_auto_fetch();
auto_fetch_temperature();
init_ui();
xTaskCreate(publish_ui_input, "ui_input_event", 2048, NULL, 10, NULL);
pca9555_init();
ui_input_init();
xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10,
NULL);
vTaskDelay(pdMS_TO_TICKS(10));
light_play(light_mode_connection_wifi);
if (connect_wifi()) {

View File

@@ -3,6 +3,8 @@
#include <string.h>
#include "cJSON.h"
#include "ci_03t.c"
#include "embedded_display.c"
#include "esp_bit_defs.h"
#include "esp_event.h"
#include "esp_log.h"
@@ -13,7 +15,7 @@
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "mqtt_client.h"
#include "ui.c"
#include "ui_input.c"
#define MQTT_BROKER_URL CONFIG_MQTT_BROKER_URL
#define NUMBER_OF_LEDS CONFIG_NUMBER_OF_LEDS
@@ -30,6 +32,7 @@
#define MQTT_DESKTOP_KEY_PREFIX "display-ambient-light/desktop/"
#define MQTT_ONLINE_SUFFIX "online"
#define MQTT_COLORS_SUFFIX "colors"
#define MQTT_CMD_SUFFIX "cmd"
#define MQTT_ALL_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_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 EventGroupHandle_t s_mqtt_event_group;
static xQueueHandle mqtt_cmd_event = NULL;
static esp_mqtt_client_handle_t client = NULL;
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,
MQTT_DESKTOP_SENDING_BIT | MQTT_COLORS_STAND_BY_BIT);
} else {
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
if (strncmp(event->topic, MQTT_KEY_DESKTOP_DISPLAY_0_BRIGHTNESS,
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;
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() {
mqtt_colors_buffer = (uint8_t *)malloc(sizeof(uint8_t) * NUMBER_OF_LEDS * 3);
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 = {
.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;
for (;;) {
if (xQueueReceive(ui_input_event, &input, portMAX_DELAY)) {
switch (input.key) {
case UI_INPUT_DISPLAY_0_BRIGHTNESS:
case UI_INPUT_DISPLAY_1_BRIGHTNESS: {
case ui_input_key_display_0_brightness:
case ui_input_key_display_1_brightness: {
cJSON *publish_json_root, *brightness;
publish_json_root = cJSON_CreateObject();
cJSON_AddNumberToObject(
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",
brightness = cJSON_CreateObject());
cJSON_AddNumberToObject(brightness, "Absolute", input.value);
cJSON_AddNumberToObject(brightness, "Relative", input.value);
char *publish_str = cJSON_Print(publish_json_root);
cJSON_Delete(publish_json_root);
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 "embedded_display.c"
#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 GX21M15_ADDRESS 0x90
#define GX21M15_TEMP_POINTER_VALUE 0b00 // 温度寄存器
#define GX21M15_CONF_POINTER_VALUE 0b01 // 配置寄存器
#define GX21M15_THYST_POINTER_VALUE 0b10 // 回滞寄存器
#define GX21M15_TOS_POINTER_VALUE 0b11 // 过温关断寄存器
#define DEFAULT_TEMPERATURE -999 // 过温关断寄存器
#define TEMPERATURE_TAG "temperature"
void fetch_temperature(void* arg) {
esp_err_t error;
float temperature = DEFAULT_TEMPERATURE;
@@ -30,11 +28,11 @@ void fetch_temperature(void* arg) {
for (;;) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
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);
i2c_master_write_byte(cmd, 0, ACK_CHECK_EN);
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[1]), NACK_VAL);
i2c_master_stop(cmd);
@@ -64,11 +62,16 @@ void fetch_temperature(void* arg) {
}
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);
}
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);
}