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.
965 lines
22 KiB
965 lines
22 KiB
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "serial.h"
|
|
#include "a3kpacket.h"
|
|
#include "gpio.h"
|
|
#include "a3k.h"
|
|
#include "tick.h"
|
|
|
|
#define WAIT_TIMEOUT (100) /* 100ms */
|
|
#define RATE_PINS (6)
|
|
|
|
struct fifo_tag {
|
|
char *pnew; /* points to newest fifo element */
|
|
char *pold; /* points to oldest fifo element */
|
|
short nelem;/* number of bytes currently in fifo */
|
|
short blen;
|
|
char *bend;
|
|
char *b;
|
|
};
|
|
|
|
typedef struct fifo_tag FIFO;
|
|
|
|
struct a3k_tag {
|
|
struct serial *uart;
|
|
uint32_t rst;
|
|
uint32_t rts;
|
|
|
|
int pseudo;
|
|
|
|
uint32_t rate[RATE_PINS];
|
|
uint32_t ec;
|
|
uint32_t ns;
|
|
uint32_t es;
|
|
|
|
FIFO rx;
|
|
uint8_t _buf[FORMAT3KBLEN];
|
|
};
|
|
|
|
static char *put_next_byte( char *p, short val )
|
|
{
|
|
*p++ = val;
|
|
return p;
|
|
}
|
|
|
|
static char *put_next_word( char *p, short val )
|
|
{
|
|
*p++ = (val >> 8) & 0x00ff;
|
|
*p++ = val & 0x00ff;
|
|
return p;
|
|
}
|
|
|
|
|
|
static char *get_next_byte( char *p, short *val )
|
|
{
|
|
*val = *p++ & 0x00ff;
|
|
return p;
|
|
}
|
|
|
|
static char *get_next_word( char *p, short *val )
|
|
{
|
|
*val = *p++;
|
|
*val <<= 8;
|
|
*val |= *p++;
|
|
return p;
|
|
}
|
|
|
|
static void __send_all(a3k_t tag, const uint8_t *p, int len)
|
|
{
|
|
int n;
|
|
|
|
while (len > 0) {
|
|
n = serial_send_buffered(tag->uart, p, len);
|
|
p += n;
|
|
len -= n;
|
|
}
|
|
}
|
|
|
|
static void fifo_putpacket(a3k_t tag, char *p)
|
|
{
|
|
int len;
|
|
|
|
len = (((short)p[1])<<8)|p[2];
|
|
len += 4;
|
|
|
|
__send_all(tag, (void *)p, len);
|
|
}
|
|
|
|
#if 0
|
|
static char __getc(a3k_t a3k)
|
|
{
|
|
char c;
|
|
|
|
while (serial_recv_buffered(a3k->uart, (void *)&c, 1) != 1)
|
|
;
|
|
return c;
|
|
}
|
|
#endif
|
|
|
|
static char __fifo_getc(FIFO *f)
|
|
{
|
|
if (f->nelem) {
|
|
char c;
|
|
c = *f->pold++;
|
|
if(f->pold == f->bend)
|
|
f->pold = f->b;
|
|
f->nelem -= 1;
|
|
return c;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
static int __getpacket(a3k_t tag, char *p)
|
|
{
|
|
short len;
|
|
short i;
|
|
uint8_t *p_save = (uint8_t *)p;
|
|
FIFO *f = &tag->rx;
|
|
|
|
p[0] = __fifo_getc(f); //get the header
|
|
p[1] = __fifo_getc(f); //get the len (msb)
|
|
p[2] = __fifo_getc(f); //get the len (lsb)
|
|
p[3] = __fifo_getc(f); //get the type
|
|
len = p[1];
|
|
len <<= 8;
|
|
len |= (p[2] & 0x00ff);
|
|
p += 4;
|
|
for ( i = 0; i < len; i++ ) {
|
|
*p++ = __fifo_getc(f);
|
|
}
|
|
|
|
printf("\r\n");
|
|
for (i = 0; i < (len + 4); ++i) {
|
|
printf("%02x ", p_save[i]);
|
|
}
|
|
printf("\r\n");
|
|
|
|
return len + 4;
|
|
}
|
|
|
|
static void put_packet(a3k_t a3k, char *packet, char *end, char type, char parity)
|
|
{
|
|
char *p = packet;
|
|
short len = end - packet - 4;
|
|
|
|
if (parity)
|
|
len += 2;
|
|
|
|
/*
|
|
* add the header, length, and type
|
|
*/
|
|
p = put_next_byte( p, PKT_HEADER );
|
|
p = put_next_word( p, len );
|
|
p = put_next_byte( p, type );
|
|
|
|
/*
|
|
* from this point on, len is the total length of the
|
|
* packet including header/len/type
|
|
*/
|
|
len += 4;
|
|
|
|
/*
|
|
* add the parity field if enabled. Note that the parity
|
|
* byte does not cover the header byte.
|
|
*/
|
|
if (parity) {
|
|
short i;
|
|
char pbyte = 0;
|
|
end = put_next_byte(end, PKT_PARITYBYTE );
|
|
for ( i = 1; i < len - 1; i++ ) {
|
|
pbyte ^= packet[i];
|
|
}
|
|
end = put_next_byte(end, pbyte );
|
|
}
|
|
|
|
fifo_putpacket(a3k, packet);
|
|
}
|
|
|
|
/*
|
|
* This function gets the next character from a fifo. It is assumed
|
|
* that the fifo contains at leas one character. If it does not the
|
|
* function returns a null character.
|
|
*/
|
|
static int __fifo_waitpacket(a3k_t tag)
|
|
{
|
|
int n, len;
|
|
char *old;
|
|
FIFO *f = &tag->rx;
|
|
uint64_t end = millis() + WAIT_TIMEOUT;
|
|
|
|
restart:
|
|
if (millis() > end) {
|
|
return -1;
|
|
}
|
|
|
|
/* try to receive from serial */
|
|
while (f->blen != f->nelem) {
|
|
len = f->bend - f->pnew;
|
|
n = serial_recv_buffered(tag->uart, (void *)f->pnew, len);
|
|
if (n > 0) {
|
|
f->pnew += n;
|
|
if (f->pnew == f->bend) {
|
|
f->pnew = f->b;
|
|
}
|
|
f->nelem += n;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
while ((f->nelem > 0) && (*f->pold != PKT_HEADER)) {
|
|
__fifo_getc(f);
|
|
}
|
|
|
|
if (*f->pold != PKT_HEADER)
|
|
goto restart;
|
|
|
|
if (f->nelem < 3)
|
|
goto restart;
|
|
|
|
old = f->pold + 1;
|
|
if (old == f->bend) {
|
|
old = f->b;
|
|
}
|
|
len = *old++;
|
|
len <<= 8;
|
|
if (old == f->bend) {
|
|
old = f->b;
|
|
}
|
|
len |= *old++;
|
|
|
|
if (f->nelem < (len + 4)) {
|
|
goto restart;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int get_packet(a3k_t a3k, char *packet)
|
|
{
|
|
#if 0
|
|
return __getpacket(a3k, packet);
|
|
#else
|
|
if (__fifo_waitpacket(a3k)) {
|
|
return 0;
|
|
}
|
|
return __getpacket(a3k, packet);
|
|
#endif
|
|
}
|
|
|
|
static int wait_a3k_ready(a3k_t tag)
|
|
{
|
|
char packet[30];
|
|
|
|
memset(packet, 0, sizeof packet);
|
|
|
|
get_packet(tag, packet);
|
|
|
|
if (packet[0] != 0x61)
|
|
return (1);
|
|
if (packet[1] != 0x0)
|
|
return (2);
|
|
if (packet[2] != 0x03)
|
|
return (3);
|
|
if(packet[3] != 0x0)
|
|
return (4);
|
|
if(packet[4] != 0x39)
|
|
return (5);
|
|
if(packet[5] != 0x2f)
|
|
return (6);
|
|
if (packet[6] != (0x3^0x39^0x2f))
|
|
return (7);
|
|
|
|
/* we should verify that it is a ready packet, but for now we do not */
|
|
return (0);
|
|
}
|
|
|
|
int get_cfg(a3k_t a3k, short * cfg0, short * cfg1, short * cfg2)
|
|
{
|
|
char packet[30];
|
|
char *p = packet+4;
|
|
short plen;
|
|
short chk_header, chk_len, chk_type, chk_field;
|
|
|
|
p = put_next_byte(p,PKT_GETCFG);
|
|
put_packet(a3k, packet, p, PKT_CONTROL, 1);
|
|
|
|
plen = get_packet(a3k,packet);
|
|
if(plen == 0)
|
|
return 1;
|
|
p = packet;
|
|
p = get_next_byte(p, &chk_header);
|
|
if(chk_header != PKT_HEADER)
|
|
return -1;
|
|
p = get_next_word(p, &chk_len);
|
|
if(chk_len != 6)
|
|
return -2;
|
|
p = get_next_byte(p,&chk_type);
|
|
if(chk_type != PKT_CONTROL)
|
|
return -3;
|
|
p = get_next_byte(p, &chk_field);
|
|
if(chk_field != PKT_GETCFG)
|
|
return -4;
|
|
p = get_next_byte(p, cfg0);
|
|
p = get_next_byte(p, cfg1);
|
|
p = get_next_byte(p, cfg2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int packet_reset_a3k(a3k_t a3k)
|
|
{
|
|
uint64_t end = millis() + 5;
|
|
|
|
gpio_clear(a3k->rst);
|
|
|
|
while (millis() < end)
|
|
;
|
|
|
|
serial_rx_buffer_clear(a3k->uart);
|
|
serial_tx_buffer_clear(a3k->uart);
|
|
|
|
gpio_set(a3k->rst);
|
|
|
|
wait_a3k_ready(a3k);
|
|
|
|
#if 1
|
|
char packet[30];
|
|
char *p = packet+4;
|
|
short cfg = (1<<13); //noise suppressor on
|
|
// short cfg0, cfg1, cfg2;
|
|
|
|
p = put_next_byte(p, PKT_RESETSOFTCFG );
|
|
cfg |= (5<<8); /* UART */
|
|
|
|
p = put_next_byte( p, 0x05); //DTX_ENABLE = 0, IF_SELECT0 = 1, IF_SELECT1 = 0, IF_SELECT2 = 1;
|
|
p = put_next_byte( p, 0);
|
|
p = put_next_byte( p, 0);
|
|
p = put_next_byte( p, 0x0D); //DTX_ENABLE = 0, IF_SELECT0 = 1, IF_SELECT1 = 0, IF_SELECT2 = 1;
|
|
p = put_next_byte( p, 0x00);
|
|
p = put_next_byte( p, 0x00);
|
|
put_packet(a3k, packet, p, PKT_CONTROL, 1);
|
|
|
|
return wait_a3k_ready(a3k);
|
|
|
|
// get_cfg(a3k, &cfg0, &cfg1, &cfg2);
|
|
#endif
|
|
}
|
|
|
|
static int config_a3k(a3k_t interface, short ratet, char input_gain, char output_gain)
|
|
{
|
|
/*
|
|
* we can modify this to put characters into a fifo instead of
|
|
* a buffer. We would then modify put_packet and get_packet
|
|
* to work with a fifo instead of a buffer. This will save
|
|
* stack space and save code. we would need to create
|
|
* fifo_putword() which puts two characters.
|
|
*/
|
|
char packet[30];
|
|
char *p = packet+4;
|
|
short chk_header, chk_len, chk_type, chk_field, chk_response_ok;
|
|
short plen;
|
|
short lowpower = 0;
|
|
|
|
if (ratet >= 0) {
|
|
p = put_next_byte( p, PKT_RATET );
|
|
p = put_next_byte( p, ratet );
|
|
}
|
|
|
|
if (input_gain != 0 || output_gain != 0) {
|
|
p = put_next_byte(p, PKT_GAIN);
|
|
p = put_next_byte(p, input_gain);
|
|
p = put_next_byte(p, output_gain);
|
|
}
|
|
|
|
p = put_next_byte( p, PKT_LOWPOWER );
|
|
p = put_next_byte( p, lowpower );
|
|
p = put_next_byte( p, PKT_INIT );
|
|
p = put_next_byte( p, PKT_INIT_ENCODER|PKT_INIT_DECODER );
|
|
|
|
put_packet(interface, packet, p, PKT_CONTROL, 1);
|
|
|
|
//we expect a 9 byte response packet
|
|
plen = get_packet(interface, packet);
|
|
if (plen == 0) {
|
|
return 1;
|
|
}
|
|
|
|
p = packet;
|
|
p = get_next_byte( p, &chk_header );
|
|
if (chk_header != PKT_HEADER)
|
|
return -1;
|
|
|
|
p = get_next_word( p, &chk_len );
|
|
if (ratet >= 0) {
|
|
if (input_gain != 0 || output_gain != 0) {
|
|
if (chk_len != 6 + 4)
|
|
return -2;
|
|
} else {
|
|
if (chk_len != 6+2)
|
|
return -2;
|
|
}
|
|
} else {
|
|
if (input_gain != 0 || output_gain != 0) {
|
|
if (chk_len != (6 + 2))
|
|
return -2;
|
|
} else {
|
|
if (chk_len != 6)
|
|
return -2;
|
|
}
|
|
}
|
|
|
|
p = get_next_byte( p, &chk_type );
|
|
if (chk_type != PKT_CONTROL)
|
|
return -3;
|
|
|
|
if (ratet >= 0) {
|
|
p = get_next_byte( p, &chk_field);
|
|
if (chk_field != PKT_RATET)
|
|
return -4;
|
|
p = get_next_byte( p, &chk_response_ok);
|
|
if (chk_response_ok != PKT_RESPONSE_OK)
|
|
return -5;
|
|
}
|
|
|
|
if (input_gain != 0 || output_gain != 0) {
|
|
p = get_next_byte(p, &chk_field);
|
|
if (chk_field != PKT_GAIN) {
|
|
return -6;
|
|
}
|
|
p = get_next_byte(p, &chk_response_ok);
|
|
if (chk_response_ok != PKT_RESPONSE_OK)
|
|
return -7;
|
|
}
|
|
|
|
p = get_next_byte( p, &chk_field);
|
|
if (chk_field != PKT_LOWPOWER)
|
|
return -8;
|
|
p = get_next_byte( p, &chk_response_ok);
|
|
if (chk_response_ok != PKT_RESPONSE_OK)
|
|
return -9;
|
|
|
|
p = get_next_byte( p, &chk_field);
|
|
if (chk_field != PKT_INIT)
|
|
return -10;
|
|
p = get_next_byte( p, &chk_response_ok);
|
|
if (chk_response_ok != PKT_RESPONSE_OK)
|
|
return -11;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int config_a3k_codec(a3k_t interface )
|
|
{
|
|
char packet[128];
|
|
char *p = packet+4;
|
|
short plen;
|
|
short INPUT_GAIN;
|
|
short INPUT_SEL;
|
|
short ADCGAIN, DACGAIN;
|
|
|
|
INPUT_GAIN = 0x3;
|
|
// INPUT_GAIN = 0x3b; // mute,24db
|
|
|
|
INPUT_SEL = 0x2;
|
|
|
|
ADCGAIN = 0x3e; //20 dB
|
|
// ADCGAIN = 0x2A; //0 dB
|
|
|
|
DACGAIN = 0x7e; //20db
|
|
// DACGAIN = 0x74; //0db
|
|
#if 0
|
|
/*
|
|
* there is two ways to set up the codec. This is the first
|
|
* method. Use PKT_CODECCFG to specify what control registers
|
|
* to change and the new values. Then later they will be
|
|
* sent to the codec when the PKT_CODECSTART is sent.
|
|
*/
|
|
p = put_next_byte( p, PKT_CODECCFG );
|
|
p = put_next_byte( p, 6 );
|
|
p = put_next_word (p, (2<<8)| (1<<7)|(4<<3)); // set TURBO=1 (SCLK=MCLK/P), keep I2C addr=4
|
|
p = put_next_word (p, (1<<8)| 1|(1<<6) /*|(1<<5)*/ ); // set 16 bit DAC mode, set continuous data transfer mode
|
|
p = put_next_word (p, (4<<8)| 0x80|3); // set M=3
|
|
p = put_next_word (p, (5<<8)| ADCGAIN );
|
|
p = put_next_word (p, (5<<8)| 0x80|(7<<3)| INPUT_GAIN); // sidetone=MUTE / INPUT GAIN = 24dB ==> 0x3
|
|
p = put_next_word (p, (6<<8)| (INPUT_SEL<<1)); // set input LINE IN = 0x6 MIC = 0x2
|
|
#else
|
|
/*
|
|
* For the second method, use PKT_CODECCFG to specify that 0
|
|
* registers are configured by PKT_CODECSTART. Then use
|
|
* PKT_SETCODECRESET to take the codec out of reset. Use
|
|
* PKT_DELAYNUS to insert delay, then use PKT_WRITEI2C
|
|
* repeatedly to generate i2c writes. This sets up the AIC14,
|
|
* later when PKT_CODECSTART is received, it will not try to
|
|
* reconfigure the aic14. All it does is enable the codec
|
|
* interface of the a3k without configuring the aic14 first.
|
|
* Either method works. This method is more generic.
|
|
*/
|
|
p = put_next_byte( p, PKT_CODECCFG );
|
|
p = put_next_byte( p, 0 );
|
|
|
|
p = put_next_byte( p, PKT_SETCODECRESET );
|
|
|
|
p = put_next_byte( p, PKT_DELAYNUS );
|
|
p = put_next_word( p, 10 );
|
|
|
|
#define PKT_WRITEREG( p, reg, val ) p = put_next_byte( p, PKT_WRITEI2C ); p = put_next_byte( p, 3 ); p = put_next_byte( p, 0x80 ); p = put_next_byte( p, reg ); p = put_next_byte( p, val )
|
|
|
|
PKT_WRITEREG (p, 2, (1<<7)|(4<<3)); // set TURBO=1 (SCLK=MCLK/P), keep I2C addr=4
|
|
PKT_WRITEREG (p, 1, 1|(1<<6) /*|(1<<5)*/); // set 16 bit DAC mode, set continuous data transfer mode
|
|
PKT_WRITEREG (p, 4, 0x8A);
|
|
PKT_WRITEREG (p, 4, (0x10));
|
|
PKT_WRITEREG (p, 5, ADCGAIN);
|
|
PKT_WRITEREG (p, 5, DACGAIN);
|
|
PKT_WRITEREG (p, 5, 0x80|(7<<3)| INPUT_GAIN); // sidetone=MUTE / INPUT GAIN = 24dB ==> 0x3
|
|
PKT_WRITEREG (p, 6, (INPUT_SEL<<1)); // set input LINE IN = 0x6 MIC = 0x2
|
|
#endif
|
|
p = put_next_byte( p, PKT_DISCARDNCODEC );
|
|
p = put_next_word( p, 128 ); //tell the a3k to discard the first 128 codec samples, output 0
|
|
|
|
//final delay will delay response packet which puts some time
|
|
//between config_a3k_codec and start_a3k_codec.
|
|
p = put_next_byte( p, PKT_DELAYNUS );
|
|
p = put_next_word( p, 10 );
|
|
|
|
put_packet(interface, packet, p, PKT_CONTROL, 1);
|
|
|
|
//we expect a 9 byte response packet
|
|
plen = get_packet(interface, packet);
|
|
if (plen == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int start_a3k_codec(a3k_t interface, short skew, short passthru, short codecif)
|
|
{
|
|
char packet[30];
|
|
char *p = packet+4;
|
|
short chk_header, chk_len, chk_type, chk_field, chk_response_ok;
|
|
short plen;
|
|
|
|
p = put_next_byte( p, PKT_STARTCODEC );
|
|
p = put_next_byte( p, (skew & 1) | ((passthru & 1)<<1) | ((codecif & 1)<<2) );
|
|
put_packet(interface, packet, p, PKT_CONTROL, 1);
|
|
|
|
plen = get_packet(interface, packet);
|
|
if (plen == 0)
|
|
return 1;
|
|
|
|
p = packet;
|
|
p = get_next_byte( p, &chk_header );
|
|
if (chk_header != PKT_HEADER)
|
|
return -1;
|
|
p = get_next_word( p, &chk_len );
|
|
if (chk_len != 4)
|
|
return -2;
|
|
p = get_next_byte( p, &chk_type );
|
|
if (chk_type != PKT_CONTROL)
|
|
return -3;
|
|
p = get_next_byte( p, &chk_field);
|
|
if (chk_field != PKT_STARTCODEC)
|
|
return -12;
|
|
p = get_next_byte( p, &chk_response_ok);
|
|
if (chk_response_ok != PKT_RESPONSE_OK)
|
|
return -13;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __attribute__((unused)) stop_a3k_codec(a3k_t interface)
|
|
{
|
|
char packet[30];
|
|
char *p = packet+4;
|
|
short chk_header, chk_len, chk_type, chk_field, chk_response_ok;
|
|
short plen;
|
|
|
|
p = put_next_byte( p, PKT_STOPCODEC );
|
|
put_packet(interface, packet, p, PKT_CONTROL, 1);
|
|
|
|
plen = get_packet(interface, packet);
|
|
if (plen == 0)
|
|
return 1;
|
|
|
|
p = packet;
|
|
p = get_next_byte( p, &chk_header );
|
|
if (chk_header != PKT_HEADER)
|
|
return -1;
|
|
p = get_next_word( p, &chk_len );
|
|
if (chk_len != 4)
|
|
return -2;
|
|
p = get_next_byte( p, &chk_type );
|
|
if (chk_type != PKT_CONTROL)
|
|
return -3;
|
|
p = get_next_byte( p, &chk_field);
|
|
if (chk_field != PKT_STARTCODEC)
|
|
return -12;
|
|
p = get_next_byte( p, &chk_response_ok);
|
|
if (chk_response_ok != PKT_RESPONSE_OK)
|
|
return -13;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void pins_set(a3k_t tag, int rate, int ec, int ns, int es)
|
|
{
|
|
gpio_write(tag->rate[0], (0x01 & rate));
|
|
gpio_write(tag->rate[1], (0x02 & rate));
|
|
gpio_write(tag->rate[2], (0x04 & rate));
|
|
gpio_write(tag->rate[3], (0x08 & rate));
|
|
gpio_write(tag->rate[4], (0x10 & rate));
|
|
gpio_write(tag->rate[5], (0x20 & rate));
|
|
|
|
gpio_write(tag->ec, ec);
|
|
gpio_write(tag->ns, ns);
|
|
gpio_write(tag->es, es);
|
|
}
|
|
|
|
void read_cfg(a3k_t tag)
|
|
{
|
|
char packet[10];
|
|
char *p = packet + 4;
|
|
|
|
p = put_next_byte(p, 0x37);
|
|
|
|
put_packet(tag, packet, p, PKT_CONTROL, 1);
|
|
|
|
get_packet(tag, packet);
|
|
}
|
|
|
|
static void __fifo_init(FIFO *f, short blen, char *b)
|
|
{
|
|
f->pnew = f->pold = b;
|
|
f->blen = blen;
|
|
f->bend = b + blen;
|
|
f->b = b;
|
|
f->nelem = 0;
|
|
}
|
|
|
|
/*
|
|
* This function does not take anything out of the fifo. It assumes
|
|
* that there is a complete packet in the fifo (or at least the
|
|
* header/length/type). It just looks at the 4th byte which is the
|
|
* type byte and returns it. In the event that the fifo does not
|
|
* contain at least 4 bytes, it returns 0x0ff.
|
|
*/
|
|
int a3k_peekpackettype(a3k_t tag)
|
|
{
|
|
FIFO *f = &tag->rx;
|
|
char i;
|
|
char c;
|
|
volatile char *old = f->pold;
|
|
for ( i = 0; i < 4; i++ ) {
|
|
c = *old++;
|
|
if (old == f->bend)
|
|
old = f->b;
|
|
}
|
|
/*
|
|
* just return the forth byte. Note that nelem wasn't
|
|
* decremented and the fifo pointers are unchanged.
|
|
* This function peeked into the fifo without changing
|
|
* it.
|
|
*/
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
* this function discards a packet from the fifo.
|
|
*/
|
|
void a3k_discardpacket(a3k_t tag)
|
|
{
|
|
FIFO *f = &tag->rx;
|
|
/*
|
|
* one we get len we can just subtract len+1 from elem and
|
|
* then do a circular wrap around of the fifo pointer.
|
|
* for now i discard characters one at a time.
|
|
*/
|
|
char c;
|
|
short len;
|
|
short i;
|
|
|
|
__fifo_getc(f);
|
|
c = __fifo_getc(f);
|
|
len = c;
|
|
len <<= 8;
|
|
c = __fifo_getc( f );
|
|
len |= (c & 0x00ff);
|
|
len++; //dont forget the type byte
|
|
for ( i = 0; i < len; i++ ) {
|
|
__fifo_getc( f );
|
|
}
|
|
}
|
|
|
|
int a3k_getpacket(a3k_t tag, uint8_t *buf, int size)
|
|
{
|
|
char c;
|
|
int i = 0, x, len;
|
|
FIFO *f = &tag->rx;
|
|
|
|
buf[i++] = __fifo_getc(f);
|
|
c = __fifo_getc(f);
|
|
buf[i++] = c;
|
|
len = (c << 8);
|
|
c = __fifo_getc(f);
|
|
buf[i++] = c;
|
|
len |= (c & 0xff);
|
|
|
|
++len; // dont forget the type byte
|
|
for (x = 0; x < len && x < (size - 4); ++x) {
|
|
buf[i++] = __fifo_getc(f);
|
|
}
|
|
|
|
while (x < len) { /* drop */
|
|
__fifo_getc(f);
|
|
++x;
|
|
}
|
|
|
|
return (len + 3);
|
|
}
|
|
|
|
int a3k_get_rawpacket(a3k_t tag, uint8_t *buf, int size)
|
|
{
|
|
uint8_t c;
|
|
int n = 0, len;
|
|
FIFO *f = &tag->rx;
|
|
|
|
__fifo_getc(f); /* drop 0x61 */
|
|
c = __fifo_getc(f); /* len (MSB) */
|
|
len = (c << 8) | (__fifo_getc(f) & 0xff); /* len (LSB) */
|
|
__fifo_getc(f); /* drop type */
|
|
c = __fifo_getc(f); /* drop CHAND field */
|
|
assert(c == 1);
|
|
c = __fifo_getc(f); /* CHANAD bits */
|
|
c /= 8; /* to bytes */
|
|
for (n = 0; n < c && n < size; ++n) {
|
|
buf[n] = __fifo_getc(f);
|
|
}
|
|
len -= n;
|
|
while (len > 0) { /* drop 0x2f, parity, etc ... */
|
|
__fifo_getc(f);
|
|
}
|
|
return (n);
|
|
}
|
|
|
|
int a3k_putpacket(a3k_t tag, const void *_ptr, int len)
|
|
{
|
|
__send_all(tag, _ptr, len);
|
|
return (len);
|
|
}
|
|
|
|
/*
|
|
* This function just checks the fifo without modifying it, unless it
|
|
* discovers that the header is missing. When the fifo is missing
|
|
* the header all data is discarded until a header is found.
|
|
*/
|
|
int a3k_checkfullpacket(a3k_t tag)
|
|
{
|
|
FIFO *f = &tag->rx;
|
|
int len, n;
|
|
char *old;
|
|
|
|
start:
|
|
/* try to receive from serial */
|
|
while (f->blen != f->nelem) {
|
|
len = f->bend - f->pnew;
|
|
n = serial_recv_buffered(tag->uart, (void *)f->pnew, len);
|
|
if (n > 0) {
|
|
f->pnew += n;
|
|
if (f->pnew == f->bend) {
|
|
f->pnew = f->b;
|
|
}
|
|
f->nelem += n;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* if there is a character in the fifo and it is not
|
|
* a header byte then discard it. Keep going as
|
|
* long as there are still bytes in the fifo. if a packet
|
|
* with bad parity is received it is discarded.
|
|
*/
|
|
while ((f->nelem > 0) && ( *f->pold != PKT_HEADER )) {
|
|
__fifo_getc(f);
|
|
}
|
|
|
|
/*
|
|
* now we are either out of characters in the fifo
|
|
* or the first character is a header byte. If we
|
|
* dont have at least the header byte and the two
|
|
* len bytes yet, then just return.
|
|
*/
|
|
if (f->nelem < 3)
|
|
return 0;
|
|
|
|
/*
|
|
* we now have the header and two len bytes in the
|
|
* fifo.
|
|
*/
|
|
old = f->pold + 1;
|
|
|
|
if (old == f->bend)
|
|
old = f->b;
|
|
|
|
len = *old++;
|
|
len <<= 8;
|
|
if (old == f->bend)
|
|
old = f->b;
|
|
len |= *old++;
|
|
if (len > 340) {
|
|
__fifo_getc(f);
|
|
goto start;
|
|
}
|
|
if (f->nelem >= len+4) {
|
|
/*
|
|
* we now have received a full packet. We will
|
|
* check its parity. if the parity is bad then
|
|
* we will discard the packet, and return 0.
|
|
* If the packet is good then we will return 1.
|
|
*/
|
|
short i;
|
|
char parity = 0;
|
|
|
|
parity ^= ((len >> 8) & 0x00ff);
|
|
parity ^= (len & 0x00ff);
|
|
|
|
if (old == f->bend)
|
|
old = f->b;
|
|
|
|
for(i=0;i<len+1;i++) {
|
|
parity ^= *old++;
|
|
if (old == f->bend)
|
|
old = f->b;
|
|
}
|
|
if (parity == 0)
|
|
return 1; /* we have a full packet with good parity check */
|
|
else {
|
|
a3k_discardpacket(tag);
|
|
return 0;
|
|
}
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
int a3k_setup(a3k_t tag, int baudrate)
|
|
{
|
|
int err = 0;
|
|
#ifdef STM32F429_439xx
|
|
int i;
|
|
#endif
|
|
|
|
__fifo_init(&tag->rx, FORMAT3KBLEN, (void *)tag->_buf);
|
|
|
|
if (baudrate < 0) {
|
|
baudrate = A3K_UART_BAUDRATE;
|
|
}
|
|
|
|
serial_setup(tag->uart, baudrate, 8, SERIAL_STOPBITS_1);
|
|
|
|
if (tag->pseudo) {
|
|
return 0;
|
|
}
|
|
|
|
#ifdef STM32F429_439xx
|
|
gpio_init(tag->rst, GPIO_OUTPUT | GPIO_FLAG_PP | GPIO_FLAG_PU);
|
|
gpio_init(tag->rts, GPIO_INPUT | GPIO_FLAG_PP | GPIO_FLAG_PU | GPIO_SPEED_FAST);
|
|
|
|
gpio_init(tag->ec, GPIO_OUTPUT);
|
|
gpio_init(tag->ns, GPIO_OUTPUT);
|
|
gpio_init(tag->es, GPIO_OUTPUT);
|
|
|
|
for (i = 0; i < RATE_PINS; ++i) {
|
|
gpio_init(tag->rate[i], GPIO_OUTPUT);
|
|
}
|
|
|
|
pins_set(tag, 0x2c, 0, 1, 0); //ec, ns, es
|
|
#endif
|
|
|
|
if (packet_reset_a3k(tag)) {
|
|
printf("reset a3k failed.\r\n");
|
|
err = -1;
|
|
goto tail;
|
|
}
|
|
/*
|
|
if (stop_a3k_codec(tag)) {
|
|
printf("stop codec failed.\r\n");
|
|
}
|
|
*/
|
|
if (config_a3k(tag, -1, 0, 0)) { /* ratet, input_gain, output_gain */
|
|
printf("config a3k failed.\r\n");
|
|
err = -2;
|
|
goto tail;
|
|
}
|
|
|
|
if (config_a3k_codec(tag)) {
|
|
printf("config a3k codec failed.\r\n");
|
|
err = -3;
|
|
goto tail;
|
|
}
|
|
|
|
// read_cfg(tag);
|
|
|
|
if (start_a3k_codec(tag, 0, 0, 0)) {
|
|
printf("start a3k codec mode failed.\r\n");
|
|
err = -4;
|
|
goto tail;
|
|
}
|
|
|
|
tail:
|
|
return err;
|
|
}
|
|
|
|
void a3k_close(a3k_t tag)
|
|
{
|
|
if (!tag->pseudo) {
|
|
packet_reset_a3k(tag);
|
|
}
|
|
serial_close(tag->uart);
|
|
}
|
|
|
|
#if (TARGET_HAS_A3K_0)
|
|
struct a3k_tag a3k0 = {
|
|
.uart = &serial1,
|
|
.rst = PF10,
|
|
.rts = PG7,
|
|
|
|
.pseudo = 0,
|
|
|
|
.rate = {PB0, PC4, PC5, PC3, PC0, PC1},
|
|
.ec = PC2,
|
|
.ns = PJ15,
|
|
.es = PG12,
|
|
};
|
|
#endif
|
|
|
|
#if TARGET_HAS_A3K_1
|
|
struct a3k_tag a3k1 = {
|
|
.uart = &serial2,
|
|
.rst = PI14,
|
|
.rts = PK2,
|
|
|
|
.pseudo = 0,
|
|
|
|
.rate = {PJ4, PJ13, PJ14, PK3, PG10, PK4},
|
|
.ec = PI15,
|
|
.ns = PJ12,
|
|
.es = PH4,
|
|
};
|
|
#endif
|
|
|
|
#if TARGET_HAS_A3K_2
|
|
struct a3k_tag a3k2 = {
|
|
.uart = &serial3,
|
|
.pseudo = 1,
|
|
};
|
|
#endif
|
|
|
|
#if TARGET_HAS_A3K_3
|
|
struct a3k_tag a3k3 = {
|
|
.uart = &serial5,
|
|
.pseudo = 1,
|
|
};
|
|
#endif
|
|
|
|
|