You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.4 KiB

2 years ago
  1. #include "spisound.h"
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <getopt.h>
  5. #include <linux/spi/spidev.h>
  6. #include <linux/types.h>
  7. #include <pthread.h>
  8. #include <stdbool.h>
  9. #include <stdint.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h> //for strerror()
  13. #include <sys/ioctl.h>
  14. #include <unistd.h>
  15. #define MAX_ONE_FRAME_VOICE_SIZE 2000
  16. #define IOCTL(vfd, vkey, vvalue, errorcode) \
  17. { \
  18. int ret = ioctl(vfd, vkey, &vvalue); \
  19. if (ret != 0) { \
  20. close(vfd); \
  21. vfd = -1; \
  22. m_sys_error = errno; \
  23. m_last_error = errorcode; \
  24. return errorcode; \
  25. } \
  26. }
  27. // static const char *m_deviceName = NULL;
  28. static spisound_cb_t m_callback = NULL;
  29. static int m_fd = 0;
  30. static int m_sys_error = 0;
  31. static error_code_t m_last_error = ksp_success;
  32. static int m_cs_gpio_id = 0;
  33. static int m_gpiofd = 0;
  34. static pthread_t sound_read_thread;
  35. static bool inited = false;
  36. static bool started = false;
  37. static void *sound_read_thread_func(void *v);
  38. static void gpio_set_value(int value) { write(m_gpiofd, value ? "1\n" : "0\n", 2); }
  39. static void readvoice();
  40. static int32_t *multiplierX2(int32_t *voice, int32_t size, int32_t *outsize) {
  41. static int32_t voicebuf[MAX_ONE_FRAME_VOICE_SIZE * 2]; // 50ms
  42. if (size > MAX_ONE_FRAME_VOICE_SIZE) {
  43. size = MAX_ONE_FRAME_VOICE_SIZE;
  44. }
  45. for (size_t i = 0; i < size; i++) {
  46. voicebuf[i * 2] = voice[i];
  47. if (i + 1 < size) {
  48. voicebuf[i * 2 + 1] = (voice[i] + voice[i + 1]) / 2;
  49. }
  50. }
  51. *outsize = size * 2;
  52. return voicebuf;
  53. }
  54. static void filterVoice(int32_t *voice, int32_t size) {
  55. /**
  56. * @brief 1.5
  57. */
  58. static int32_t lastvoice = 0;
  59. lastvoice = voice[size - 1];
  60. { //
  61. int32_t avg = (lastvoice + voice[1]) / 2;
  62. if (abs(voice[0]) > abs(avg * 1.5)) {
  63. voice[0] = avg;
  64. }
  65. }
  66. for (size_t i = 1; i < size - 1; i++) {
  67. int32_t avg = (voice[i - 1] + voice[i + 1]) / 2;
  68. if (abs(voice[i]) > abs(avg * 1.5)) {
  69. voice[i] = avg;
  70. }
  71. }
  72. {
  73. int32_t expectendvoice = voice[size - 2] + (voice[size - 2] - voice[size - 3]);
  74. if (abs(voice[size - 1]) > abs(expectendvoice * 1.5)) {
  75. voice[size - 1] = expectendvoice;
  76. }
  77. }
  78. }
  79. error_code_t spisound_init(const char *deviceName, int csgpionameId, spisound_cb_t callback) {
  80. m_callback = callback;
  81. m_cs_gpio_id = csgpionameId;
  82. //
  83. m_fd = open(deviceName, O_RDWR);
  84. if (m_fd < 0) {
  85. m_sys_error = errno;
  86. m_last_error = ksp_init_spi_error_open_fail;
  87. return ksp_init_spi_error_open_fail;
  88. }
  89. // 设置模式
  90. int mode = SPI_MODE_3;
  91. int bits = 8;
  92. int speed = 3000000;
  93. // SPI初始化
  94. IOCTL(m_fd, SPI_IOC_WR_MODE, mode, ksp_init_spi_error_set_mode_fail);
  95. IOCTL(m_fd, SPI_IOC_WR_BITS_PER_WORD, bits, ksp_init_spi_error_set_mode_fail);
  96. IOCTL(m_fd, SPI_IOC_WR_MAX_SPEED_HZ, speed, ksp_init_spi_error_set_mode_fail);
  97. char cmd[256] = {0};
  98. sprintf(cmd, "echo %d 1> /sys/class/gpio/export 2>/dev/null", m_cs_gpio_id);
  99. system(cmd);
  100. sprintf(cmd, "echo out > /sys/class/gpio/gpio%d/direction", m_cs_gpio_id);
  101. system(cmd);
  102. sprintf(cmd, "/sys/class/gpio/gpio%d/value", m_cs_gpio_id);
  103. m_gpiofd = open(cmd, O_RDWR);
  104. if (m_gpiofd < 0) {
  105. m_sys_error = errno;
  106. m_last_error = ksp_init_spi_cs_pin_open_fail;
  107. return ksp_init_spi_cs_pin_open_fail;
  108. }
  109. inited = true;
  110. return ksp_success;
  111. }
  112. static void *sound_read_thread_func(void *v) {
  113. while (true) {
  114. // 一次系统调用时间大概500us
  115. readvoice();
  116. usleep(10000);
  117. }
  118. return NULL;
  119. }
  120. error_code_t spisound_start_capture(void) {
  121. //
  122. if (!inited) {
  123. return ksp_module_not_inited;
  124. }
  125. if (started) {
  126. return ksp_module_has_started;
  127. }
  128. int ret = pthread_create(&sound_read_thread, NULL, sound_read_thread_func, NULL);
  129. if (ret != 0) {
  130. m_sys_error = errno;
  131. return ksp_create_thread_fail;
  132. }
  133. started = true;
  134. return ksp_success;
  135. }
  136. static void readvoice() {
  137. static int32_t voicebuf[MAX_ONE_FRAME_VOICE_SIZE]; // 50ms
  138. static int32_t rxdatabytesize; //
  139. rxdatabytesize = 0;
  140. memset(voicebuf, 0, sizeof(voicebuf));
  141. gpio_set_value(0);
  142. // usleep(1500); // CS信号触发后,给单片机足够的时间准备音频数据
  143. int ret = read(m_fd, &rxdatabytesize, 4);
  144. // printf("read rxdatabytesize:%d\n", rxdatabytesize);
  145. if (rxdatabytesize <= 0) {
  146. gpio_set_value(1);
  147. return;
  148. }
  149. if (rxdatabytesize > MAX_ONE_FRAME_VOICE_SIZE * 4) {
  150. printf("WARNING: rxdatabytesize(%d) > voiceBufSize \n", rxdatabytesize);
  151. gpio_set_value(1);
  152. return;
  153. }
  154. ret = read(m_fd, voicebuf, rxdatabytesize);
  155. gpio_set_value(1);
  156. {
  157. int32_t voiceframesize = 0;
  158. filterVoice(voicebuf, rxdatabytesize / 4);
  159. int32_t *voicereport = multiplierX2(voicebuf, rxdatabytesize / 4, &voiceframesize);
  160. if (m_callback) m_callback(voicereport, voiceframesize);
  161. }
  162. return;
  163. }
  164. void spisound_dump_last_error() {
  165. printf("----------------spisound_dump_last_error-----------------\n");
  166. printf("- module error: %s(%d)\n", error_code_to_string(m_last_error), m_last_error);
  167. printf("- sys_ error : %s(%d)\n", strerror(m_sys_error), m_sys_error);
  168. printf("-\n");
  169. }