commit
92270c796d
7 changed files with 278 additions and 0 deletions
-
9.clang-format
-
1.gitignore
-
2README.md
-
1build.sh
-
1install.sh
-
199spisound.c
-
65spisound.h
@ -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 |
@ -0,0 +1 @@ |
|||||
|
libspisound.so |
@ -0,0 +1,2 @@ |
|||||
|
# linux_demo_project |
||||
|
|
@ -0,0 +1 @@ |
|||||
|
gcc -shared -fPIC spisound.c -o libspisound.so |
@ -0,0 +1 @@ |
|||||
|
sudo cp libspisound.so /usr/lib/ |
@ -0,0 +1,199 @@ |
|||||
|
#include "spisound.h" |
||||
|
|
||||
|
#include <errno.h> |
||||
|
#include <fcntl.h> |
||||
|
#include <getopt.h> |
||||
|
#include <linux/spi/spidev.h> |
||||
|
#include <linux/types.h> |
||||
|
#include <pthread.h> |
||||
|
#include <stdbool.h> |
||||
|
#include <stdint.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> //for strerror() |
||||
|
#include <sys/ioctl.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
#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"); |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
#pragma once |
||||
|
#include <stdint.h> |
||||
|
|
||||
|
#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 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue