From 92270c796ddd8d601c975421c92f1ff85eef770d Mon Sep 17 00:00:00 2001 From: zhaohe Date: Sun, 2 Jul 2023 14:41:57 +0800 Subject: [PATCH] update --- .clang-format | 9 +++ .gitignore | 1 + README.md | 2 + build.sh | 1 + install.sh | 1 + spisound.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spisound.h | 65 +++++++++++++++++++ 7 files changed, 278 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 README.md create mode 100755 build.sh create mode 100755 install.sh create mode 100644 spisound.c create mode 100644 spisound.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..45866f9 --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 160 +AlignConsecutiveMacros: true +AlignConsecutiveDeclarations: true +AlignConsecutiveAssignments: true +AlignOperands: true \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..010090f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +libspisound.so \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1c76586 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# linux_demo_project + diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..f994ed1 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +gcc -shared -fPIC spisound.c -o libspisound.so \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..6f38cc8 --- /dev/null +++ b/install.sh @@ -0,0 +1 @@ +sudo cp libspisound.so /usr/lib/ \ No newline at end of file diff --git a/spisound.c b/spisound.c new file mode 100644 index 0000000..106147e --- /dev/null +++ b/spisound.c @@ -0,0 +1,199 @@ +#include "spisound.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //for strerror() +#include +#include + +#define MAX_ONE_FRAME_VOICE_SIZE 2000 + +#define IOCTL(vfd, vkey, vvalue, errorcode) \ + { \ + int ret = ioctl(vfd, vkey, &vvalue); \ + if (ret != 0) { \ + close(vfd); \ + vfd = -1; \ + m_sys_error = errno; \ + m_last_error = errorcode; \ + return errorcode; \ + } \ + } + +// static const char *m_deviceName = NULL; +static spisound_cb_t m_callback = NULL; +static int m_fd = 0; +static int m_sys_error = 0; +static error_code_t m_last_error = ksp_success; +static int m_cs_gpio_id = 0; + +static int m_gpiofd = 0; + +static pthread_t sound_read_thread; +static bool inited = false; +static bool started = false; + +static void *sound_read_thread_func(void *v); +static void gpio_set_value(int value) { write(m_gpiofd, value ? "1\n" : "0\n", 2); } +static void readvoice(); + +static int32_t *multiplierX2(int32_t *voice, int32_t size, int32_t *outsize) { + static int32_t voicebuf[MAX_ONE_FRAME_VOICE_SIZE * 2]; // 50ms + if (size > MAX_ONE_FRAME_VOICE_SIZE) { + size = MAX_ONE_FRAME_VOICE_SIZE; + } + + for (size_t i = 0; i < size; i++) { + voicebuf[i * 2] = voice[i]; + if (i + 1 < size) { + voicebuf[i * 2 + 1] = (voice[i] + voice[i + 1]) / 2; + } + } + *outsize = size * 2; + return voicebuf; +} + +static void filterVoice(int32_t *voice, int32_t size) { + /** + * @brief 简单的过滤器,如果当前点大于上一个点和下一个点的平均值的1.5倍,则将当前点设置为平均值 + */ + static int32_t lastvoice = 0; + lastvoice = voice[size - 1]; + + { // + int32_t avg = (lastvoice + voice[1]) / 2; + if (abs(voice[0]) > abs(avg * 1.5)) { + voice[0] = avg; + } + } + + for (size_t i = 1; i < size - 1; i++) { + int32_t avg = (voice[i - 1] + voice[i + 1]) / 2; + if (abs(voice[i]) > abs(avg * 1.5)) { + voice[i] = avg; + } + } + + { + int32_t expectendvoice = voice[size - 2] + (voice[size - 2] - voice[size - 3]); + if (abs(voice[size - 1]) > abs(expectendvoice * 1.5)) { + voice[size - 1] = expectendvoice; + } + } +} + +error_code_t spisound_init(const char *deviceName, int csgpionameId, spisound_cb_t callback) { + m_callback = callback; + m_cs_gpio_id = csgpionameId; + // + m_fd = open(deviceName, O_RDWR); + if (m_fd < 0) { + m_sys_error = errno; + m_last_error = ksp_init_spi_error_open_fail; + return ksp_init_spi_error_open_fail; + } + // 设置模式 + int mode = SPI_MODE_3; + int bits = 8; + int speed = 3000000; + + // SPI初始化 + IOCTL(m_fd, SPI_IOC_WR_MODE, mode, ksp_init_spi_error_set_mode_fail); + IOCTL(m_fd, SPI_IOC_WR_BITS_PER_WORD, bits, ksp_init_spi_error_set_mode_fail); + IOCTL(m_fd, SPI_IOC_WR_MAX_SPEED_HZ, speed, ksp_init_spi_error_set_mode_fail); + + char cmd[256] = {0}; + sprintf(cmd, "echo %d 1> /sys/class/gpio/export 2>/dev/null", m_cs_gpio_id); + system(cmd); + + sprintf(cmd, "echo out > /sys/class/gpio/gpio%d/direction", m_cs_gpio_id); + system(cmd); + + sprintf(cmd, "/sys/class/gpio/gpio%d/value", m_cs_gpio_id); + m_gpiofd = open(cmd, O_RDWR); + if (m_gpiofd < 0) { + m_sys_error = errno; + m_last_error = ksp_init_spi_cs_pin_open_fail; + return ksp_init_spi_cs_pin_open_fail; + } + inited = true; + return ksp_success; +} + +static void *sound_read_thread_func(void *v) { + while (true) { + // 一次系统调用时间大概500us + readvoice(); + usleep(10000); + } + return NULL; +} + +error_code_t spisound_start_capture(void) { + // + if (!inited) { + return ksp_module_not_inited; + } + + if (started) { + return ksp_module_has_started; + } + + int ret = pthread_create(&sound_read_thread, NULL, sound_read_thread_func, NULL); + if (ret != 0) { + m_sys_error = errno; + return ksp_create_thread_fail; + } + + started = true; + return ksp_success; +} + +static void readvoice() { + static int32_t voicebuf[MAX_ONE_FRAME_VOICE_SIZE]; // 50ms + static int32_t rxdatabytesize; // + + rxdatabytesize = 0; + memset(voicebuf, 0, sizeof(voicebuf)); + + gpio_set_value(0); + // usleep(1500); // CS信号触发后,给单片机足够的时间准备音频数据 + int ret = read(m_fd, &rxdatabytesize, 4); + // printf("read rxdatabytesize:%d\n", rxdatabytesize); + if (rxdatabytesize <= 0) { + gpio_set_value(1); + return; + } + if (rxdatabytesize > MAX_ONE_FRAME_VOICE_SIZE * 4) { + printf("WARNING: rxdatabytesize(%d) > voiceBufSize \n", rxdatabytesize); + gpio_set_value(1); + return; + } + + ret = read(m_fd, voicebuf, rxdatabytesize); + gpio_set_value(1); + + { + int32_t voiceframesize = 0; + filterVoice(voicebuf, rxdatabytesize / 4); + int32_t *voicereport = multiplierX2(voicebuf, rxdatabytesize / 4, &voiceframesize); + if (m_callback) m_callback(voicereport, voiceframesize); + } + + return; +} + +void spisound_dump_last_error() { + printf("----------------spisound_dump_last_error-----------------\n"); + printf("- module error: %s(%d)\n", error_code_to_string(m_last_error), m_last_error); + printf("- sys_ error : %s(%d)\n", strerror(m_sys_error), m_sys_error); + printf("-\n"); +} diff --git a/spisound.h b/spisound.h new file mode 100644 index 0000000..d4790fc --- /dev/null +++ b/spisound.h @@ -0,0 +1,65 @@ +#pragma once +#include + +#ifdef cplusplus +extern "C" { +#endif +/** + * @brief 上报48k音频数据32位音频数据 + * + * @param data 音频数据 + * @param len 音频数据长度 + * + */ +typedef void (*spisound_cb_t)(int32_t *data, uint32_t len); + +typedef enum { + ksp_success, + ksp_module_not_inited, + ksp_module_has_started, + ksp_create_thread_fail, + ksp_init_spi_cs_pin_open_fail, + ksp_init_spi_error_open_fail, + ksp_init_spi_error_set_speed_fail, + ksp_init_spi_error_set_nbits_fail, + ksp_init_spi_error_set_mode_fail, +} error_code_t; + +static inline const char *error_code_to_string(error_code_t code) { + switch (code) { + case ksp_success: + return "success"; + case ksp_module_not_inited: + return "module not inited"; + case ksp_module_has_started: + return "module has started"; + case ksp_create_thread_fail: + return "create thread fail"; + case ksp_init_spi_cs_pin_open_fail: + return "init spi cs pin open fail"; + case ksp_init_spi_error_open_fail: + return "init spi error open fail"; + case ksp_init_spi_error_set_speed_fail: + return "init spi error set speed fail"; + case ksp_init_spi_error_set_nbits_fail: + return "init spi error set nbits fail"; + case ksp_init_spi_error_set_mode_fail: + return "init spi error set mode fail"; + default: + return "unknown error"; + } +} + +/** + * @brief 初始化声音采集模块 + * + * @param deviceName + * @param callback + */ +error_code_t spisound_init(const char *deviceName, int csgpionId, spisound_cb_t callback); +error_code_t spisound_start_capture(void); + +void spisound_dump_last_error(); +#ifdef cplusplus +} +#endif