Hi,
I'm using an ATTiny 804 board with the ultimate goal of driving an led strip or two after a voice command. My voice module linked the Elechouse git repo, but the driver uses software serial, which basically doesn't fares well with led strips and effects.
So I programmed the VR module via an arduino uno R3 (on which, using the original driver, everything works fine), and I now am trying to make the tiny recognize the voice, but something goes wrong: this is my driver implementation (pardon the subs VR->DR, but I tried everything)
#include "VRClient.h"
#include <string.h>
#include <avr/delay.h>
DR* DR::instance;
/** temp data buffer */
uint8_t dr_buf[32];
uint8_t hextab[17]="0123456789ABCDEF";
/**
@brief DR class constructor.
@param receivePin --> software serial RX
transmitPin --> software serial TX
*/
DR::DR(uint8_t receivePin, uint8_t transmitPin)
{
instance = this;
//Serial.begin(38400);
//Serial.begin(9600);
}
int DR::begin(){
Serial.begin(9600);
while(!Serial)
_delay_ms(100);
send_pkt(FRAME_CMD_SET_BR,0,0,0);
return 0;
}
/**
@brief DR 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 DR :: recognize(uint8_t *buf, int timeout)
{
int ret, i;
ret = receive_pkt(dr_buf, timeout);
if(dr_buf[2] != FRAME_CMD_DR){
return -1;
}
if(ret > 0){
for(i = 0; i < (dr_buf[1] - 3); i++){
buf[i] = dr_buf[4+i];
}
return i;
}
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 DR :: load(uint8_t *records, uint8_t len, uint8_t *buf)
{
uint8_t ret;
send_pkt(FRAME_CMD_LOAD, records, len);
ret = receive_pkt(dr_buf);
if(ret<=0){
return -1;
}
if(dr_buf[2] != FRAME_CMD_LOAD){
return -1;
}
if(buf != 0){
memcpy(buf, dr_buf+3, dr_buf[1]-2);
return dr_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 DR :: load(uint8_t record, uint8_t *buf)
{
uint8_t ret;
send_pkt(FRAME_CMD_LOAD, &record, 1);
ret = receive_pkt(dr_buf);
if(ret<=0){
return -1;
}
if(dr_buf[2] != FRAME_CMD_LOAD){
return -1;
}
if(buf != 0){
memcpy(buf, dr_buf+3, dr_buf[1]-2);
return dr_buf[1]-2;
}
return 0;
}
/**
@brief clear recognizer.
@retval 0 --> success
-1 --> failed
*/
int DR :: clear()
{
int len;
send_pkt(FRAME_CMD_CLEAR, 0, 0);
len = receive_pkt(dr_buf);
if(len<=0){
return -1;
}
if(dr_buf[2] != FRAME_CMD_CLEAR){
return -1;
}
//DBGLN("DR Module Cleared");
return 0;
}
/**
@brief send data packet in Voice Recognition module protocol format.
@param cmd --> command
subcmd --> subcommand
buf --> data area
len --> length of buf
*/
void DR :: send_pkt(uint8_t cmd, uint8_t subcmd, uint8_t *buf, uint8_t len)
{
while(Serial.available()){
Serial.read();// replace flush();
}
Serial.write(FRAME_HEAD);
Serial.write(len+3);
Serial.write(cmd);
Serial.write(subcmd);
Serial.write(buf, len);
Serial.write(FRAME_END);
}
/**
@brief send data packet in Voice Recognition module protocol format.
@param cmd --> command
buf --> data area
len --> length of buf
*/
void DR :: send_pkt(uint8_t cmd, uint8_t *buf, uint8_t len)
{
while(Serial.available()){
Serial.read();// replace flush();
}
Serial.write(FRAME_HEAD);
Serial.write(len+2);
Serial.write(cmd);
Serial.write(buf, len);
Serial.write(FRAME_END);
}
/**
@brief send data packet in Voice Recognition module protocol format.
@param buf --> data area
len --> length of buf
*/
void DR :: send_pkt(uint8_t *buf, uint8_t len)
{
while(Serial.available()){
Serial.read();// replace flush();
}
Serial.write(FRAME_HEAD);
Serial.write(len+1);
Serial.write(buf, len);
Serial.write(FRAME_END);
}
/**
@brief receive a valid data packet in Voice Recognition module protocol format.
@param buf --> return value buffer.
timeout --> time of reveiving
@retval '>0' --> success, packet lenght(length of all data in buf)
'<0' --> failed
*/
int DR :: 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 = rece2(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 DR::rece2(uint8_t* buf, int len, uint16_t to){
return Serial.readBytes(buf,len);
}
int DR::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.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;
}
and here is my sketch:
#include <VRClient.h>
#include <Adafruit_NeoPixel.h>
#include <avr/delay.h>
// NOT NEEDED BUT EASY SWITCH
#define PIN_TX PIN_PB1
#define PIN_RX PIN_PB0
// test LED
#define T PIN_PA4
// commands
#define stopC (0)
#define bluC (1)
#define rossoC (2)
#define arancioC (4)
// Region for future LED strip
struct Colore {
uint8_t r;
uint8_t g;
uint8_t b;
Colore(uint8_t rosso, uint8_t verde, uint8_t blu) {
r = rosso;
g = verde;
b = blu;
}
Colore() {}
};
const Colore blu_1 = Colore(0, 100, 255);
const Colore blu_2 = Colore(0, 0, 255);
const Colore blu_3 = Colore(0, 0, 200);
const Colore rosso_1 = Colore(255, 0, 0);
const Colore rosso_2 = Colore(200, 0, 0);
const Colore rosso_3 = Colore(200, 0, 100);
const Colore a_1 = Colore(255, 150, 0);
const Colore a_2 = Colore(255, 100, 0);
const Colore a_3 = Colore(255, 50, 0);
const Colore nero = Colore(0, 0, 0);
struct Effetto {
Colore colori[2];
void set_colori( Colore f, Colore o) {
colori[0] = f;
colori[1] = o;
}
};
volatile Effetto spento;
volatile Effetto blu;
volatile Effetto rosso;
volatile Effetto giallo;
volatile Effetto* Effetti[] = { &blu, &rosso, &giallo,&spento };
volatile Effetto* effetto;
volatile Effetto* prev;
// END LED
DR mic(PIN_TX, PIN_RX);
uint8_t buf[64];
void setup() {
pinMode(T,OUTPUT);
digitalWrite(T,LOW);
// set colours
spento.set_colori(nero, nero);
blu.set_colori(blu_1, blu_3);
rosso.set_colori(rosso_1, rosso_2);
giallo.set_colori(a_1, a_2);
effetto = &spento;
prev=&spento;
mic.begin();
_delay_ms(500);
mic.clear();
mic.load((uint8_t) 0);
mic.load((uint8_t)2);
mic.load((uint8_t)1);
mic.load((uint8_t)4);
}
void loop() {
//Your code here:
int ret;
ret = 0;
ret = mic.recognize(buf, 50);
if (ret >= 0) {
switch (buf[1]) {
case stopC:
effetto = &spento;
break;
case rossoC:
effetto = &rosso;
break;
case 0x01:
effetto = &blu;
break;
case arancioC:
default:
effetto = &giallo;
break;
}
}
if(prev!=effetto)
{
dbg();
}
_delay_ms(500);
void dbg(){
digitalWrite(T,HIGH);
_delay_ms(345);
digitalWrite(T,LOW);
chg=false;
}
The fact is that I see serial activity and the voice command gets recognized, as you can see by the captured frame:
The frame is correct but somehow something is wrong and isn't read by the tiny (the T led doesn't blink). With the same commands everything seems ok with the software serial. I think there must be something I am missing, can you please help me? At this point I don't know what to do.
Thanks
