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