/* This file is quasi the same as masDriver_Demand.c The main diffence holds in the protocol used : here to PC is sensed to send data continously, just receiving message about buffer state, and modulating the throwput by this way. But there's some difficulties to do that. The comments about the methods are placed in the masDriver_Demand.c file */ /* ------------------------------------------------------------------------- * includes * ------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------------- * defines * ------------------------------------------------------------------------- */ #define USE_SERIAL #define DEBUG_MODE /* ----------- atmel128 I2C response codes : values that can take the register TWSR after sending a I2C command ----------- */ #define I2C_STATUS_MASK 0xF8 #define I2C_START_TRANSMITTED 0x08 #define I2C_REP_START_TRANSMITTED 0x10 #define I2C_SLA_W_TRANSMITTED_W_ACK 0x18 #define I2C_SLA_W_TRANSMITTED_NO_ACK 0x20 #define I2C_DATA_BYTE_TRANSMITTED_W_ACK 0x28 #define I2C_DATA_BYTE_TRANSMITTED_NO_ACK 0x30 #define I2C_ARBITRATION_LOST 0x38 // not used #define I2C_SLA_R_TRANSMITTED_W_ACK 0x40 #define I2C_SLA_R_TRANSMITTED_NO_ACK 0x48 #define I2C_DATA_BYTE_RECEIVED_W_ACK 0x50 #define I2C_DATA_BYTE_RECEIVED_NO_ACK 0x58 /* ----------- MAS 3587F dependent data : mostly I2C codes ----------- */ // main I2C device adress #define DW 0x3c #define DR 0x3d // adresses to write or read the DSP memory and registers #define DATA_WRITE 0x68 #define DATA_READ 0x69 // adresses to write or read the codec register #define CODEC_WRITE 0x6c #define CODEC_READ 0x6d // adresses of the direct configuration registers #define CONTROL_REG 0x6a #define DCCF_REG 0x76 #define FIRST_DCDC_CONFIGURATION_REGISTER DCCF_REG #define DCFR_REG 0x77 #define SECOND_DCDC_CONFIGURATION_REGISTER DCFR_REG // commands for DCDC configuration register #define DCCF_REG_RESET 0x5050 #define DCFR_REG_RESET 0x0000 // commands for control register #define CTRL_REG_RESET_NODC 0x0000 #define CTRL_REG_DSP_ON_NODC 0x0400 #define CTRL_REG_BOTH_ON_NODC 0x0C00 // adresses of the differents memory cells #define APPSELECT 0x07F6 #define APPRUNNING 0x07F7 #define ENCODERCONTROL 0x07F0 #define IOCONTROLMAIN 0x07F1 #define INTERFACECONTROL 0x07F2 #define OUTCLKCONFIG 0x07F4 #define SPDOUTBITS 0x07F8 #define SOFTMUTE 0x07F9 #define OUT_LL 0x07FC #define OUT_LR 0x07FD #define OUT_RL 0x07FE #define OUT_RR 0x07FF // values for the AppSelect memory cell (D0:7F6) #define APPSELECT_MEM_BOTH_DECODE 0x0c #define APPSELECT_MEM_LAYER2_DECODE 0x04 #define APPSELECT_MEM_LAYER3_DECODE 0x03 #define APPSELECT_MEM_ENCODE 0x20 // values for the IOControlMain memory cell (DO:7F1) #define IOCTRL_MEM_INVERT_SOC (1 << 14) #define IOCTRL_MEM_INSERT_TIMECODE (1 << 12) #define IOCTRL_MEM_OUTPUT_DELAY (1 << 11) #define IOCTRL_MEM_LOOP_THROUGH (1 << 10) #define IOCTRL_MEM_ENCODE_SDI_INPUT_NOPLL (1 << 8) #define IOCTRL_MEM_ENCODE_SPDIF_INPUT (1 << 9) #define IOCTRL_MEM_DECODE_INPUT_PIO (1 << 8) #define IOCTRL_MEM_DECODE_INPUT_SIDB 0 #define IOCTRL_MEM_INVERT_SIC (1 << 7) #define IOCTRL_MEM_INPUT_DELAY (1 << 6) #define IOCTRL_MEM_WORD_STROBE_SDO_INVERT (1 << 5) #define IOCTRL_MEM_SDO_16BITS_SAMPLE (1 << 4) #define IOCTRL_MEM_CLOCK_SETTING_MPEG2 (1 << 3) #define IOCTRL_MEM_DECODE_SIBC_INVERT (1 << 2) #define IOCTRL_MEM_ENCODE_SDI_STROBE_INVERT (1 << 2) #define IOCTRL_MEM_BROADCASTMODE (1 << 1) #define IOCTRL_MEM_VALIDATE 1 #define IOCTRL_MEM_STANDARD_IN_PIO 0x125 #define IOCTRL_MEM_STANDARD_IN_SERIAL 0x25 // values fot the InterfaceControl memory cell (DO:7F2) #define INTCTRL_MEM_SPDIF2 (1 << 6) #define INTCTRL_MEM_SPDIF_DISABLE (1 << 5) #define INTCTRL_MEM_SDO_DISABLE (1 << 3) #define INTCTRL_MEM_CLOCK_HIGH_IMPEDANCE (1 << 2) #define INTCTRL_MEM_SDI_SOURCE_AD 1 #define INTCTRL_MEM_STANDARD 0x0004 // values for the OutClkCOnfig memory cell (D0:7F4) #define OUTCLKCONFIG_MEM_STANDARD 0x00080000 // values for the SoftMute memory cell (D0:7F9) #define MUTE_MEM_BITRESERVOIR_EMPTY (1 << 2) #define MUTE_MEM_PAUSE (1 << 1) #define MUTE_MEM_MUTE 1 // values for the OUT_LL - OUT_RR - OUT_RL - OUTLR register #define OUT_RR_STEREO 0x00080000 #define OUT_LL_STEREO 0x00080000 #define OUT_RL_STEREO 0x00000000 #define OUT_LR_STEREO 0x00000000 #define OUT_RR_LEFTMONO 0x00000000 #define OUT_LL_LEFTMONO 0x00080000 #define OUT_RL_LEFTMONO 0x00000000 #define OUT_LR_LEFTMONO 0x00080000 #define OUT_RR_RIGHTMONO 0x00080000 #define OUT_LL_RIGHTMONO 0x00000000 #define OUT_RL_RIGHTMONO 0x00080000 #define OUT_LR_RIGHTMONO 0x00000000 // adresses for the codec configuration registers #define CONV_CONF 0x0000 #define ADC_IN_MODE 0x0008 #define DAC_IN_ADC 0x0006 #define DAC_IN_DSP 0x0007 #define DAC_OUT_MODE 0x000e #define BASS 0x0014 #define TREBLE 0x0015 #define LOUDNESS 0x001e #define BALANCE 0x0011 #define VOLUME 0x0010 // standard values for the codec configuration registers #define CONV_CONF_LINE_IN 0x2207 #define CONV_CONF_MIC_IN 0x220F #define ADC_IN_MONO 0x8000 #define ADC_IN_STEREO 0x0000 #define DAC_IN_NO_VOLUME 0x0000 #define DAC_IN_50_PERCENT 0x2000 #define DAC_IN_100_PERCENT 0x4000 #define DAC_IN_MAX 0x7f00 #define BALANCE_FULL_RIGHT 0x7f00 #define BALANCE_HALF_RIGHT 0x3f00 #define BALANCE_FULL_LEFT 0x8000 #define BALANCE_HALF_LEFT 0x4000 #define BALANCE_MEDIUM 0x0000 #define VOLUME_MAX 0x7f00 #define VOLUME_STANDARD 0x6000 #define VOLUME_HALF 0x3f00 #define VOLUME_MUTE 0x0000 /* ----------- various defines : ----------- */ #define LED_PORT PORTB #define LED_PORT_DDR DDRB #define CONTROL_PORT PORTB #define CONTROL_PORT_DDR DDRB #define MSB_PIO_PORT PORTE #define MSB_PIO_PORT_DDR DDRE #define LSB_PIO_PORT PORTF #define LSB_PIO_PORT_DDR DDRF #define EOD PIN0 // PB0 #define PR PIN3 // PB3 #define RTR PIN1 // PB1 #define PCS PIN2 // PB2 #define PI19 PIN7 // PE7 #define PI18 PIN6 // PE6 #define PI17 PIN5 // PE5 #define PI16 PIN3 // PE3 #define PI15 PIN4 // PF4 #define PI14 PIN5 // PF5 #define PI13 PIN6 // PF6 #define PI12 PIN7 // PF7 #define LED0 4 #define LED1 5 #define LED2 6 #define LED3 7 #define L2CAP_BUF_LEN 16 #define PACKET_SIZE 650 #define MP3_BUFFER_START_ADDR 0x1100 #define MP3_BUFFER_END_ADDR 0xFFFF #define MP3_BUFFER_LENGTH 0xEEFF #define DATA_ACK_EVENT 192 #define FILE_TRANSFER_DONE_EVENT 193 #define PLAY_EVENT 194 #define PROCEED_COMMAND_EVENT 195 #define BUFFER_PLACE_THRESHOLD 0x1800 // in byte : 6KB #define BUFFER_CRITICAL_THRESHOLD 0x800 // in byte = 2KB #define BUFFER_LOW_THRESHOLD 0x3000 // in bytes = 12 KB #define NMORE "nMORE" struct Demand_struct { u8 tag; u32 time; struct Demand_struct* next; struct Demand_struct* previous; }; typedef struct Demand_struct demand; /* ------------------------------------------------------------------------- * globals * ------------------------------------------------------------------------- */ //u8 pc_addr[6] = { (u8)0x00, (u8)0x02, (u8)0x72, (u8)0x01, (u8)0x77, (u8)0xf5 }; u8 pc_addr[6] = { (u8)0xf5, (u8)0x77, (u8)0x01, (u8)0x72, (u8)0x02, (u8)0x00 }; l2cap_data_buffer_elem_t data_buf[L2CAP_BUF_LEN]; u8 * read_pointer; u8 * write_pointer; u16 quantity_received; u8 more[3] = "nM"; #ifdef USE_SERIAL u8 serial_mask; #endif u8 p_n; u32 microsec; u8 bufferFilling; // used as boolean u8 cid; u8 endOfFile; // used as boolean u8 firstTransfer; // used as boolean u8 demandOnProcess; // used as boolean u8 bufferLow = 0; // used as boolean u8 bufferCritical = 0; // used as boolean /* ------------------------------------------------------------------------- * methods * ------------------------------------------------------------------------- */ void wait(u16 microseconds) { u16 j; for (j = 0 ; j < microseconds; j++) { asm volatile("nop"); } } /*-----------------------------------------------------------------------*/ void wait32(u32 microseconds) { u32 j; for (j = 0 ; j < microseconds; j++) { asm volatile("nop"); } } /*-----------------------------------------------------------------------*/ void resetMAS(void) { // reset MAS3587 sbi(DDRD, PIN7); cbi(PORTD, PIN7); wait(200); sbi(PORTD, PIN7); wait(1000); } /*-----------------------------------------------------------------------*/ void setLed(int i) { i = i + 3; sbi(LED_PORT, i); } /*-----------------------------------------------------------------------*/ void unsetLed(int i) { i = i + 3; cbi(LED_PORT, i); } /*-----------------------------------------------------------------------*/ void led_init(void) { sbi( LED_PORT_DDR, LED0 ); sbi( LED_PORT_DDR, LED1 ); sbi( LED_PORT_DDR, LED2 ); sbi( LED_PORT_DDR, LED3 ); cbi( LED_PORT, LED0 ); cbi( LED_PORT, LED1 ); cbi( LED_PORT, LED2 ); cbi( LED_PORT, LED3 ); } /*-----------------------------------------------------------------------*/ void I2C_init(void) { printf("Configuring I2C channel..."); // spec page 196: i2c speed // init SCL frequency // 100 kHz regular, 400 kHz fast // clock speed: 7.3728 MHz // 100 kHz = 7.3728 MHz / (16 + 2 x TWBR) x 4 ^ TWPS // regular: TWSR = 1, TWBR = 7 // set i2c speed // it's written in doc that TWBR >= 10 outp( (u8)10, TWBR ); outp( BV(TWPS0), TWSR ); // outp(SLAVE_ADDRESS << 1 | 1, TWAR); // enable TWI outp(BV(TWEN), TWCR); printf("done" NL); } /*-----------------------------------------------------------------------*/ int I2C_startCond(void) { unsigned char status; // write start condition outp(BV(TWINT) | BV(TWSTA) | BV(TWEN), TWCR); // wait until TWINT flag is set while (!(inp(TWCR) & BV(TWINT))); status = inp(TWSR); if ((status & I2C_STATUS_MASK) != I2C_START_TRANSMITTED) { return -1; } return 0; } /*-----------------------------------------------------------------------*/ int I2C_repStartCond() { unsigned char status; // write start condition outp(BV(TWINT) | BV(TWSTA) | BV(TWEN), TWCR); // wait until TWINT flag is set while (!(inp(TWCR) & BV(TWINT))); status = inp(TWSR); if ((status & I2C_STATUS_MASK) != I2C_REP_START_TRANSMITTED) { return -1; } return 0; } /*-----------------------------------------------------------------------*/ int I2C_stopCond() { // write stop condition outp(BV(TWINT) | BV(TWSTO) | BV(TWEN), TWCR); while (!(inp(TWCR) & BV(TWSTO))); return 0; } /*-----------------------------------------------------------------------*/ int I2C_writeByte(u8 byte) { unsigned char status; outp(byte, TWDR); // load the data that we want to transmit outp(BV(TWINT) | BV(TWEN), TWCR); // start transmission // wait until TWINT flag is set while (!(inp(TWCR) & BV(TWINT))); status = inp(TWSR); status &= I2C_STATUS_MASK; if (!(status == I2C_SLA_W_TRANSMITTED_W_ACK || I2C_DATA_BYTE_TRANSMITTED_W_ACK || status == I2C_SLA_R_TRANSMITTED_W_ACK)) { return -1; } return 0; } /*-----------------------------------------------------------------------*/ int I2C_readByte(u8 * result, bool last) { unsigned char status; // for the last byte to read, a NOACK must be send if (last) { outp(BV(TWINT) | BV(TWEN), TWCR); while (!(inp(TWCR) & BV(TWINT))); *result = inp(TWDR); status = inp(TWSR); status &= I2C_STATUS_MASK; if (status != I2C_DATA_BYTE_RECEIVED_NO_ACK) { return -1; } return 0; } else { outp(BV(TWINT) | BV(TWEN) | BV(TWEA), TWCR); while (!(inp(TWCR) & BV(TWINT))); *result = inp(TWDR); status = inp(TWSR); status &= I2C_STATUS_MASK; if (status != I2C_DATA_BYTE_RECEIVED_W_ACK) { return -1; } return 0; } } /*-----------------------------------------------------------------------*/ int writeControlRegister(u16 data) { // OK int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(CONTROL_REG) || I2C_writeByte((u8)(data >> 8)) || // left part I2C_writeByte((u8)(data & 0xFF)) || // right part I2C_stopCond() ); wait(1000); return ret; } /*-----------------------------------------------------------------------*/ int readControlRegister(u16 * data) { // OK u8 result1, result2; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(CONTROL_REG) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,1) || I2C_stopCond() ); *data = result2; *data |= ((u16)result1 << 8); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int writeFirstDCDCconfigurationRegister(u16 data) { // OK int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(FIRST_DCDC_CONFIGURATION_REGISTER) || I2C_writeByte((u8)(data >> 8)) || // left part I2C_writeByte((u8)(data & 0xFF)) || // right part I2C_stopCond() ); wait(1000); return ret; } /*-----------------------------------------------------------------------*/ int readFirstDCDCconfigurationRegister(u16 * data) { // OK u8 result1, result2; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(FIRST_DCDC_CONFIGURATION_REGISTER) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,1) || I2C_stopCond() ); *data = result2; *data |= ((u16)result1 << 8); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int writeSecondDCDCconfigurationRegister(u16 data) { // OK int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(SECOND_DCDC_CONFIGURATION_REGISTER) || I2C_writeByte((u8)(data >> 8)) || // left part I2C_writeByte((u8)(data & 0xFF)) || // right part I2C_stopCond() ); wait(1000); return ret; } /*-----------------------------------------------------------------------*/ int readSecondDCDCconfigurationRegister(u16 * data) { // OK u8 result1, result2; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(SECOND_DCDC_CONFIGURATION_REGISTER) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,1) || I2C_stopCond() ); *data = result2; *data |= ((u16)result1 << 8); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int writeMemoryD0(u16 adress, u32 data) { // OK int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || // I2C_writeByte(DATA_WRITE) || // I2C_writeByte(0xe0) || // I2C_writeByte(0x00) || // --> write in D1 Memory I2C_writeByte(0x00) || // I2C_writeByte(0x01) || // --> 1 word to write I2C_writeByte((u8)(adress >> 8)) || // I2C_writeByte((u8)(adress & 0xFF)) || // --> adress I2C_writeByte((u8)(data >> 24)) || // I2C_writeByte((u8)(data >> 16)) || // I2C_writeByte((u8)(data >> 8)) || // I2C_writeByte((u8)(data & 0xFF)) || // --> data I2C_stopCond() ); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int writeMemoryD1(u16 adress, u32 data) { int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || // I2C_writeByte(DATA_WRITE) || // I2C_writeByte(0xf0) || // I2C_writeByte(0x00) || // --> write in D1 Memory I2C_writeByte(0x00) || // I2C_writeByte(0x01) || // --> 1 word to write I2C_writeByte((u8)(adress >> 8)) || // I2C_writeByte((u8)(adress & 0xFF)) || // --> adress I2C_writeByte((u8)(data >> 24)) || // I2C_writeByte((u8)(data >> 16)) || // I2C_writeByte((u8)(data >> 8)) || // I2C_writeByte((u8)(data & 0xFF)) || // --> data I2C_stopCond() ); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int readMemoryD0(u16 adress, u32 * data) { // OK u8 result1, result2, result3, result4; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || // I2C_writeByte(DATA_WRITE) || // I2C_writeByte(0xc0) || // I2C_writeByte(0x00) || // --> write in D0 Memory I2C_writeByte(0x00) || // I2C_writeByte(0x01) || // --> 1 word to write I2C_writeByte((u8)(adress >> 8)) || // I2C_writeByte((u8)(adress & 0xFF)) || // --> adress I2C_stopCond() ); wait(10); ret |= ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(DATA_READ) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,0) || I2C_readByte(&result3,0) || I2C_readByte(&result4,1) || I2C_stopCond() ); *data = result4; *data |= ((u32)result3 << 8); *data |= ((u32)result2 << 16); *data |= ((u32)result1 << 24); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int readMemoryD1(u16 adress, u32 * data) { u8 result1, result2, result3, result4; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || // I2C_writeByte(DATA_WRITE) || // I2C_writeByte(0xd0) || // I2C_writeByte(0x00) || // --> write in D1 Memory I2C_writeByte(0x00) || // I2C_writeByte(0x01) || // --> 1 word to write I2C_writeByte((u8)(adress >> 8)) || // I2C_writeByte((u8)(adress & 0xFF)) || // --> adress I2C_stopCond() ); wait(10); ret |= ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(DATA_READ) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,0) || I2C_readByte(&result3,0) || I2C_readByte(&result4,1) || I2C_stopCond() ); *data = result4; *data |= ((u32)result3 << 8); *data |= ((u32)result2 << 16); *data |= ((u32)result1 << 24); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int readIcVersion(u32 * data) { // OK u8 result1, result2, result3, result4; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(0x68) || I2C_writeByte(0x70) || I2C_writeByte(0x00) || I2C_stopCond() ); wait(10); ret |= ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(0x69) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,0) || I2C_readByte(&result3,0) || I2C_readByte(&result4,1) || I2C_stopCond() ); *data = (u32)result4; *data |= ((u32)result3 << 8); *data |= ((u32)result2 << 16); *data |= ((u32)result1 << 24); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int writeCodec(u8 addr, u16 data) { int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(CODEC_WRITE) || I2C_writeByte(00) || I2C_writeByte(addr) || I2C_writeByte((u8)(data >> 8)) || // left part I2C_writeByte((u8)(data & 0xFF)) || // right part I2C_stopCond() ); wait(500); return ret; } /*-----------------------------------------------------------------------*/ int readCodec(u8 addr, u16 * data) { // mas doc page 40 u8 result1, result2; int ret; ret = ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(CODEC_WRITE) || I2C_writeByte(0x00) || I2C_writeByte(addr) || I2C_stopCond() ); wait(10); ret |= ( I2C_startCond() || I2C_writeByte(DW) || I2C_writeByte(CODEC_READ) || I2C_repStartCond() || I2C_writeByte(DR) || I2C_readByte(&result1,0) || I2C_readByte(&result2,1) || I2C_stopCond() ); *data = (u16)result2; *data |= ((u16)result1 << 8); wait(500); return ret; } /*-----------------------------------------------------------------------*/ void printMemory(int D, char * s, u16 address) { // usage : printMemory(0, "IOCONTROLMAIN", IOCONTROLMAIN); u32 * data; if (D == 0) { readMemoryD0(address, data); } else { readMemoryD1(address, data); } printf("%s : UP %X DOWN %X" NL, s, (u16)(*data >> 16), (u16)(*data)); } /*-----------------------------------------------------------------------*/ void printCodec(char * s, u16 address, u16 * data) { readCodec(address, data); printf("%s : %X" NL,s,(u16)(*data)); } /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ void bt_cb( call_data_t call_data, cb_data_t cb_data ) { u8 data_idx = (u8)((call_data & 0x0000FF) >> 0); u8 error_code; cid = l2cap_data_buffer[data_idx].local_cid; btn_bt_data_send(getChan((u16)cid), "GO", 4, &error_code); printf("CONNNECTEEEEEEEEEEEEEEEEEEEEEEED"NL); } /*-----------------------------------------------------------------------*/ void send_data_request(call_data_t call_data /* cid */, cb_data_t cb_data) { u8 error_code; more[0] = 1; demandOnProcess += 1; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); return; } /*-----------------------------------------------------------------------*/ void feedMas(void) { #ifdef USE_PIO if (!(bufferCritical)) { while (inp(PINB) & 0x1) { // EOD HIGH // set PIO if (*read_pointer & 0x1) sbi(PORTF, PIN7); else cbi(PORTF, PIN7); // PI19 PIN7 // PE7 if (*read_pointer & 0x2) sbi(PORTF, PIN6); else cbi(PORTF, PIN6); // PI18 PIN6 // PE6 if (*read_pointer & 0x4) sbi(PORTF, PIN5); else cbi(PORTF, PIN5); // PI17 PIN5 // PE5 if (*read_pointer & 0x8) sbi(PORTF, PIN4); else cbi(PORTF, PIN4); // PI16 PIN3 // PE3 if (*read_pointer & 0x10) sbi(PORTE, PIN3); else cbi(PORTE, PIN3); // PI15 PIN4 // PF4 if (*read_pointer & 0x20) sbi(PORTE, PIN5); else cbi(PORTE, PIN5); // PI14 PIN5 // PF5 if (*read_pointer & 0x40) sbi(PORTE, PIN6); else cbi(PORTE, PIN6); // PI13 PIN6 // PF6 if (*read_pointer & 0x80) sbi(PORTE, PIN7); else cbi(PORTE, PIN7); // PI12 PIN7 // PF7 sbi(CONTROL_PORT, PR); // raise PR if (read_pointer == MP3_BUFFER_END_ADDR) { // active wait read_pointer = MP3_BUFFER_START_ADDR; // active wait } // active wait else { // active wait read_pointer++; // active wait } // active wait while(!(inp(PINB) & 0x2)); // wait for RTR up cbi(CONTROL_PORT, PR); // low PR } } #endif sbi(PORTF, PIN5); #ifdef USE_SERIAL if (!(bufferCritical)) { outp(BV(SPE) | BV (MSTR) | BV(CPHA) | BV(SPR0), SPCR); // enable SPI, master mode, clock rate = f/4 while (inp(PINE) & 0x8) { // EOD HIGH (EOD = E3 --> 0x8) outp(*read_pointer, SPDR); if (read_pointer == MP3_BUFFER_END_ADDR) { read_pointer = MP3_BUFFER_START_ADDR; } else { read_pointer++; } while(!(inp(SPSR) & (BV(SPIF)))); } } cbi(PORTF, PIN5); #endif } /*-----------------------------------------------------------------------*/ void data_received_cb( call_data_t call_data, cb_data_t cb_data ) { u16 i; u16 length; u8 * data; u16 diff; u8 error_code; u8 data_idx = (u8)((call_data & 0x0000FF) >> 0); length = l2cap_data_buffer[data_idx].payload_length; data = l2cap_data_buffer[data_idx].data; if (bufferFilling) { if (firstTransfer) { printf("Filling buffer..."); firstTransfer = 0; read_pointer = MP3_BUFFER_END_ADDR; cid = l2cap_data_buffer[data_idx].local_cid; p_n = 0; } // MAS not playing yet, filling the buffer for (i = 0 ; i < length ; i++) { *write_pointer = *(data + i); if (write_pointer == MP3_BUFFER_END_ADDR) { write_pointer = MP3_BUFFER_START_ADDR; } else { write_pointer++; } } quantity_received += length; // free the buffer for incoming l2cap/rfcomm data packets btn_bt_data_free( data_idx ); if (quantity_received >= PACKET_SIZE) { // End of the 1kb packet quantity_received = 0; demandOnProcess--; // computing the difference between the two pointers if (write_pointer >= read_pointer) { diff = MP3_BUFFER_LENGTH - (u16)(write_pointer - read_pointer); } else { diff = read_pointer - write_pointer; } // testing if buffer demi full if (diff <= (MP3_BUFFER_LENGTH / 2)) { // full - start playing bufferFilling = FALSE; printf("done"NL); demandOnProcess = 0; //btn_disp_put_event(PLAY_EVENT, (call_data_t)cid); } } } else { // feed MAS feedMas(); quantity_received += length; // this loop takes about 225 us to be executed for (i = 0 ; i < length ; i++) { *write_pointer = *(data + i); if (write_pointer == MP3_BUFFER_END_ADDR) { write_pointer = MP3_BUFFER_START_ADDR; } else { write_pointer++; } } btn_bt_data_free( data_idx ); feedMas(); if (quantity_received >= PACKET_SIZE) { // End of the 1kb packet quantity_received = 0; if (write_pointer >= read_pointer) { diff = MP3_BUFFER_LENGTH - (u16)(write_pointer - read_pointer); } else { diff = read_pointer - write_pointer; } printf("diff %u"NL,diff); if (diff > (MP3_BUFFER_LENGTH * 0.85)) { // less btn_bt_data_send(getChan((u16)cid), "LESS", 4, &error_code); printf("LESS"NL); } if (diff < (MP3_BUFFER_LENGTH * 0.10)) { // more btn_bt_data_send(getChan((u16)cid), "MORE", 4, &error_code); printf("MORE"NL); } } feedMas(); } cbi(PORTF, PIN4); if ((length >= 4) && (strncmp(data, "END", 3) == 0)) { endOfFile = 1; if (bufferFilling) { printf("done"NL); } } } /*-----------------------------------------------------------------------*/ void buffer_init(void) { u16 i = 0; printf("Initializing buffer..."); write_pointer = MP3_BUFFER_START_ADDR; for (i = 0 ; i < MP3_BUFFER_LENGTH ; i++) { *write_pointer = 0; write_pointer++; } // place pointers at the beginning read_pointer = MP3_BUFFER_START_ADDR; write_pointer = MP3_BUFFER_START_ADDR; printf("done"NL); } /*-----------------------------------------------------------------------*/ void play( call_data_t call_data, cb_data_t cb_data ) { u8 error_code; feedMas(); if (bufferLow) { // testing if buffer is going low if (write_pointer >= read_pointer) { // testing if buffer critical if ((u16)(write_pointer - read_pointer) < (u16)BUFFER_CRITICAL_THRESHOLD) { printf("buffer underrun, filling it again..."); bufferLow = FALSE; bufferFilling = TRUE; demandOnProcess++; more[0] = 1; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); return; } // testing if buffer always low if ((u16)(write_pointer - read_pointer) >= (u16)BUFFER_LOW_THRESHOLD) { bufferLow = FALSE; printf("now OK again"NL); } } else { // testing if buffer critical if ( (u16)(read_pointer - write_pointer) > (u16)(MP3_BUFFER_LENGTH - BUFFER_CRITICAL_THRESHOLD) ) { printf("buffer underrun, filling it again..."NL); bufferLow = FALSE; bufferFilling = TRUE; demandOnProcess++; more[0] = 1; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); return; } // testing if buffer always low if ( (u16)(read_pointer - write_pointer) <= (u16)(MP3_BUFFER_LENGTH - BUFFER_LOW_THRESHOLD) ) { bufferLow = FALSE; printf("now OK again"NL); } } } else { if (write_pointer >= read_pointer) { if ((u16)(write_pointer - read_pointer) < (u16)BUFFER_LOW_THRESHOLD) { printf("buffer going low..."); bufferLow = TRUE; } } else { if ( (u16)(read_pointer - write_pointer) > (u16)(MP3_BUFFER_LENGTH - BUFFER_LOW_THRESHOLD) ) { printf("buffer going low..."); bufferLow = TRUE; } } } if (read_pointer >= write_pointer) { if ( ( (u16)(read_pointer - write_pointer) > BUFFER_PLACE_THRESHOLD) && (!(endOfFile)) ) { if (!(demandOnProcess)) { // ask for data if (bufferLow) { more[0] = 1; demandOnProcess += 1; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); } else { more[0] = 5; demandOnProcess += 5; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); } return; } } } else { if ( ((u16)(read_pointer - MP3_BUFFER_START_ADDR + MP3_BUFFER_END_ADDR - write_pointer) > (u16)(BUFFER_PLACE_THRESHOLD)) && (!(endOfFile)) ) { if (!(demandOnProcess)) { // ask for data if (bufferLow) { more[0] = 1; demandOnProcess += 1; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); } else { more[0] = 5; demandOnProcess += 5; btn_bt_data_send(getChan((u16)cid), more, 3, &error_code); } return; } } } btn_disp_put_event(PROCEED_COMMAND_EVENT, (call_data_t)cid); } /*-----------------------------------------------------------------------*/ void commands( call_data_t call_data, cb_data_t cb_data ) { // place here what you want to do when system has a bit of idle time // // this method is typically the designed place where one shall look // if user is pushing on a button to, e.g change the volume or so // // but WARNING :this method shall to take too long to be executed. // // After some test, the execution times of this methods shall be bigger than // // | bitrate | recommended | critical | // ---------------------------------------------------- // 56 kbps < 55 ms 90 ms // 64 kbps < 50 ms 70 ms // 80 kbps < 45 ms 70 ms // 96 kbps < 20 ms ? // // Note that at 96 kbps (with the current version), the buffer will also // need some data, so this method will be executed very rarely. It's // eventually possible to decrease the BUFFER_SPACE_THRESHOLD this method // more often executed // // Do also not forget to call again the play method, using fot that // the event mechanism btn_disp_put_event(PLAY_EVENT, (call_data_t)cid); } /*-----------------------------------------------------------------------*/ void stop( call_data_t call_data, cb_data_t cb_data ) { } /*-----------------------------------------------------------------------*/ void transfer_init(void) { quantity_received = 0; bufferFilling = 1; endOfFile = 0; firstTransfer = 1; demandOnProcess = 0; bufferLow = 0; bufferCritical = 0; #ifdef USE_SERIAL serial_mask = 0x80; // 1 << 7 #endif microsec = 50; } /*-----------------------------------------------------------------------*/ u8 mas_init(void) { u8 boolean = 0; printf("Preparing IO to talk with MAS..."); #ifdef USE_PIO // configure input pin PB0 / EOD cbi(CONTROL_PORT, EOD); cbi(CONTROL_PORT_DDR, EOD); // configure input pin PB1 / RTR cbi(CONTROL_PORT, RTR /*works with EOD*/); cbi(CONTROL_PORT_DDR, RTR /*works with EOD*/); // configure output pin PB2 / PCS sbi(CONTROL_PORT_DDR, PCS); cbi(CONTROL_PORT, PCS); // configure output pin PB3 / PR sbi(CONTROL_PORT_DDR, PR); cbi(CONTROL_PORT, PR); // confiure output PIO sbi(MSB_PIO_PORT_DDR, PI19); sbi(MSB_PIO_PORT_DDR, PI18); sbi(MSB_PIO_PORT_DDR, PI17); sbi(MSB_PIO_PORT_DDR, PI16); sbi(LSB_PIO_PORT_DDR, PI15); sbi(LSB_PIO_PORT_DDR, PI14); sbi(LSB_PIO_PORT_DDR, PI13); sbi(LSB_PIO_PORT_DDR, PI12); cbi(MSB_PIO_PORT, PI19); cbi(MSB_PIO_PORT, PI18); cbi(MSB_PIO_PORT, PI17); cbi(MSB_PIO_PORT, PI16); cbi(LSB_PIO_PORT, PI15); cbi(LSB_PIO_PORT, PI14); cbi(LSB_PIO_PORT, PI13); cbi(LSB_PIO_PORT, PI12); #endif #ifdef USE_SERIAL // configure built-in SPI outp(BV(PIN2) | BV(PIN1) | BV(PIN0), DDRB); // set MOSI and SCK output, SS and MISO inputs // configure input pin PE3 / EOD cbi(PORTE, PIN3); cbi(DDRE, PIN3); outp(BV(SPI2X), SPSR); #endif #ifdef DEBUG_MODE // configure output pin PF4 sbi(DDRF, PIN4); cbi(PORTF, PIN4); sbi(DDRF, PIN5); cbi(PORTF, PIN5); sbi(DDRF, PIN6); cbi(PORTF, PIN6); sbi(DDRF, PIN7); cbi(PORTF, PIN7); #endif printf("done"NL); printf("Configuring MAS..."); resetMAS(); writeControlRegister(CTRL_REG_DSP_ON_NODC); wait(1000); writeFirstDCDCconfigurationRegister(DCCF_REG_RESET); writeSecondDCDCconfigurationRegister(DCFR_REG_RESET); boolean |= writeMemoryD0(INTERFACECONTROL, INTCTRL_MEM_STANDARD); boolean |= writeMemoryD0(OUT_LL, OUT_LL_STEREO); boolean |= writeMemoryD0(OUT_LR, OUT_LR_STEREO); boolean |= writeMemoryD0(OUT_RL, OUT_RL_STEREO); boolean |= writeMemoryD0(OUT_RR, OUT_RR_STEREO); boolean |= writeMemoryD0(OUTCLKCONFIG, OUTCLKCONFIG_MEM_STANDARD); #ifdef USE_PIO boolean |= writeMemoryD0(IOCONTROLMAIN, IOCTRL_MEM_STANDARD_IN_PIO); #endif #ifdef USE_SERIAL boolean |= writeMemoryD0(IOCONTROLMAIN, IOCTRL_MEM_STANDARD_IN_SERIAL); #endif boolean |= writeControlRegister(CTRL_REG_BOTH_ON_NODC); wait(2000); boolean |= writeCodec(DAC_IN_ADC, DAC_IN_50_PERCENT); boolean |= writeCodec(CONV_CONF, CONV_CONF_LINE_IN); boolean |= writeCodec(ADC_IN_MODE, ADC_IN_STEREO); boolean |= writeCodec(VOLUME, VOLUME_MAX); boolean |= writeCodec(DAC_IN_DSP, DAC_IN_50_PERCENT); wait(200); boolean |= writeMemoryD0(APPSELECT, APPSELECT_MEM_BOTH_DECODE); if (boolean) { printf("NOT DONE" NL); printf("Please start again. If problem persist, just cry" NL); } else { printf("done"NL); } return boolean; } /* ------------------------------------------------------------------------- * main() * ------------------------------------------------------------------------- */ int main( int argc, char *argv[] ) { u8 error_code = 0; btn_init( argc, argv ); btn_system_init( argc, argv, data_buf, L2CAP_BUF_LEN ); btn_rtc_init(); btn_uart1_init(); printf(NL); printf("+------------------------------------------------+"NL); printf("| MAS_DRIVER 1.4 |"NL); printf("+------------------------------------------------+"NL NL); led_init(); buffer_init(); I2C_init(); transfer_init(); mas_init(); btn_bt_change_local_name( "btnode 2.2 for MAS", &error_code ); btn_bt_psm_add( 8197 ); // register function "cb" for event "event". when "event" occurs, // the callback function "cb" is called with "cb_data" as its second // argument // event cb cb_data btn_disp_ev_reg( BT_CONNECTION_EV, bt_cb, BT_CONNECTION_EV ); btn_disp_ev_reg( BT_DISCONNECT_EV, bt_cb, BT_DISCONNECT_EV ); btn_disp_ev_reg( BT_ROLE_CHANGE_EV, bt_cb, BT_ROLE_CHANGE_EV ); btn_disp_ev_reg( BT_DATA_RCV_EV, data_received_cb, BT_DATA_RCV_EV ); btn_disp_ev_reg( BT_RFCOMM_RCV_EV, data_received_cb, BT_RFCOMM_RCV_EV ); btn_disp_ev_reg( DATA_ACK_EVENT, send_data_request, DATA_ACK_EVENT ); btn_disp_ev_reg( PLAY_EVENT, play, PLAY_EVENT); btn_disp_ev_reg( FILE_TRANSFER_DONE_EVENT, stop, FILE_TRANSFER_DONE_EVENT); btn_disp_ev_reg( PROCEED_COMMAND_EVENT, commands, PROCEED_COMMAND_EVENT); /* printf( "=============================" NL ); btn_bt_connect( pc_addr, (u16)8197, &error_code ); if( error_code ) { printf( "APP-ERROR: couldn't establish l2cap connection. "NL ); } else { printf( "APP: connection of l2cap channel initiated sucessfully." NL ); } printf( "=============================" NL ); */ btn_disp_run(); return 0; }