Переписал библиотеку GitHub - elechouse/VoiceRecognitionV3: Arduino library for elechouse Voice Recognition V3 module
под ESP32-S3, все команды работают кроме самой важной load она возвращает -1 то есть : Load failed or timeout.
На Arduino всё прекрасно работает.
load 0 1 2 3
--------------------------------------------------------------------------------
Load failed or timeout.
--------------------------------------------------------------------------------
Подскажите, в чём проблема?
VoiceRecognitionV3.h
// Edited by Frank Van Hooft 2022 specifically for ESP32 UART2
/**
******************************************************************************
* @file VoiceRecognitionV2.h
* @author Elechouse Team
* @version V1.0
* @date 2013-6-6
* @brief This file provides all the VoiceRecognitionV2 firmware functions.
******************************************************************************
@note
This driver is for elechouse Voice Recognition V2 Module(LINKS here)
******************************************************************************
* @section HISTORY
V1.0 Initial version.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, ELECHOUSE SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2013 ELECHOUSE</center></h2>
******************************************************************************
*/
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "wiring_private.h"
#define DEBUG
#ifdef DEBUG
#define DBGSTR(message) Serial.print(message)
#define DBGBUF(buf, len) Serial.write(buf, len)
#define DBGLN(message) Serial.println(message)
#define DBGFMT(msg, fmt) Serial.print(msg, fmt)
#define DBGCHAR(c) Serial.write(c)
#else
#define DBG(message)
#endif // DEBUG
#define VR_DEFAULT_TIMEOUT (1000)
/***************************************************************************/
#define FRAME_HEAD (0xAA)
#define FRAME_END (0x0A)
/***************************************************************************/
#define FRAME_CMD_CHECK_SYSTEM (0x00)
#define FRAME_CMD_CHECK_BSR (0x01)
#define FRAME_CMD_CHECK_TRAIN (0x02)
#define FRAME_CMD_CHECK_SIG (0x03)
#define FRAME_CMD_RESET_DEFAULT (0x10) //reset configuration
#define FRAME_CMD_SET_BR (0x11) //baud rate
#define FRAME_CMD_SET_IOM (0x12) //IO mode
#define FRAME_CMD_SET_PW (0x13) //pulse width
#define FRAME_CMD_RESET_IO (0x14) // reset IO OUTPUT
#define FRAME_CMD_SET_AL (0x15) // Auto load
#define FRAME_CMD_TRAIN (0x20)
#define FRAME_CMD_SIG_TRAIN (0x21)
#define FRAME_CMD_SET_SIG (0x22)
#define FRAME_CMD_LOAD (0x30) //Load N records
#define FRAME_CMD_CLEAR (0x31) //Clear BSR buffer
#define FRAME_CMD_GROUP (0x32) //
#define FRAME_CMD_GROUP_SET (0x00) //
#define FRAME_CMD_GROUP_SUGRP (0x01) //
#define FRAME_CMD_GROUP_LSGRP (0x02) //
#define FRAME_CMD_GROUP_LUGRP (0x03) //
#define FRAME_CMD_GROUP_CUGRP (0x04) //
#define FRAME_CMD_TEST (0xEE)
#define FRAME_CMD_TEST_READ (0x01)
#define FRAME_CMD_TEST_WRITE (0x00)
#define FRAME_CMD_VR (0x0D) //Voice recognized
#define FRAME_CMD_PROMPT (0x0A)
#define FRAME_CMD_ERROR (0xFF)
/***************************************************************************/
// #define FRAME_ERR_UDCMD (0x00)
// #define FRAME_ERR_LEN (0x01)
// #define FRAME_ERR_DATA (0x02)
// #define FRAME_ERR_SUBCMD (0x03)
// //#define FRAME_ERR_
// #define FRAME_STA_SUCCESS (0x00)
// #define FRAME_STA_FAILED (0xFF)
/***************************************************************************/
class VR {
public:
VR(uint8_t receivePin, uint8_t transmitPin);
static VR* getInstance() {
return instance;
}
typedef enum{
PULSE = 0,
TOGGLE = 1,
SET = 2,
CLEAR = 3
}io_mode_t;
typedef enum{
LEVEL0 = 0,
LEVEL1,
LEVEL2,
LEVEL3,
LEVEL4,
LEVEL5,
LEVEL6,
LEVEL7,
LEVEL8,
LEVEL9,
LEVEL10,
LEVEL11,
LEVEL12,
LEVEL13,
LEVEL14,
LEVEL15,
}pulse_width_level_t;
typedef enum{
GROUP0 = 0,
GROUP1,
GROUP2,
GROUP3,
GROUP4,
GROUP5,
GROUP6,
GROUP7,
GROUP_ALL = 0xFF,
}group_t;
void begin(HardwareSerial* SerialPort);
int setBaudRate(unsigned long br);
int setIOMode(io_mode_t mode);
int resetIO(uint8_t *ios=0, uint8_t len=1);
int setPulseWidth(uint8_t level);
int setAutoLoad(uint8_t *records=0, uint8_t len = 0);
int disableAutoLoad();
int restoreSystemSettings();
int checkSystemSettings(uint8_t* buf);
int recognize(uint8_t *buf, int timeout = VR_DEFAULT_TIMEOUT);
int train(uint8_t *records, uint8_t len=1, uint8_t *buf = 0);
int train(uint8_t record, uint8_t *buf = 0);
int trainWithSignature(uint8_t record, const void *buf, uint8_t len=0, uint8_t *retbuf = 0);
int load(uint8_t *records, uint8_t len=1, uint8_t *buf = 0);
int load(uint8_t record, uint8_t *buf = 0);
int clear();
int setSignature(uint8_t record, const void *buf=0, uint8_t len=0);
int deleteSignature(uint8_t record);
int checkSignature(uint8_t record, uint8_t *buf);
int checkRecognizer(uint8_t *buf);
int checkRecord(uint8_t *buf, uint8_t *records = 0, uint8_t len = 0);
/** group control */
int setGroupControl(uint8_t ctrl);
int checkGroupControl();
int setUserGroup(uint8_t grp, uint8_t *records, uint8_t len);
int checkUserGroup(uint8_t grp, uint8_t *buf);
int loadSystemGroup(uint8_t grp, uint8_t *buf=0);
int loadUserGroup(uint8_t grp, uint8_t *buf=0);
int test(uint8_t cmd, uint8_t *bsr);
int writehex(uint8_t *buf, uint8_t len);
/***************************************************************************/
/** low level */
int len(uint8_t *buf);
int cmp(uint8_t *buf, uint8_t *bufcmp, int len );
void cpy(char *buf, char * pbuf);
void sort(uint8_t *buf, int len);
int cleanDup(uint8_t *des, uint8_t *buf, int len);
void send_pkt(uint8_t *buf, uint8_t len);
void send_pkt(uint8_t cmd, uint8_t *buf, uint8_t len);
void send_pkt(uint8_t cmd, uint8_t subcmd, uint8_t *buf, uint8_t len);
int receive(uint8_t *buf, int len, uint16_t timeout = VR_DEFAULT_TIMEOUT);
int receive_pkt(uint8_t *buf, uint16_t timeout = VR_DEFAULT_TIMEOUT);
/***************************************************************************/
private:
static VR* instance;
};
VoiceRecognitionV3.cpp
// Edited by Frank Van Hooft 2022 specifically for ESP32 UART2
/**
******************************************************************************
* @file VoiceRecognitionV2.cpp
* @author Elechouse Team
* @version V1.0
* @date 2013-6-6
* @brief This file provides all the VoiceRecognitionV2 firmware functions.
******************************************************************************
@note
This driver is for elechouse Voice Recognition V2 Module(LINKS here)
******************************************************************************
* @section HISTORY
V1.0 Initial version.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, ELECHOUSE SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2013 ELECHOUSE</center></h2>
******************************************************************************
*/
#include "VoiceRecognitionV3.h"
#include <string.h>
#include <inttypes.h>
VR* VR::instance;
HardwareSerial* SERIAL_2;
/** temp data buffer */
uint8_t vr_buf[32];
uint8_t hextab[17]="0123456789ABCDEF";
/**
@brief VR class constructor.
@param receivePin --> software serial RX - IGNORED FOR ESP32
transmitPin --> software serial TX - IGNORED FOR ESP32
*/
VR::VR(uint8_t receivePin, uint8_t transmitPin)
{
instance = this;
}
/**
@brief VR class constructor.
@param buf --> return data .
buf[0] --> Group mode(FF: None Group, 0x8n: User, 0x0n:System
buf[1] --> number of record which is recognized.
buf[2] --> Recognizer index(position) value of the recognized record.
buf[3] --> Signature length
buf[4]~buf[n] --> Signature
timeout --> wait time for receiving packet.
@retval length of valid data in buf. 0 means no data received.
*/
int VR :: recognize(uint8_t *buf, int timeout)
{
int ret, i;
ret = receive_pkt(vr_buf, timeout);
if(vr_buf[2] != FRAME_CMD_VR){
return -1;
}
if(ret > 0){
for(i = 0; i < (vr_buf[1] - 3); i++){
buf[i] = vr_buf[4+i];
}
return i;
}
return 0;
}
void VR :: begin(HardwareSerial* SerialPort)
{
SERIAL_2 = SerialPort;
}
/**
@brief train records, at least one.
@param records --> record data buffer pointer.
len --> number of records.
buf --> pointer of return value buffer, optional.
buf[0] --> number of records which are trained successfully.
buf[2i+1] --> record number
buf[2i+2] --> record train status.
00 --> Trained
FE --> Train Time Out
FF --> Value out of range"
(i = 0 ~ len-1 )
@retval '>0' --> length of valid data in buf.
0 --> success, and no data received.
'<0' --> failed.
-1 --> data format error.
-2 --> train timeout.
*/
int VR :: train(uint8_t *records, uint8_t len, uint8_t *buf)
{
int ret;
unsigned long start_millis;
if(len == 0){
return -1;
}
send_pkt(FRAME_CMD_TRAIN, records, len);
start_millis = millis();
while(1){
ret = receive_pkt(vr_buf);
if(ret>0){
switch(vr_buf[2]){
case FRAME_CMD_PROMPT:
DBGSTR("Record:\t");
DBGFMT(vr_buf[3], DEC);
DBGSTR("\t");
DBGBUF(vr_buf+4, ret-4);
break;
case FRAME_CMD_TRAIN:
if(buf != 0){
memcpy(buf, vr_buf+3, vr_buf[1]-2);
return vr_buf[1]-2;
}
DBGSTR("Train finish.\r\nSuccess: \t");
DBGFMT(vr_buf[3], DEC);
DBGSTR(" \r\n");
return 0;
break;
default:
break;
}
start_millis = millis();
}
if(millis()-start_millis > 8000){
return -2;
}
}
return 0;
}
/**
@brief train one record.
@param records --> record data buffer pointer.
len --> number of records.
buf --> pointer of return value buffer, optional.
buf[0] --> number of records which are trained successfully.
buf[2i+1] --> record number
buf[2i+2] --> record train status.
00 --> Trained
FE --> Train Time Out
FF --> Value out of range"
(i = 0 ~ len-1 )
@retval '>0' --> length of valid data in buf.
0 --> success, and no data received.
'<0' --> failed.
-1 --> data format error.
-2 --> train timeout.
*/
int VR :: train(uint8_t record, uint8_t *buf)
{
return train(&record, 1, buf);
}
/**
@brief train record and set a signature(alias) for this record.
@param record --> record value.
buf --> signature string/data pointer.
len --> lenght of buf.
retbuf --> return data .
retbuf[0] --> number of records which are trained successfully.
retbuf[1] --> record number.
retbuf[2] --> record train status.
00 --> Trained
F0 --> Trained, signature truncate
FE --> Train Time Out
FF --> Value out of range"
retbuf[3] ~ retbuf[retval-1] --> Signature.(retval means return value)
@retval '>0' --> length of valid data in buf.
0 --> success, and no data received.
'<0' --> failed.
-1 --> data format error.
-2 --> train with signature timeout.
*/
int VR :: trainWithSignature(uint8_t record, const void *buf, uint8_t len, uint8_t * retbuf)
{
int ret;
unsigned long start_millis;
if(len){
send_pkt(FRAME_CMD_SIG_TRAIN, record, (uint8_t *)buf, len);
}else{
if(buf == 0){
return -1;
}
len = strlen((char *)buf);
if(len>10){
return -1;
}
send_pkt(FRAME_CMD_SIG_TRAIN, record, (uint8_t *)buf, len);
}
start_millis = millis();
while(1){
ret = receive_pkt(vr_buf);
if(ret>0){
switch(vr_buf[2]){
case FRAME_CMD_PROMPT:
DBGSTR("Record:\t");
DBGFMT(vr_buf[3], DEC);
DBGSTR("\t");
DBGBUF(vr_buf+4, ret-4);
break;
case FRAME_CMD_SIG_TRAIN:
if(retbuf != 0){
memcpy(retbuf, vr_buf+3, vr_buf[1]-2);
return vr_buf[1]-2;
}
DBGSTR("Train finish.\r\nSuccess: \t");
DBGFMT(vr_buf[3], DEC);
DBGSTR(" \r\n");
writehex(vr_buf, vr_buf[1]+2);
return 0;
break;
default:
break;
}
start_millis = millis();
}
if(millis()-start_millis > 8000){
return -2;
}
}
return 0;
}
/**
@brief Load records to recognizer.
@param records --> record data buffer pointer.
len --> number of records.
buf --> pointer of return value buffer, optional.
buf[0] --> number of records which are load successfully.
buf[2i+1] --> record number
buf[2i+2] --> record load status.
00 --> Loaded
FC --> Record already in recognizer
FD --> Recognizer full
FE --> Record untrained
FF --> Value out of range"
(i = 0 ~ '(retval-1)/2' )
@retval '>0' --> length of valid data in buf.
0 --> success, buf=0, and no data returned.
'<0' --> failed.
*/
int VR :: load(uint8_t *records, uint8_t len, uint8_t *buf)
{
uint8_t ret;
send_pkt(FRAME_CMD_LOAD, records, len);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_LOAD){
return -1;
}
if(buf != 0){
memcpy(buf, vr_buf+3, vr_buf[1]-2);
return vr_buf[1]-2;
}
return 0;
}
/**
@brief Load one record to recognizer.
@param record --> record value.
buf --> pointer of return value buffer, optional.
buf[0] --> number of records which are load successfully.
buf[2i+1] --> record number
buf[2i+2] --> record load status.
00 --> Loaded
FC --> Record already in recognizer
FD --> Recognizer full
FE --> Record untrained
FF --> Value out of range"
(i = 0 ~ '(retval-1)/2' )
@retval '>0' --> length of valid data in buf.
0 --> success, buf=0, and no data returned.
'<0' --> failed.
*/
int VR :: load(uint8_t record, uint8_t *buf)
{
uint8_t ret;
send_pkt(FRAME_CMD_LOAD, &record, 1);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_LOAD){
return -1;
}
if(buf != 0){
memcpy(buf, vr_buf+3, vr_buf[1]-2);
return vr_buf[1]-2;
}
return 0;
}
/**
@brief set signature(alias) for a record.
@param record --> record value.
buf --> signature buffer.
len --> length of buf.
@retval 0 --> success, buf=0, and no data returned.
'<0' --> failed.
*/
int VR :: setSignature(uint8_t record, const void *buf, uint8_t len)
{
int ret;
if(len == 0 && buf == 0){
/** delete signature */
}else if(len == 0 && buf != 0){
if(buf == 0){
return -1;
}
len = strlen((char *)buf);
if(len>10){
return -1;
}
}else if(len != 0 && buf != 0){
}else{
return -1;
}
send_pkt(FRAME_CMD_SET_SIG, record, (uint8_t *)buf, len);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_SET_SIG){
return -1;
}
return 0;
}
/**
@brief delete signature(alias) of a record.
@param record --> record value.
@retval 0 --> success
-1 --> failed
*/
int VR :: deleteSignature(uint8_t record)
{
return setSignature(record);
}
/**
@brief check the signature(alias) of a record.
@param record --> record value.
buf --> signature, return value buffer.
@retval '>0' --> length of valid data in buf.
0 --> success, buf=0, and no data returned.
'<0' --> failed.
*/
int VR :: checkSignature(uint8_t record, uint8_t *buf)
{
int ret;
if(record < 0){
return -1;
}
send_pkt(FRAME_CMD_CHECK_SIG, record, 0, 0);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_CHECK_SIG){
return -1;
}
if(vr_buf[4]>0){
memcpy(buf, vr_buf+5, vr_buf[4]);
return vr_buf[4];
}else{
return 0;
}
}
/**
@brief clear recognizer.
@retval 0 --> success
-1 --> failed
*/
int VR :: clear()
{
int len;
send_pkt(FRAME_CMD_CLEAR, 0, 0);
len = receive_pkt(vr_buf);
if(len<=0){
Serial.println("Clear returned nothing\r\n");
return -1;
}
if(vr_buf[2] != FRAME_CMD_CLEAR){
Serial.println("Clear returned ");
Serial.print(vr_buf[0], HEX);
Serial.print(vr_buf[1], HEX);
Serial.print(vr_buf[2], HEX);
Serial.print(vr_buf[3], HEX);
Serial.print("\r\n");
return -1;
}
//DBGLN("VR Module Cleared");
return 0;
}
/**
@brief clear recognizer.
@param buf --> return value buffer.
buf[0] --> Number of valid voice records in recognizer
buf[i+1] --> Record number.(0xFF: Not loaded(Nongroup mode), or not set (Group mode))
(i= 0, 1, ... 6)
buf[8] --> Number of all voice records in recognizer
buf[9] --> Valid records position indicate.
buf[10] --> Group mode indicate(FF: None Group, 0x8n: User, 0x0n:System
@retval '>0' --> success, length of data in buf
-1 --> failed
*/
int VR :: checkRecognizer(uint8_t *buf)
{
int len;
send_pkt(FRAME_CMD_CHECK_BSR, 0, 0);
len = receive_pkt(vr_buf);
if(len<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_CHECK_BSR){
return -1;
}
if(vr_buf[1] != 0x0D){
return -1;
}
memcpy(buf, vr_buf+3, vr_buf[1]-2);
return vr_buf[1]-2;
}
/**
@brief check record train status.
@param buf --> return value
buf[0] --> Number of checked records
buf[2i+1] --> Record number.
buf[2i+2] --> Record train status. (00: untrained, 01: trained, FF: record value out of range)
(i = 0 ~ buf[0]-1 )
@retval Number of trained records
*/
int VR :: checkRecord(uint8_t *buf, uint8_t *records, uint8_t len)
{
int ret;
int cnt = 0;
unsigned long start_millis;
if(records == 0 && len==0){
memset(buf, 0xF0, 255);
send_pkt(FRAME_CMD_CHECK_TRAIN, 0xFF, 0, 0);
start_millis = millis();
while(1){
len = receive_pkt(vr_buf);
if(len>0){
if(vr_buf[2] == FRAME_CMD_CHECK_TRAIN){
for(int i=0; i<vr_buf[1]-3; i+=2){
buf[vr_buf[4+i]]=vr_buf[4+i+1];
}
cnt++;
if(cnt == 51){
return vr_buf[3];
}
}else{
return -3;
}
start_millis = millis();
}
if(millis()-start_millis > 500){
if(cnt>0){
buf[0] = cnt*5;
return vr_buf[3];
}
return -2;
}
}
}else if(len>0){
ret = cleanDup(vr_buf, records, len);
send_pkt(FRAME_CMD_CHECK_TRAIN, vr_buf, ret);
ret = receive_pkt(vr_buf);
if(ret>0){
if(vr_buf[2] == FRAME_CMD_CHECK_TRAIN){
memcpy(buf+1, vr_buf+4, vr_buf[1]-3);
buf[0] = (vr_buf[1]-3)/2;
return vr_buf[3];
}else{
return -3;
}
}else{
return -1;
}
}else{
return -1;
}
}
/****************************************************************************/
/******************************* GROUP CONTROL ******************************/
/**
@brief set group control by external IO function
@param ctrl --> group control by external IO
0 --> disable group control by external IO
1 --> user group control by external IO
2 --> system group control by external IO
@retval 0 --> success
-1 --> failed
*/
int VR :: setGroupControl(uint8_t ctrl)
{
int ret;
if(ctrl>2){
return -1;
}
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_SET, &ctrl, 1);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_GROUP){
return -1;
}
return 0;
}
/**
@brief check group control by external IO function
@param ctrl --> group control by external IO
@retval 0 --> group control by external IO disabled
1 --> user group control by external IO status
2 --> system group control by external IO status
-1 --> failed
*/
int VR :: checkGroupControl()
{
uint8_t cmd;
int ret;
cmd = 0xFF;
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_SET, &cmd, 1);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_GROUP){
return -1;
}
ret = vr_buf[5];
if(ret == 0xFF){
ret = 0;
}
return ret;
}
/**
@brief set user gruop content.
@param grp --> user group number.
records --> pointer of records buffer.
len --> length of reocrds
@retval 0 --> success
-1 --> failed
*/
int VR :: setUserGroup(uint8_t grp, uint8_t *records, uint8_t len)
{
int ret;
if(len == 0 || records == 0){
return -1;
}
if(grp >= 8){
return -1;
}
vr_buf[0] = grp;
memcpy(vr_buf+1, records, len);
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_SUGRP, vr_buf, len+1);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_GROUP){
return -1;
}
return 0;
}
/**
@brief check user gruop content.
@param grp --> user group number.
buf --> return value
buf[8i] --> group number.
buf[8i+1] --> group position 0 status.
buf[8i+2] --> group position 1 status.
... ...
buf[8i+6] --> group position 5 status.
buf[8i+7] --> group position 6 status.
(i = 0 ~ @retval)
@retval '>0' --> number of checked user group
'<0' --> failed
*/
int VR :: checkUserGroup(uint8_t grp, uint8_t *buf)
{
int ret;
int cnt = 0;
unsigned long start_millis;
if(grp == GROUP_ALL){
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_CUGRP, 0, 0);
start_millis = millis();
while(1){
ret = receive_pkt(vr_buf);
if(ret>0){
if(vr_buf[2] == FRAME_CMD_GROUP && vr_buf[1] == 10){
memcpy(buf+8*cnt, vr_buf+3, vr_buf[1]-2);
cnt++;
if(cnt == 8){
return cnt;
}
}else{
return -3;
}
start_millis = millis();
}
if(millis()-start_millis > 500){
if(cnt>0){
return cnt;
}
return -2;
}
}
}else if(grp <= GROUP7){
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_CUGRP, &grp, 1);
ret = receive_pkt(vr_buf);
if(ret>0){
if(vr_buf[2] == FRAME_CMD_GROUP && vr_buf[1] == 10){
memcpy(buf+8*cnt, vr_buf+3, vr_buf[1]-2);
return 1;
}else{
return -3;
}
}else{
return -2;
}
}else{
return -1;
}
}
/**
@brief load system gruop content to recognizer.
@param grp --> syestem group number.
buf --> return value.
buf[0] --> Number of valid voice records in recognizer.
buf[i+1] --> Record number.(0xFF: Not loaded(Nongroup mode), or not set (Group mode))
(i= 0, 1, ... 6)
buf[8] --> Number of all voice records in recognizer
buf[9] --> Valid records position indicate.
buf[10] --> Group mode indicate(FF: None Group, 0x8n: User, 0x0n:System
(i = 0 ~ @retval)
@retval '>0' --> length of buf
'<0' --> failed
*/
int VR :: loadSystemGroup(uint8_t grp, uint8_t *buf)
{
int ret;
if(grp > 10){
return -1;
}
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_LSGRP, &grp, 1);
ret = receive_pkt(vr_buf);
if(ret <= 0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_GROUP){
return -1;
}
if(buf != 0){
vr_buf[3] = 0;
for(int i=0; i<8; i++){
if(vr_buf[12]&(1<<i)){
vr_buf[3]++;
}
}
memcpy(buf, vr_buf+3, vr_buf[1]-2);
return vr_buf[1]-2;
}
return 0;
}
/**
@brief load user gruop content to recognizer.
@param grp --> user group number.
buf --> return value.
buf[0] --> Number of valid voice records in recognizer.
buf[i+1] --> Record number.(0xFF: Not loaded(Nongroup mode), or not set (Group mode))
(i= 0, 1, ... 6)
buf[8] --> Number of all voice records in recognizer
buf[9] --> Valid records position indicate.
buf[10] --> Group mode indicate(FF: None Group, 0x8n: User, 0x0n:System)
(i = 0 ~ @retval)
@retval '>0' --> length of buf
'<0' --> failed
*/
int VR :: loadUserGroup(uint8_t grp, uint8_t *buf)
{
int ret;
if(grp > GROUP7){
return -1;
}
send_pkt(FRAME_CMD_GROUP, FRAME_CMD_GROUP_LUGRP, &grp, 1);
ret = receive_pkt(vr_buf);
if(ret <= 0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_GROUP){
return -1;
}
if(buf != 0){
vr_buf[3] = 0;
for(int i=0; i<8; i++){
if(vr_buf[12]&(1<<i)){
vr_buf[3]++;
}
}
memcpy(buf, vr_buf+3, 11);
return 1;
}
return 0;
}
/**
@brief reset system setting to default
@retval 0 --> success
-1 --> failed
*/
int VR :: restoreSystemSettings()
{
int len;
send_pkt(FRAME_CMD_RESET_DEFAULT, 0, 0);
len = receive_pkt(vr_buf);
if(len<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_RESET_DEFAULT){
return -1;
}
return 0;
}
/**
@brief check system settings
@param buf --> return value
buf[0] --> baud rate. (0-9600 1-2400 2-4800 3-9600 4-19200 5-38400)
buf[1] --> output io mode(0-pulse 1-toggle 2-clear 3-set)
buf[2] --> pulse width level
buf[3] --> auto load(0,0xFF-disable 1-enable)
buf[4] --> Group control by external IO(0-disable 1-system group 2-user group)
@retval '>0' --> buf length
-1 --> failed
*/
int VR :: checkSystemSettings(uint8_t* buf)
{
int len;
if(buf == 0){
return -1;
}
send_pkt(FRAME_CMD_CHECK_SYSTEM, 0, 0);
len = receive_pkt(vr_buf);
if(len<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_CHECK_SYSTEM){
return -1;
}
memcpy(buf, vr_buf+4, vr_buf[1]-3);
return vr_buf[1]-3;
return 0;
}
/**
@brief set module baud rate.
@param br --> module baud rate.(0-9600 1-2400 2-4800 3-9600 4-19200 5-38400)
@retval 0 --> success
-1 --> failed
This changes the baud rate of the module, but not of the ESP32 serial port!
*/
int VR :: setBaudRate(unsigned long br)
{
uint8_t baud_rate;
int ret;
switch(br){
case 2400:
baud_rate = 1;
break;
case 4800:
baud_rate = 2;
break;
case 9600:
baud_rate = 0;
//baud_rate = 3;
break;
case 19200:
baud_rate = 4;
break;
case 38400:
baud_rate = 5;
break;
default:
return -1;
break;
}
send_pkt(FRAME_CMD_SET_BR, baud_rate, 0, 0);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_SET_BR){
return -1;
}
//DBGLN("VR Module Cleared");
return 0;
}
/**
@brief set module output IO mode.
@param mode --> module output IO mode.(must be PULSE, TOGGLE, SET, CLEAR)
@retval 0 --> success
-1 --> failed
*/
int VR :: setIOMode(io_mode_t mode)
{
if(mode > 3){
return -1;
}
int ret;
send_pkt(FRAME_CMD_SET_IOM, mode, 0, 0);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_SET_IOM){
return -1;
}
return 0;
}
/**
@brief resset module output IO.
@param ios --> output IO buffer.
len --> length of ios.
@retval 0 --> success
-1 --> failed
*/
int VR :: resetIO(uint8_t *ios, uint8_t len)
{
int ret;
if(len == 1 && ios == 0){
send_pkt(FRAME_CMD_RESET_IO, 0xFF, 0, 0);
}else if(len != 0 && ios != 0){
send_pkt(FRAME_CMD_RESET_IO, ios, len);
}else{
return -1;
}
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_RESET_IO){
return -1;
}
return 0;
}
/**
@brief set module pulse width(PULSE mode).
@param level --> pulse width level.(LEVEL0~LEVEL15)
len --> length of ios.
@retval 0 --> success
-1 --> failed
*/
int VR :: setPulseWidth(uint8_t level)
{
int ret;
if(level > VR::LEVEL15){
return -1;
}
send_pkt(FRAME_CMD_SET_PW, level, 0, 0);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_SET_PW){
return -1;
}
return 0;
}
/**
@brief set autoload.
@param records --> record buffer.
len --> records length.
@retval 0 --> success
-1 --> failed
*/
int VR :: setAutoLoad(uint8_t *records, uint8_t len)
{
int ret;
uint8_t map;
if(len == 0 && records == 0){
map = 0;
}else if(len != 0 && records != 0){
map = 0;
for(int i=0; i<len; i++){
map |= (1<<i);
}
}else{
return -1;
}
send_pkt(FRAME_CMD_SET_AL, map, records, len);
ret = receive_pkt(vr_buf);
if(ret<=0){
return -1;
}
if(vr_buf[2] != FRAME_CMD_SET_AL){
return -1;
}
return 0;
}
/**
@brief disable autoload.
@param records --> record buffer.
len --> records length.
@retval 0 --> success
-1 --> failed
*/
int VR :: disableAutoLoad()
{
return setAutoLoad();
}
int VR :: test(uint8_t cmd, uint8_t *bsr)
{
int len, i;
unsigned long start_millis;
switch(cmd){
case FRAME_CMD_TEST_READ:
vr_buf[0] = FRAME_CMD_TEST_READ;
send_pkt(FRAME_CMD_TEST, vr_buf, 1);
start_millis = millis();
while(1){
len = receive_pkt(vr_buf);
if(len>0){
switch(vr_buf[2]){
case FRAME_CMD_TEST:
memcpy(bsr+vr_buf[3]*20, vr_buf+4, 20);
if(vr_buf[3] == 9){
return 0;
}
break;
default:
DBGLN("TEST ERROR");
return -1;
break;
}
start_millis = millis();
}
if(millis()-start_millis > 4000){
return -2;
}
}
break;
case FRAME_CMD_TEST_WRITE:
for(i=0; i<10; i++){
vr_buf[0] = i;
memcpy(vr_buf+1, bsr+20*i, 20);
send_pkt(FRAME_CMD_TEST, FRAME_CMD_TEST_WRITE, vr_buf, 21);
start_millis = millis();
while(1){
len = receive_pkt(vr_buf);
if(len>0){
if(vr_buf[2] == FRAME_CMD_TEST){
break;
}else{
DBGLN("TEST ERROR");
return -1;
}
start_millis = millis();
}
if(millis()-start_millis > 4000){
return -2;
}
}
}
break;
default:
break;
}
return 0;
}
/**flash operation function (strlen)*/
int VR :: len(uint8_t *buf)
{
int i=0;
while(pgm_read_byte_near(buf++)){
i++;
}
return i;
}
/**flash operation function (strcmp)*/
int VR :: cmp(uint8_t *buf, uint8_t *bufcmp, int len )
{
int i;
for(i=0; i<len; i++){
if(buf[i] != pgm_read_byte_near(bufcmp+i)){
return -1;
}
}
return 0;
}
/**flash operation function (strcpy)*/
void VR :: cpy(char *buf, char * pbuf)
{
int i=0;
while(pgm_read_byte_near(pbuf)){
buf[i] = pgm_read_byte_near(pbuf++);
i++;
}
}
/** ascending sort */
void VR :: sort(uint8_t *buf, int len)
{
int i, j;
uint8_t tmp;
for(i=0; i<len; i++){
for(j=i+1; j<len; j++){
if(buf[j] < buf[i]){
tmp = buf[i];
buf[i] = buf[j];
buf[j] = tmp;
}
}
}
}
/** remove duplicates */
int VR :: cleanDup(uint8_t *des, uint8_t *buf, int len)
{
if(len<1){
return -1;
}
int i, j, k=0;
for(i=0; i<len; i++){
for(j=0; j<k; j++){
if(buf[i] == des[j]){
break;
}
}
if(j==k){
des[k] = buf[i];
k++;
}
}
return k;
#if 0
int i=0, j=1, k=0;
sort(buf, len);
for(; j<len; ){
des[k] = buf[i];
k++;
while(buf[i]==buf[j]){
j++;
if(j==len){
return k;
}
}
i=j;
}
return k;
#endif
}
/** Serial print in HEX format */
int VR :: writehex(uint8_t *buf, uint8_t len)
{
int i;
for(i=0; i<len; i++){
DBGCHAR(hextab[(buf[i]&0xF0)>>4]);
DBGCHAR(hextab[(buf[i]&0x0F)]);
DBGCHAR(' ');
}
return len;
}
/**
@brief send data packet in Voice Recognition module protocol format.
@param cmd --> command
subcmd --> subcommand
buf --> data area
len --> length of buf
*/
void VR :: send_pkt(uint8_t cmd, uint8_t subcmd, uint8_t *buf, uint8_t len)
{
while(SERIAL_2->available()){
SERIAL_2->read();// replace flush();
}
SERIAL_2->write(FRAME_HEAD);
SERIAL_2->write(len+3);
SERIAL_2->write(cmd);
SERIAL_2->write(subcmd);
SERIAL_2->write(buf, len);
SERIAL_2->write(FRAME_END);
}
/**
@brief send data packet in Voice Recognition module protocol format.
@param cmd --> command
buf --> data area
len --> length of buf
*/
void VR :: send_pkt(uint8_t cmd, uint8_t *buf, uint8_t len)
{
while(SERIAL_2->available()){
SERIAL_2->read();// replace flush();
}
SERIAL_2->write(FRAME_HEAD);
SERIAL_2->write(len+2);
SERIAL_2->write(cmd);
SERIAL_2->write(FRAME_END);
}
/**
@brief send data packet in Voice Recognition module protocol format.
@param buf --> data area
len --> length of buf
*/
void VR :: send_pkt(uint8_t *buf, uint8_t len)
{
while(SERIAL_2->available()){
SERIAL_2->read();// replace flush();
}
SERIAL_2->write(FRAME_HEAD);
SERIAL_2->write(len+1);
SERIAL_2->write(buf, len);
SERIAL_2->write(FRAME_END);
}
/**
@brief receive a valid data packet in Voice Recognition module protocol format.
@param buf --> return value buffer.
timeout --> time of receiving (ms)
@retval '>0' --> success, packet length(length of all data in buf)
'<0' --> failed
*/
int VR :: receive_pkt(uint8_t *buf, uint16_t timeout)
{
int ret;
ret = receive(buf, 2, timeout);
if(ret != 2){
return -1;
}
if(buf[0] != FRAME_HEAD){
return -2;
}
if(buf[1] < 2){
return -3;
}
ret = receive(buf+2, buf[1], timeout);
if(buf[buf[1]+1] != FRAME_END){
return -4;
}
// DBGBUF(buf, buf[1]+2);
return buf[1]+2;
}
/**
@brief receive data .
@param buf --> return value buffer.
len --> length expect to receive.
timeout --> time of reveiving
@retval number of received bytes, 0 means no data received.
*/
int VR::receive(uint8_t *buf, int len, uint16_t timeout)
{
int read_bytes = 0;
int ret;
unsigned long start_millis;
while (read_bytes < len) {
start_millis = millis();
do {
ret = SERIAL_2->read();
if (ret >= 0) {
break;
}
} while( (millis() - start_millis ) < timeout);
if (ret < 0) {
return read_bytes;
}
buf[read_bytes] = (char)ret;
read_bytes++;
}
return read_bytes;
}
код для ввода команд через консоль vr_sample_train.ino
/**
******************************************************************************
* @file vr_sample_train.ino
* @author JiapengLi
* @brief This file provides a demostration on
* how to train VoiceRecognitionModule to record your voice
******************************************************************************
* @note:
* Use serial command to control VoiceRecognitionModule. '
* All commands are case insensitive. Default serial baud rate 115200.
*
* COMMAND FORMAT EXAMPLE Comment
*
* train train (r0) (r1)... train 0 2 45 Train records
* load load (r0) (r1) ... load 0 51 2 3 Load records
* clear clear clear remove all records in Recognizer
* record record / record (r0) (r1)... record / record 0 79 Check record train status
* vr vr vr Check recognizer status
* getsig getsig (r) getsig 0 Get signature of record (r)
* sigtrain sigtrain (r) (sig) sigtrain 0 ZERO Train one record(r) with signature(sig)
* settings settings settings Check current system settings
******************************************************************************
* @section HISTORY
*
* 2013/06/13 Initial version.
*/
#include "VoiceRecognitionV3.h"
HardwareSerial SERIAL_4(1);
/**
* Connection
* Arduino VoiceRecognitionModule
* 2 -------> TX
* 3 -------> RX
*/
VR myVR(2,3); // 2:RX 3:TX, you can choose your favourite pins.
/***************************************************************************/
/** declare print functions */
void printSeperator();
void printSignature(uint8_t *buf, int len);
void printVR(uint8_t *buf);
void printLoad(uint8_t *buf, uint8_t len);
void printTrain(uint8_t *buf, uint8_t len);
void printCheckRecognizer(uint8_t *buf);
void printUserGroup(uint8_t *buf, int len);
void printCheckRecord(uint8_t *buf, int num);
void printCheckRecordAll(uint8_t *buf, int num);
void printSigTrain(uint8_t *buf, uint8_t len);
void printSystemSettings(uint8_t *buf, int len);
void printHelp(void);
/***************************************************************************/
// command analyze part
#define CMD_BUF_LEN 64+1
#define CMD_NUM 10
typedef int (*cmd_function_t)(int, int);
uint8_t cmd[CMD_BUF_LEN];
uint8_t cmd_cnt;
uint8_t *paraAddr;
int receiveCMD();
int checkCMD(int len);
int checkParaNum(int len);
int findPara(int len, int paraNum, uint8_t **addr);
int compareCMD(uint8_t *para1 , uint8_t *para2, int len);
int cmdTrain(int len, int paraNum);
int cmdLoad(int len, int paraNum);
int cmdTest(int len, int paraNum);
int cmdVR(int len, int paraNum);
int cmdClear(int len, int paraNum);
int cmdRecord(int len, int paraNum);
int cmdSigTrain(int len, int paraNum);
int cmdGetSig(int len, int paraNum);
int cmdSettings(int len, int paraNum);
int cmdHelp(int len, int paraNum);
/** cmdList, cmdLen, cmdFunction has correspondence */
const char cmdList[CMD_NUM][10] = { // command list table
{
"train" }
,
{
"load" }
,
{
"clear" }
,
{
"vr" }
,
{
"record" }
,
{
"sigtrain" }
,
{
"getsig" }
,
{
"Settings" }
,
{
"test" }
,
{
"help" }
,
};
const char cmdLen[CMD_NUM]= { // command length
5, // {"train"},
4, // {"load"},
5, // {"clear"},
2, // {"vr"},
6, // {"record"},
8, // {"sigtrain"},
6, // {"getsig"},
8, // {"Settings"},
4, // {"test"},
4, // {"help"}
};
cmd_function_t cmdFunction[CMD_NUM]={ // command handle fuction(function pointer table)
cmdTrain,
cmdLoad,
cmdClear,
cmdVR,
cmdRecord,
cmdSigTrain,
cmdGetSig,
cmdSettings,
cmdTest,
cmdHelp,
};
/***************************************************************************/
/** temprory data */
uint8_t buf[255];
uint8_t records[7]; // save record
void setup(void)
{
SERIAL_4.begin(9600, SERIAL_8N1, 42, 39);
myVR.begin(&SERIAL_4);
/** initialize */
Serial.begin(115200);
Serial.println(F("Elechouse Voice Recognition V3 Module \"train\" sample."));
printSeperator();
Serial.println(F("Usage:"));
printSeperator();
printHelp();
printSeperator();
cmd_cnt = 0;
}
void loop(void)
{
int len, paraNum, paraLen, i;
/** receive Serial command */
len = receiveCMD();
if(len>0){
/** check if the received command is valid */
if(!checkCMD(len)){
/** check parameter number of the received command */
paraNum = checkParaNum(len);
/** display the receved command back */
Serial.write(cmd, len);
/** find the first parameter */
paraLen = findPara(len, 1, ¶Addr);
/** compare the received command with command in the list */
for(i=0; i<CMD_NUM; i++){
/** compare command length */
if(paraLen == cmdLen[i]){
/** compare command content */
if( compareCMD(paraAddr, (uint8_t *)cmdList[i], paraLen) == 0 ){
/** call command function */
if( cmdFunction[i](len, paraNum) != 0){
printSeperator();
Serial.println(F("Command Format Error!"));
printSeperator();
}
break;
}
}
}
/** command is not supported*/
if(i == CMD_NUM){
printSeperator();
Serial.println(F("Unkonwn command"));
printSeperator();
}
}
else{
/** received command is invalid */
printSeperator();
Serial.println(F("Command format error"));
printSeperator();
}
}
/** try to receive recognize result */
int ret;
ret = myVR.recognize(buf, 50);
if(ret>0){
/** voice recognized, print result */
printVR(buf);
}
}
/**
* @brief receive command from Serial.
* @param NONE.
* @retval command length, if no command receive return -1.
*/
int receiveCMD()
{
int ret;
int len;
unsigned long start_millis;
start_millis = millis();
while(1){
ret = Serial.read();
if(ret>0){
start_millis = millis();
cmd[cmd_cnt] = ret;
if(cmd[cmd_cnt] == '\n'){
len = cmd_cnt+1;
cmd_cnt = 0;
return len;
}
cmd_cnt++;
if(cmd_cnt == CMD_BUF_LEN){
cmd_cnt = 0;
return -1;
}
}
if(millis() - start_millis > 100){
cmd_cnt = 0;
return -1;
}
}
}
/**
* @brief compare two commands, case insensitive.
* @param para1 --> command buffer 1
* para2 --> command buffer 2
* len --> buffer length
* @retval 0 --> equal
* -1 --> unequal
*/
int compareCMD(uint8_t *para1 , uint8_t *para2, int len)
{
int i;
uint8_t res;
for(i=0; i<len; i++){
res = para2[i] - para1[i];
if(res != 0 && res != 0x20){
res = para1[i] - para2[i];
if(res != 0 && res != 0x20){
return -1;
}
}
}
return 0;
}
/**
* @brief Check command format.
* @param len --> command length
* @retval 0 --> command is valid
* -1 --> command is invalid
*/
int checkCMD(int len)
{
int i;
for(i=0; i<len; i++){
if(cmd[i] > 0x1F && cmd[i] < 0x7F){
}
else if(cmd[i] == '\t' || cmd[i] == ' ' || cmd[i] == '\r' || cmd[i] == '\n'){
}
else{
return -1;
}
}
return 0;
}
/**
* @brief Check the number of parameters in the command
* @param len --> command length
* @retval number of parameters
*/
int checkParaNum(int len)
{
int cnt=0, i;
for(i=0; i<len; ){
if(cmd[i]!='\t' && cmd[i]!=' ' && cmd[i] != '\r' && cmd[i] != '\n'){
cnt++;
while(cmd[i] != '\t' && cmd[i] != ' ' && cmd[i] != '\r' && cmd[i] != '\n'){
i++;
}
}
i++;
}
return cnt;
}
/**
* @brief Find the specified parameter.
* @param len --> command length
* paraIndex --> parameter index
* addr --> return value. position of the parameter
* @retval length of specified parameter
*/
int findPara(int len, int paraIndex, uint8_t **addr)
{
int cnt=0, i, paraLen;
uint8_t dt;
for(i=0; i<len; ){
dt = cmd[i];
if(dt!='\t' && dt!=' '){
cnt++;
if(paraIndex == cnt){
*addr = cmd+i;
paraLen = 0;
while(cmd[i] != '\t' && cmd[i] != ' ' && cmd[i] != '\r' && cmd[i] != '\n'){
i++;
paraLen++;
}
return paraLen;
}
else{
while(cmd[i] != '\t' && cmd[i] != ' ' && cmd[i] != '\r' && cmd[i] != '\n'){
i++;
}
}
}
else{
i++;
}
}
return -1;
}
int cmdHelp(int len, int paraNum)
{
if(paraNum != 1){
return -1;
}
printSeperator();
printHelp();
printSeperator();
return 0;
}
/**
* @brief Handle "train" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdTrain(int len, int paraNum)
{
int i, ret;
if(paraNum < 2 || paraNum > 8 ){
return -1;
}
for(i=2; i<=paraNum; i++){
findPara(len, i, ¶Addr);
records[i-2] = atoi((char *)paraAddr);
if(records[i-2] == 0 && *paraAddr != '0'){
return -1;
}
}
printSeperator();
ret = myVR.train(records, paraNum-1, buf);
// ret = myVR.train(records, paraNum-1);
if(ret >= 0){
printTrain(buf, ret);
}
else if(ret == -1){
Serial.println(F("Train failed."));
}
else if(ret == -2){
Serial.println(F("Train Timeout."));
}
printSeperator();
return 0;
}
/**
* @brief Handle "load" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdLoad(int len, int paraNum)
{
int i, ret;
if(paraNum < 2 || paraNum > 8 ){
return -1;
}
for(i=2; i<=paraNum; i++){
findPara(len, i, ¶Addr);
records[i-2] = atoi((char *)paraAddr);
if(records[i-2] == 0 && *paraAddr != '0'){
return -1;
}
}
// myVR.writehex(records, paraNum-1);
ret = myVR.load(records, paraNum-1, buf);
printSeperator();
if(ret >= 0){
printLoad(buf, ret);
}
else{
Serial.println(F("Load failed or timeout."));
}
printSeperator();
return 0;
}
/**
* @brief Handle "clear" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdClear(int len, int paraNum)
{
if(paraNum != 1){
return -1;
}
if(myVR.clear() == 0){
printSeperator();
Serial.println(F("Recognizer cleared."));
printSeperator();
}
else{
printSeperator();
Serial.println(F("Clear recognizer failed or timeout."));
printSeperator();
}
return 0;
}
/**
* @brief Handle "vr" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdVR(int len, int paraNum)
{
int ret;
if(paraNum != 1){
return -1;
}
ret = myVR.checkRecognizer(buf);
if(ret<=0){
printSeperator();
Serial.println(F("Check recognizer failed or timeout."));
printSeperator();
return 0;
}
printSeperator();
printCheckRecognizer(buf);
printSeperator();
return 0;
}
/**
* @brief Handle "record" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdRecord(int len, int paraNum)
{
int ret;
if(paraNum == 1){
ret = myVR.checkRecord(buf);
printSeperator();
if(ret>=0){
printCheckRecordAll(buf, ret);
}
else{
Serial.println(F("Check record failed or timeout."));
}
printSeperator();
}
else if(paraNum < 9){
for(int i=2; i<=paraNum; i++){
findPara(len, i, ¶Addr);
records[i-2] = atoi((char *)paraAddr);
if(records[i-2] == 0 && *paraAddr != '0'){
return -1;
}
}
ret = myVR.checkRecord(buf, records, paraNum-1); // auto clean duplicate records
printSeperator();
if(ret>=0){
printCheckRecord(buf, ret);
}
else{
Serial.println(F("Check record failed or timeout."));
}
printSeperator();
}
else{
return -1;
}
return 0;
}
/**
* @brief Handle "sigtrain" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdSigTrain(int len, int paraNum)
{
int ret, sig_len;
uint8_t *lastAddr;
if(paraNum < 2){
return -1;
}
findPara(len, 2, ¶Addr);
records[0] = atoi((char *)paraAddr);
if(records[0] == 0 && *paraAddr != '0'){
return -1;
}
findPara(len, 3, ¶Addr);
sig_len = findPara(len, paraNum, &lastAddr);
sig_len +=( (unsigned int)lastAddr - (unsigned int)paraAddr );
printSeperator();
ret = myVR.trainWithSignature(records[0], paraAddr, sig_len, buf);
// ret = myVR.trainWithSignature(records, paraNum-1);
if(ret >= 0){
printSigTrain(buf, ret);
}
else{
Serial.println(F("Train with signature failed or timeout."));
}
printSeperator();
return 0;
}
/**
* @brief Handle "getsig" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdGetSig(int len, int paraNum)
{
int ret;
if(paraNum != 2){
return -1;
}
findPara(len, 2, ¶Addr);
records[0] = atoi((char *)paraAddr);
if(records[0] == 0 && *paraAddr != '0'){
return -1;
}
ret = myVR.checkSignature(records[0], buf);
printSeperator();
if(ret == 0){
Serial.println(F("Signature isn't set."));
}
else if(ret > 0){
Serial.print(F("Signature:"));
printSignature(buf, ret);
Serial.println();
}
else{
Serial.println(F("Get sig error or timeout."));
}
printSeperator();
return 0;
}
/**
* @brief Handle "test" command
* @param len --> command length
* paraNum --> number of parameters
* @retval 0 --> success
* -1 --> Command format error
*/
int cmdTest(int len, int paraNum)
{
printSeperator();
Serial.println(F("TEST is not supported."));
printSeperator();
return 0;
}
int cmdSettings(int len, int paraNum)
{
int ret;
if(paraNum != 1){
return -1;
}
ret = myVR.checkSystemSettings(buf);
if( ret > 0){
printSeperator();
printSystemSettings(buf, ret);
printSeperator();
}
else{
printSeperator();
Serial.println(F("Check system settings error or timeout"));
printSeperator();
}
return 0;
}
/*****************************************************************************/
/**
* @brief Print signature, if the character is invisible,
* print hexible value instead.
* @param buf --> command length
* len --> number of parameters
*/
void printSignature(uint8_t *buf, int len)
{
int i;
for(i=0; i<len; i++){
if(buf[i]>0x19 && buf[i]<0x7F){
Serial.write(buf[i]);
}
else{
Serial.print(F("["));
Serial.print(buf[i], HEX);
Serial.print(F("]"));
}
}
}
/**
* @brief Print signature, if the character is invisible,
* print hexible value instead.
* @param buf --> VR module return value when voice is recognized.
* buf[0] --> Group mode(FF: None Group, 0x8n: User, 0x0n:System
* buf[1] --> number of record which is recognized.
* buf[2] --> Recognizer index(position) value of the recognized record.
* buf[3] --> Signature length
* buf[4]~buf[n] --> Signature
*/
void printVR(uint8_t *buf)
{
Serial.println(F("VR Index\tGroup\tRecordNum\tSignature"));
Serial.print(buf[2], DEC);
Serial.print(F("\t\t"));
if(buf[0] == 0xFF){
Serial.print(F("NONE"));
}
else if(buf[0]&0x80){
Serial.print(F("UG "));
Serial.print(buf[0]&(~0x80), DEC);
}
else{
Serial.print(F("SG "));
Serial.print(buf[0], DEC);
}
Serial.print(F("\t"));
Serial.print(buf[1], DEC);
Serial.print(F("\t\t"));
if(buf[3]>0){
printSignature(buf+4, buf[3]);
}
else{
Serial.print(F("NONE"));
}
Serial.println(F("\r\n"));
}
/**
* @brief Print seperator. Print 80 '-'.
*/
void printSeperator()
{
for(int i=0; i<80; i++){
Serial.write('-');
}
Serial.println();
}
/**
* @brief Print recoginizer status.
* @param buf --> VR module return value when voice is recognized.
* buf[0] --> Number of valid voice records in recognizer
* buf[i+1] --> Record number.(0xFF: Not loaded(Nongroup mode), or not set (Group mode)) (i= 0, 1, ... 6)
* buf[8] --> Number of all voice records in recognizer
* buf[9] --> Valid records position indicate.
* buf[10] --> Group mode indicate(FF: None Group, 0x8n: User, 0x0n:System)
*/
void printCheckRecognizer(uint8_t *buf)
{
Serial.print(F("All voice records in recognizer: "));
Serial.println(buf[8], DEC);
Serial.print(F("Valid voice records in recognizer: "));
Serial.println(buf[0], DEC);
if(buf[10] == 0xFF){
Serial.println(F("VR is not in group mode."));
}
else if(buf[10]&0x80){
Serial.print(F("VR is in user group mode:"));
Serial.println(buf[10]&0x7F, DEC);
}
else{
Serial.print(F("VR is in system group mode:"));
Serial.println(buf[10], DEC);
}
Serial.println(F("VR Index\tRecord\t\tComment"));
for(int i=0; i<7; i++){
Serial.print(i, DEC);
Serial.print(F("\t\t"));
if(buf[i+1] == 0xFF){
if(buf[10] == 0xFF){
Serial.print(F("Unloaded\tNONE"));
}
else{
Serial.print(F("Not Set\t\tNONE"));
}
}
else{
Serial.print(buf[i+1], DEC);
Serial.print(F("\t\t"));
if(buf[9]&(1<<i)){
Serial.print(F("Valid"));
}
else{
Serial.print(F("Untrained"));
}
}
Serial.println();
}
}
/**
* @brief Print record train status.
* @param buf --> Check record command return value
* buf[0] --> Number of checked records
* buf[2i+1] --> Record number.
* buf[2i+2] --> Record train status. (00: untrained, 01: trained, FF: record value out of range)
* (i = 0 ~ buf[0]-1 )
* num --> Number of trained records
*/
void printCheckRecord(uint8_t *buf, int num)
{
Serial.print(F("Check "));
Serial.print(buf[0], DEC);
Serial.println(F(" records."));
Serial.print(num, DEC);
if(num>1){
Serial.println(F(" records trained."));
}
else{
Serial.println(F(" record trained."));
}
for(int i=0; i<buf[0]*2; i += 2){
Serial.print(buf[i+1], DEC);
Serial.print(F("\t-->\t"));
switch(buf[i+2]){
case 0x01:
Serial.print(F("Trained"));
break;
case 0x00:
Serial.print(F("Untrained"));
break;
case 0xFF:
Serial.print(F("Record value out of range"));
break;
default:
Serial.print(F("Unknown Stauts"));
break;
}
Serial.println();
}
}
/**
* @brief Print record train status.
* @param buf --> Check record command return value
* buf[0] --> Number of checked records
* buf[2i+1] --> Record number.
* buf[2i+2] --> Record train status. (00: untrained, 01: trained, FF: record value out of range)
* (i = 0 ~ buf[0]-1 )
* num --> Number of trained records
*/
void printCheckRecordAll(uint8_t *buf, int num)
{
Serial.print(F("Check 255"));
Serial.println(F(" records."));
Serial.print(num, DEC);
if(num>1){
Serial.println(F(" records trained."));
}
else{
Serial.println(F(" record trained."));
}
myVR.writehex(buf, 255);
for(int i=0; i<255; i++){
if(buf[i] == 0xF0){
continue;
}
Serial.print(i, DEC);
Serial.print(F("\t-->\t"));
switch(buf[i]){
case 0x01:
Serial.print(F("Trained"));
break;
case 0x00:
Serial.print(F("Untrained"));
break;
case 0xFF:
Serial.print(F("Record value out of range"));
break;
default:
Serial.print(F("Unknown Stauts"));
break;
}
Serial.println();
}
}
/**
* @brief Print check user group result.
* @param buf --> Check record command return value
* buf[8i] --> group number.
* buf[8i+1] --> group position 0 status.
* buf[8i+2] --> group position 1 status.
* ... ...
* buf[8i+6] --> group position 5 status.
* buf[8i+7] --> group position 6 status.
* (i = 0 ~ len)
* len --> number of checked groups
*/
void printUserGroup(uint8_t *buf, int len)
{
int i, j;
Serial.println(F("Check User Group:"));
for(i=0; i<len; i++){
Serial.print(F("Group:"));
Serial.println(buf[8*i]);
for(j=0; j<7; j++){
if(buf[8*i+1+j] == 0xFF){
Serial.print(F("NONE\t"));
}
else{
Serial.print(buf[8*i+1+j], DEC);
Serial.print(F("\t"));
}
}
Serial.println();
}
}
/**
* @brief Print "load" command return value.
* @param buf --> "load" command return value
* buf[0] --> number of records which are load successfully.
* buf[2i+1] --> record number
* buf[2i+2] --> record load status.
* 00 --> Loaded
* FC --> Record already in recognizer
* FD --> Recognizer full
* FE --> Record untrained
* FF --> Value out of range"
* (i = 0 ~ (len-1)/2 )
* len --> length of buf
*/
void printLoad(uint8_t *buf, uint8_t len)
{
if(len == 0){
Serial.println(F("Load Successfully."));
return;
}
else{
Serial.print(F("Load success: "));
Serial.println(buf[0], DEC);
}
for(int i=0; i<len-1; i += 2){
Serial.print(F("Record "));
Serial.print(buf[i+1], DEC);
Serial.print(F("\t"));
switch(buf[i+2]){
case 0:
Serial.println(F("Loaded"));
break;
case 0xFC:
Serial.println(F("Record already in recognizer"));
break;
case 0xFD:
Serial.println(F("Recognizer full"));
break;
case 0xFE:
Serial.println(F("Record untrained"));
break;
case 0xFF:
Serial.println(F("Value out of range"));
break;
default:
Serial.println(F("Unknown status"));
break;
}
}
}
/**
* @brief Print "train" command return value.
* @param buf --> "train" command return value
* buf[0] --> number of records which are trained successfully.
* buf[2i+1] --> record number
* buf[2i+2] --> record train status.
* 00 --> Trained
* FE --> Train Time Out
* FF --> Value out of range"
* (i = 0 ~ len-1 )
* len --> length of buf
*/
void printTrain(uint8_t *buf, uint8_t len)
{
if(len == 0){
Serial.println(F("Train Finish."));
return;
}
else{
Serial.print(F("Train success: "));
Serial.println(buf[0], DEC);
}
for(int i=0; i<len-1; i += 2){
Serial.print(F("Record "));
Serial.print(buf[i+1], DEC);
Serial.print(F("\t"));
switch(buf[i+2]){
case 0:
Serial.println(F("Trained"));
break;
case 0xFE:
Serial.println(F("Train Time Out"));
break;
case 0xFF:
Serial.println(F("Value out of range"));
break;
default:
Serial.print(F("Unknown status "));
Serial.println(buf[i+2], HEX);
break;
}
}
}
/**
* @brief Print "sigtrain" command return value.
* @param buf --> "sigtrain" command return value
* buf[0] --> number of records which are trained successfully.
* buf[1] --> record number
* buf[2] --> record train status.
* 00 --> Trained
* F0 --> Trained, signature truncate
* FE --> Train Time Out
* FF --> Value out of range"
* buf[3] ~ buf[len-1] --> Signature.
* len --> length of buf
*/
void printSigTrain(uint8_t *buf, uint8_t len)
{
if(len == 0){
Serial.println(F("Train With Signature Finish."));
return;
}
else{
Serial.print(F("Success: "));
Serial.println(buf[0], DEC);
}
Serial.print(F("Record "));
Serial.print(buf[1], DEC);
Serial.print(F("\t"));
switch(buf[2]){
case 0:
Serial.println(F("Trained"));
break;
case 0xF0:
Serial.println(F("Trained, signature truncate"));
break;
case 0xFE:
Serial.println(F("Train Time Out"));
break;
case 0xFF:
Serial.println(F("Value out of range"));
break;
default:
Serial.print(F("Unknown status "));
Serial.println(buf[2], HEX);
break;
}
Serial.print(F("SIG: "));
Serial.write(buf+3, len-3);
Serial.println();
}
/**
* @brief Print "settings" command return value.
* @param buf --> "settings" command return value
* buf[0] --> number of records which are trained successfully.
* buf[1] --> record number
* buf[2] --> record train status.
* 00 --> Trained
* F0 --> Trained, signature truncate
* FE --> Train Time Out
* FF --> Value out of range"
* buf[3] ~ buf[len-1] --> Signature.
* len --> length of buf
*/
const unsigned int io_pw_tab[16]={
10, 15, 20, 25, 30, 35, 40, 45,
50, 75, 100, 200, 300, 400, 500, 1000
};
void printSystemSettings(uint8_t *buf, int len)
{
switch(buf[0]){
case 0:
case 3:
Serial.println(F("Baud rate: 9600"));
break;
case 1:
Serial.println(F("Baud rate: 2400"));
break;
case 2:
Serial.println(F("Baud rate: 4800"));
break;
case 4:
Serial.println(F("Baud rate: 19200"));
break;
case 5:
Serial.println(F("Baud rate: 38400"));
break;
default:
Serial.println(F("Baud rate: UNKONOWN"));
break;
}
switch(buf[1]){
case 0:
case 0xFF:
Serial.println(F("Outpu IO Mode: Pulse"));
break;
case 1:
Serial.println(F("Outpu IO Mode: Toggle"));
break;
case 2:
Serial.println(F("Outpu IO Mode: Clear(When recognized) "));
break;
case 3:
Serial.println(F("Outpu IO Mode: Set(When recognized)"));
break;
default:
Serial.println(F("Output IO Mode: UNKONOWN"));
break;
}
if(buf[2] > 15){
Serial.println(F("Pulse width: UNKONOWN"));
}
else{
Serial.print(F("Pulse Width: "));
Serial.print(io_pw_tab[buf[2]], DEC);
Serial.println(F("ms"));
}
if(buf[3] == 0 || buf[3] == 0xFF){
Serial.println(F("Auto Load: disable"));
}
else{
Serial.println(F("Auto Load: enable"));
}
switch(buf[4]){
case 0:
case 0xFF:
Serial.println(F("Group control by external IO: disabled"));
break;
case 1:
Serial.println(F("Group control by external IO: system group selected"));
break;
case 2:
Serial.println(F("Group control by external IO: user group selected"));
break;
default:
Serial.println(F("Group control by external IO: UNKNOWN STATUS"));
break;
}
}
void printHelp(void)
{
Serial.println(F("COMMAND FORMAT EXAMPLE Comment"));
printSeperator();
// Serial.println(F("--------------------------------------------------------------------------------------------------------------"));
Serial.println(F("train train (r0) (r1)... train 0 2 45 Train records"));
Serial.println(F("load load (r0) (r1) ... load 0 51 2 3 Load records"));
Serial.println(F("clear clear clear remove all records in Recognizer"));
Serial.println(F("record record / record (r0) (r1)... record / record 0 79 Check record train status"));
Serial.println(F("vr vr vr Check recognizer status"));
Serial.println(F("getsig getsig (r) getsig 0 Get signature of record (r)"));
Serial.println(F("sigtrain sigtrain (r) (sig) sigtrain 0 ZERO Train one record(r) with signature(sig)"));
Serial.println(F("settings settings settings Check current system settings"));
Serial.println(F("help help help print this message"));
}