/* Copyright (C) 2015 Allen Hill . Portions of the following source code are: Copyright (C) 2006 Marcin Slonicki . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ----------------------------------------------------------------------- this file is a part of the TOYOTA Corolla MP3 Player Project ----------------------------------------------------------------------- http://www.softservice.com.pl/corolla/avc May 28 / 2009 - version 2 */ #include #include #include #include "avclandrv.h" #include "com232.h" #include "GlobalDef.h" //------------------------------------------------------------------------------ #define AVC_OUT_EN() cbi(AC2_CTRLA, AC_ENABLE_bp); sbi(VPORTA_DIR, 6); // Write mode #define AVC_OUT_DIS() cbi(VPORTA_DIR, 6); sbi(AC2_CTRLA, AC_ENABLE_bp); // Read mode #define AVC_SET_LOGICAL_1() \ __asm__ __volatile__ ("sbi VPORTA_OUT, 6;"); #define AVC_SET_LOGICAL_0() \ __asm__ __volatile__ ("cbi VPORTA_OUT, 6;"); byte CD_ID_1; byte CD_ID_2; byte HU_ID_1; byte HU_ID_2; byte parity_bit; byte repeatMode; byte randomMode; byte playMode; byte cd_Disc; byte cd_Track; byte cd_Time_Min; byte cd_Time_Sec; byte answerReq; cd_modes CD_Mode; byte broadcast; byte master1; byte master2; byte slave1; byte slave2; byte message_len; byte message[MAXMSGLEN]; byte data_control; byte data_len; byte data[MAXMSGLEN]; // we need check answer (to avclan check) timeout // when is more then 1 min, FORCE answer. byte check_timeout; #define SW_ID 0x11 // 11 For my stereo // commands const byte stat1[] = { 0x4, 0x00, 0x00, 0x01, 0x0A }; const byte stat2[] = { 0x4, 0x00, 0x00, 0x01, 0x08 }; const byte stat3[] = { 0x4, 0x00, 0x00, 0x01, 0x0D }; const byte stat4[] = { 0x4, 0x00, 0x00, 0x01, 0x0C }; // broadcast const byte lan_stat1[] = { 0x3, 0x00, 0x01, 0x0A }; const byte lan_reg[] = { 0x3, SW_ID, 0x01, 0x00 }; const byte lan_init[] = { 0x3, SW_ID, 0x01, 0x01 }; const byte lan_check[] = { 0x3, SW_ID, 0x01, 0x20 }; const byte lan_playit[] = { 0x4, SW_ID, 0x01, 0x45, 0x63 }; const byte play_req1[] = { 0x4, 0x00, 0x25, 0x63, 0x80 }; #ifdef __AVENSIS__ const byte play_req2[] = { 0x6, 0x00, SW_ID, 0x63, 0x42 }; #else const byte play_req2[] = { 0x6, 0x00, SW_ID, 0x63, 0x42, 0x01, 0x00 }; #endif const byte play_req3[] = { 0x5, 0x00, SW_ID, 0x63, 0x42, 0x41 }; const byte stop_req[] = { 0x5, 0x00, SW_ID, 0x63, 0x43, 0x01 }; const byte stop_req2[] = { 0x5, 0x00, SW_ID, 0x63, 0x43, 0x41 }; // answers const byte CMD_REGISTER[] = {0x1, 0x05, 0x00, 0x01, SW_ID, 0x10, 0x63 }; const byte CMD_STATUS1[] = {0x1, 0x04, 0x00, 0x01, 0x00, 0x1A }; const byte CMD_STATUS2[] = {0x1, 0x04, 0x00, 0x01, 0x00, 0x18 }; const byte CMD_STATUS3[] = {0x1, 0x04, 0x00, 0x01, 0x00, 0x1D }; const byte CMD_STATUS4[] = {0x1, 0x05, 0x00, 0x01, 0x00, 0x1C, 0x00 }; byte CMD_CHECK[] = {0x1, 0x06, 0x00, 0x01, SW_ID, 0x30, 0x00, 0x00 }; const byte CMD_STATUS5[] = {0x1, 0x05, 0x00, 0x5C, 0x12, 0x53, 0x02 }; const byte CMD_STATUS5A[] = {0x0, 0x05, 0x5C, 0x31, 0xF1, 0x00, 0x00 }; const byte CMD_STATUS6[] = {0x1, 0x06, 0x00, 0x5C, 0x32, 0xF0, 0x02, 0x00 }; const byte CMD_PLAY_OK1[] = {0x1, 0x05, 0x00, 0x63, SW_ID, 0x50, 0x01 }; const byte CMD_PLAY_OK2[] = {0x1, 0x05, 0x00, 0x63, SW_ID, 0x52, 0x01 }; const byte CMD_PLAY_OK3[] = {0x0, 0x0B, 0x63, 0x31, 0xF1, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0x80 }; byte CMD_PLAY_OK4[] = {0x0, 0x0B, 0x63, 0x31, 0xF1, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }; const byte CMD_STOP1[] = {0x1, 0x05, 0x00, 0x63, SW_ID, 0x53, 0x01 }; byte CMD_STOP2[] = {0x0, 0x0B, 0x63, 0x31, 0xF1, 0x00, 0x30, 0x00, 0x00,0x00, 0x00, 0x00, 0x80 }; const byte CMD_BEEP[] = {0x1, 0x05, 0x00, 0x63, 0x29, 0x60, 0x02 }; //------------------------------------------------------------------------------ // DONE: Timing adjusted, however refactoring may make code more clear/efficient //------------------------------------------------------------------------------ void AVC_HoldLine() { STOPEvent; // wait for free line byte line_busy = 1; TCB1.CNT = 0; do { while (INPUT_IS_CLEAR) { /* The comparison value was originally 25 with CK64 (tick period of 4.34 us) at a clock frequency 14.7456MHz. For a more accurate tick period of .5 us at 16MHz, the value should be approximately 225*/ if (TCB1.CNT >= 900) break; } if (TCB1.CNT > 864) line_busy=0; } while (line_busy); // switch to out mode AVC_OUT_EN(); AVC_SET_LOGICAL_1(); STARTEvent; } // DONE: No changes necessary //------------------------------------------------------------------------------ void AVC_ReleaseLine() { AVC_SET_LOGICAL_0(); AVC_OUT_DIS(); } //------------------------------------------------------------------------------ // DONE: No changes necessary //------------------------------------------------------------------------------ void AVCLan_Init() { PORTA.PIN6CTRL = PORT_ISC_INPUT_DISABLE_gc; // Disable input buffer; recommended when using AC PORTA.PIN7CTRL = PORT_ISC_INPUT_DISABLE_gc; // Pull-ups are disabled by default VPORTA.DIR &= ~(PIN6_bm | PIN7_bm); // Zero pin 6 and 7 to set as input // Analog comparator AC2.CTRLA = AC_OUTEN_bm | AC_HYSMODE_25mV_gc | AC_ENABLE_bm; TCB1.CTRLB = TCB_ASYNC_bm | TCB_CNTMODE_SINGLE_gc; TCB1.EVCTRL = TCB_CAPTEI_bm; TCB1.INTCTRL = TCB_CAPT_bm; EVSYS.ASYNCUSER0 = EVSYS_ASYNCUSER0_ASYNCCH0_gc; TCB1.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm; message_len = 0; answerReq = cmNull; check_timeout = 0; cd_Disc = 1; cd_Track = 1; cd_Time_Min = 0; cd_Time_Sec = 0; repeatMode = 0; randomMode = 0; playMode = 0; CD_Mode = stStop; } // DONE: Timing adjusted, however refactoring may make code more clear/efficient //------------------------------------------------------------------------------ byte AVCLan_Read_Byte(byte length) { byte bite = 0; while (1) { while (INPUT_IS_CLEAR); TCB1.CNT = 0; while (INPUT_IS_SET); // If input was set for less than 26 us if ( TCB1.CNT < 208 ) { // (a generous half period), bit was a 1 bite++; parity_bit++; } length--; if (!length) return bite; bite = bite << 1; } } void set_AVC_logic_for(uint8_t val, uint16_t period) { if (val == 1) { AVC_SET_LOGICAL_1(); } else { AVC_SET_LOGICAL_0(); } TCB1.CCMP = period; EVSYS.ASYNCSTROBE = EVSYS_ASYNCCH00_bm; loop_until_bit_is_set(TCB1_INTFLAGS, 0); TCB1_INTFLAGS = 1; } // DONE: Timing adjusted //------------------------------------------------------------------------------ byte AVCLan_Send_StartBit() { set_AVC_logic_for(1, 1328); // 166 us @ 125 ns tick (for F_CPU = 16MHz) set_AVC_logic_for(0, 152); // 19 us @ 125 ns tick (for F_CPU = 16MHz) return 1; } // DONE: Timing adjusted. Comparison values are timer ticks, not us. //------------------------------------------------------------------------------ void AVCLan_Send_Bit1() { set_AVC_logic_for(1, 164); // 20.5 us @ 125 ns tick (for F_CPU = 16MHz) set_AVC_logic_for(0, 152); // 19 us @ 125 ns tick (for F_CPU = 16MHz) } void AVCLan_Send_Bit0() { set_AVC_logic_for(1, 272); // 34 us @ 125 ns tick (for F_CPU = 16MHz) set_AVC_logic_for(0, 44); // 5.5 us @ 125 ns tick (for F_CPU = 16MHz) } // DONE: Timing adjusted. //------------------------------------------------------------------------------ byte AVCLan_Read_ACK() { set_AVC_logic_for(1, 152); // 34 us @ 125 ns tick (for F_CPU = 16MHz) AVC_SET_LOGICAL_0(); // Replace with AVC_ReleaseLine? AVC_OUT_DIS(); // switch to read mode TCB1.CNT = 0; while(1) { if (INPUT_IS_SET && (TCB1.CNT > 208 )) break; // Make sure INPUT is not still set from us // Line of experimentation: Try changing TCNT0 comparison value or remove check entirely if (TCB1.CNT > 300 ) return 1; // Not sure if this fix is intent correct } while(INPUT_IS_SET); AVC_OUT_EN(); // back to write mode return 0; } byte AVCLan_Send_ACK() { TCB1.CNT = 0; while (INPUT_IS_CLEAR) { if (TCB1.CNT >= 900) return 0; // max wait time } AVC_OUT_EN(); set_AVC_logic_for(1, 272); // 34 us @ 125 ns tick (for F_CPU = 16MHz) set_AVC_logic_for(0, 44); // 5.5 us @ 125 ns tick (for F_CPU = 16MHz) AVC_OUT_DIS(); return 1; } // DONE: var 'byte' adjusted to 'bite' to avoid reserved word conflict //------------------------------------------------------------------------------ byte AVCLan_Send_Byte(byte bite, byte len) { byte b; if (len==8) { b = bite; } else { b = bite << (8-len); } while (1) { if ( (b & 128)!=0 ) { AVCLan_Send_Bit1(); parity_bit++; } else { AVCLan_Send_Bit0(); } len--; if (!len) { //if (INPUT_IS_SET) RS232_Print_P(PSTR("SBER\n")); // Send Bit ERror return 1; } b = b << 1; } } // DONE: Nothing needed. //------------------------------------------------------------------------------ byte AVCLan_Send_ParityBit() { if ( (parity_bit & 1)!=0 ) { AVCLan_Send_Bit1(); //parity_bit++; } else { AVCLan_Send_Bit0(); } parity_bit=0; return 1; } // DONE: Nothing needed. //------------------------------------------------------------------------------ byte CheckCmd(byte *cmd) { byte i; byte *c; byte l; c = cmd; l = *c++; for (i=0; i 255 ) { // 170 us // // TCCR1B = 0; // // TCCR1B |= (1 << WGM12)|(1 << CS12); // Set CTC, prescaler at 256 // STARTEvent; // RS232_Print_P(PSTR("LAN>T1\n")); // return 0; // } // } // // if ( TCNT0 < 20 ) { // 20 us // // TCCR1B = 0; // // TCCR1B |= (1 << WGM12)|(1 << CS12); // STARTEvent; // RS232_Print_P(PSTR("LAN>T2\n")); // return 0; // } AVCLan_Read_Byte(1); broadcast = AVCLan_Read_Byte(1); parity_bit = 0; master1 = AVCLan_Read_Byte(4); master2 = AVCLan_Read_Byte(8); if ((parity_bit&1)!=AVCLan_Read_Byte(1)) { STARTEvent; return 0; } parity_bit = 0; slave1 = AVCLan_Read_Byte(4); slave2 = AVCLan_Read_Byte(8); if ((parity_bit&1)!=AVCLan_Read_Byte(1)) { STARTEvent; return 0; } // is this command for me ? if ((slave1==CD_ID_1)&&(slave2==CD_ID_2)) { for_me=1; } if (for_me) AVCLan_Send_ACK(); else AVCLan_Read_Byte(1); parity_bit = 0; AVCLan_Read_Byte(4); // control - always 0xF if ((parity_bit&1)!=AVCLan_Read_Byte(1)) { STARTEvent; return 0; } if (for_me) AVCLan_Send_ACK(); else AVCLan_Read_Byte(1); parity_bit = 0; message_len = AVCLan_Read_Byte(8); if ((parity_bit&1)!=AVCLan_Read_Byte(1)) { STARTEvent; return 0; } if (for_me) AVCLan_Send_ACK(); else AVCLan_Read_Byte(1); if (message_len > MAXMSGLEN) { // RS232_Print_P(PSTR("LAN> Command error")); STARTEvent; return 0; } for (i=0; i= 900 ) break; } if ( TCB1.CNT > 864 ) line_busy=0; } while (line_busy); // switch to output mode AVC_OUT_EN(); AVCLan_Send_StartBit(); AVCLan_Send_Byte(0x1, 1); // regular communication parity_bit = 0; AVCLan_Send_Byte(CD_ID_1, 4); // CD Changer ID as master AVCLan_Send_Byte(CD_ID_2, 8); AVCLan_Send_ParityBit(); AVCLan_Send_Byte(HU_ID_1, 4); // HeadUnit ID as slave AVCLan_Send_Byte(HU_ID_2, 8); AVCLan_Send_ParityBit(); if (AVCLan_Read_ACK()) { AVC_OUT_DIS(); STARTEvent; RS232_Print_P(PSTR("Error ACK 1 (Transmission ACK)\n")); return 1; } AVCLan_Send_Byte(0xF, 4); // 0xf - control -> COMMAND WRITE AVCLan_Send_ParityBit(); if (AVCLan_Read_ACK()) { AVC_OUT_DIS(); STARTEvent; RS232_Print_P(PSTR("Error ACK 2 (COMMMAND WRITE)\n")); return 2; } AVCLan_Send_Byte(data_len, 8);// data length AVCLan_Send_ParityBit(); if (AVCLan_Read_ACK()) { AVC_OUT_DIS(); STARTEvent; RS232_Print_P(PSTR("Error ACK 3 (Data Length)\n")); return 3; } for (i=0;i= 900 ) break; } if ( TCB1.CNT > 864 ) line_busy=0; } while (line_busy); AVC_OUT_EN(); AVCLan_Send_StartBit(); AVCLan_Send_Byte(0x0, 1); // broadcast parity_bit = 0; AVCLan_Send_Byte(CD_ID_1, 4); // CD Changer ID as master AVCLan_Send_Byte(CD_ID_2, 8); AVCLan_Send_ParityBit(); AVCLan_Send_Byte(0x1, 4); // all audio devices AVCLan_Send_Byte(0xFF, 8); AVCLan_Send_ParityBit(); AVCLan_Send_Bit1(); AVCLan_Send_Byte(0xF, 4); // 0xf - control -> COMMAND WRITE AVCLan_Send_ParityBit(); AVCLan_Send_Bit1(); AVCLan_Send_Byte(data_len, 8); // data lenght AVCLan_Send_ParityBit(); AVCLan_Send_Bit1(); for (i=0;i ")); for (i=0; i