Эмулятор СД чейнджера, как запустить

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Всем Привет, захотелось мне повторить проект автора Tomas Kovacik, эмулятор CD changer для магнитолы audi concert1. Arduino pro mini (2560) прошил без проблем, но магнитола не видит устройство. Помогите запустить, может нужно, что-то раскоментировать. С arduino столкнулся первый раз.

модуль bluetooth XS3868

подключал как написано в коде: строки 33-41

ссылка на исходный код  

https://github.com/tomaskovacik/vwcdavr/blob/master/CDC_emulator/cdc_arduino_ported_k9spud_vwcdpic_for_mega/cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino

/*****************************************************************************
 * 
 * 
 * Audi/Volkswagen Audi Interface
 * 
 * Target: arduino atmega328(tested)
 * 
 * 
 * Author: Vincent
 * 
 * Date: January, 2011
 * 
 * Version: 0.01
 * 
 * 
 * 
 * Originally ported from VWCDPIC Project:
 * 
 * http://www.k9spud.com/vwcdpic/
 * 
 * 
 * 
 * Ported from Matthias Koelling's AVR Code: 
 * 
 * www.mikrocontroller.net/attachment/31279/vwcdc.c
 * 
 * ---------------------------------
 * 16. Mar 2015:
 * 
 * https://github.com/tomaskovacik/
 * arduino duemilanove works:
 * 
 * RADIO PIN -> arduino pin
 * 
 * DataOut   -> digital 8 (ICP1)
 * DataIn    -> digital 11(PB3)
 * Clock     -> digital 13(PB5)
 *
 * compter -> arduino pin
 * serial TX -> digital 0 (PD0)
 * serial RX -> digital 1 (PD1)
 *
 * 19. Mar 2015  tomaskovacik
 * port to atmega8
 * 
 * 27. Dec 2018 tomaskovacik
 * port arduino mega (atmega2560)
 * 
 *****************************************************************************/

//#define DUMPMODE
//#define DUMPMODE2

#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
#define TCCR2A TCCR2
#define TCCR2B TCCR2
#define COM2A1 COM21
#define COM2A0 COM20
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#define TIMER2_COMPA_vect TIMER2_COMP_vect
#define TIMSK1 TIMSK
#define TIFR1 TIFR
#define ICIE1 TICIE1
#define TIMSK0 TIMSK
#define TIFR2 TIFR
#define OCF2A OCF2
#define TCCR0B TCCR0
#endif

// uncoment this to have original serial outputs for PJRC players
//#define PJRC

/* enable hex control command on serial line to control mpd control
 * script with shyd.de control script
 */
//#define JUST_HEX_TO_SERIAL

/* enable bluetooth module control over serial line
 * XS3868
 */
//#define BLUETOOTH

/*
 * read disc# track# status over serial line
 */
//#define DISC_TRACK_NUMBER_FROM_MPD

/* -- Includes ------------------------------------------------------------- */



#include <avr/io.h>

#include <avr/sfr_defs.h>

#include <stdlib.h>

#include <avr/interrupt.h>

#include <avr/pgmspace.h>



#include <util/delay.h>







/* -- Configuration Parameters --------------------------------------------- */



/* -- Makros --------------------------------------------------------------- */



/* -- Defines -------------------------------------------------------------- */

#define TRUE 1



// Low period of PWTX line:

// 0: ~650us

// 1: ~1.77ms

// S: ~4.57ms



// one tick is 0.5µs

#define STARTTHRESHOLD  6400            // greater than this signifies START bit

#define HIGHTHRESHOLD   2496       // greater than this signifies 1 bit.

#define LOWTHRESHOLD     512        // greater than this signifies 0 bit.

#define PKTSIZE          -32            // command packets are 32 bits long.



// do not refresh head unit faster than 5.5ms (currently not implemented)

// 5.24s slow refresh rate when head unit in FM/AM/Tape mode (not implemented)



//#define REFRESH_PERIOD   50        // default to refresh head unit every 50.0ms

#define SECONDWAIT      -20         // wait 20 * 50ms to get 1 second (50ms*20 = 1000ms = 1s)

#define POWERIDENTWAIT  -10         // wait 10 * 1s to 10 seconds between VWCDPICx.x display

#define SCANWAIT        -100             // wait 100 * 50ms to get 5sec (50ms*100 = 5000ms = 5s)

#define _10MS           156

#define _50MS            500

#define _700US            7


#define TX_BUFFER_END   12

#define CAP_BUFFER_END	24



#define VER_MAJOR       '1'

#define VER_MINOR       '0'

#define VER_PATCHLEVEL  'b'



#define RADIO_COMMAND      PL0 //ICP4 - PL0 - arduino pin 49
#define RADIO_COMMAND  DDL0
#define RADIO_COMMAND_DDR  DDRL
#define RADIO_COMMAND_PORT  PORTL
#define RADIO_COMMAND_PIN PINL
#define RADIO_CLOCK        PL7
#define RADIO_CLOCK    DDL7
#define RADIO_CLOCK_DDR    DDRL
#define RADIO_CLOCK_PORT  PORTL
#define RADIO_DATA         PL6
#define RADIO_DATA     DDL6
#define RADIO_DATA_DDR     DDRL
#define RADIO_DATA_PORT  PORTL
//#define RADIO_COMMAND 49 //PL0(ICP4)
//#define RADIO_DATA  43 //PL6
//#define RADIO_CLOCK 42 //PL7
#define RADIO_ACC 3 //PE5 (INT5)


// Command Codes

// -------------

//

// First byte is always 53

// Second byte is always 2C

// Third and Fourth bytes always add up to FF

// All command codes seem to be a multiple of 4.

//

//

// 53 2C 0C F3 CD 1

// 53 2C 10 EF DISABLE

// 53 2C 14 EB Change CD (ignored)

// 53 2C 18 E7 Previous CD (only on Audi Concert <)

// 53 2C 2C D3 CD 5 (first packet)

// 53 2C 38 C7 Change CD/Next CD (aka MINQUIRY)

// 53 2C 4C B3 CD 3 (first packet)

// 53 2C 58 A7 Seek Back Pressed

// 53 2C 60 9F Mix 1

// 53 2C 68 97 Up on Mk3 premium (Adam Yellen)

// 53 2C 78 87 Dn

// 53 2C 8C 73 CD 2 (first packet)

// 53 2C A0 5F Scan

// 53 2C A4 5B something to do with power on (Audi Concert)

// 53 2C A8 57 Dn on Mk3 premium (Adam Yellen <adam@yellen.com>)

// 53 2C AC 53 CD 6 (first packet)

// 53 2C CC 33 CD 4 (first packet)

// 53 2C D8 27 Seek Forward Pressed

// 53 2C E0 1F Mix 6

// 53 2C E4 1B ENABLE

// 53 2C F8 07 Up





//#define  Do_PLAY           0x08  // mix button held down (RCD300 head unit only)

#define  Do_PLAY           0x03  // mix button held down (RCD300 head unit only)

#define  Do_LOADCD	  0x01	// not used

#define  Do_ENABLE_MK      0x08  // mk concert1

#define  Do_CD1            0x0C  // CD 1

#define  Do_DISABLE        0x10  // DISABLE

#define  Do_CHANGECD       0x14  // Change CD (changer ignores & no ACK)

#define  Do_PREVCD         0x18  // PREVIOUS CD (Audi Concert head unit)

#define  Do_CD5            0x2C  // CD 5

#define  Do_TP             0x30  // TP info (TP button pressed)

#define  Do_SEEKFORWARD_MK 0x38  // mk concert 1 LOAD CD (aka MINQUIRY).

// Also means "Next CD" if no CD button pressed

#define  Do_CD3            0x4C  // CD 3

#define  Do_SEEKBACK       0x58  // SEEK BACK

#define  Do_MIX_CD         0x60  // MIX 1 (mix tracks within one disc)

#define  Do_UP_MK3         0x68  // UP (Mk3 head unit)

#define  Do_DOWN           0x78  // DOWN

#define  Do_CD2            0x8C  // CD 2

#define  Do_SCAN           0xA0  // SCAN

#define  Do_UNKNOWNCMD     0xA4  // power on CD mode?? (Audi Concert head unit)

#define  Do_DOWN_MK3       0xA8  // DOWN (Mk3 head unit only)

#define  Do_CD6            0xAC  // CD 6

#define  Do_CD4            0xCC  // CD 4

#define  Do_SEEKFORWARD    0xD8  // Seek Forward

#define  Do_MIX            0xE0  // MIX 6 (mix tracks across all discs)

#define  Do_ENABLE         0xE4  // ENABLE

#define  Do_UP             0xF8  // UP

enum STATES

{

  StateIdle,

  StateIdleThenPlay,

  StateInitPlay,

  StateInitPlayEnd,

  StateInitPlayAnnounceCD,

  StatePlayLeadIn,

  StatePlayLeadInEnd,

  StatePlayLeadInAnnounceCD,

  StateTrackLeadIn,

  StatePlay,
  StateTP

};



/* -- Types ---------------------------------------------------------------- */



/* -- Extern Global Variables ---------------------------------------------- */

#ifdef BLUETOOTH

const uint8_t sDATAERR[] PROGMEM = "\r\n";

const uint8_t sOVERFLOW[] PROGMEM = "\r\n";

const uint8_t sMDISABLE[] PROGMEM = "AT#MA\r\n";

const uint8_t sMENABLE[] PROGMEM = "AT#MA\r\n";

const uint8_t sMINQUIRY[] PROGMEM = "MINQUIRY\r\n";

const uint8_t sPRV_LIST[] PROGMEM = "AT#MA\r\n";

const uint8_t sNXT_LIST[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST1[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST2[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST3[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST4[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST5[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST6[] PROGMEM = "AT#MA\r\n";

const uint8_t sRANDOM[] PROGMEM = "RANDOM\r\n";

const uint8_t sPLAY[] PROGMEM = "AT#MA\r\n";

const uint8_t sSCAN[] PROGMEM = "SCAN\r\n";

const uint8_t sSTOP[] PROGMEM = "AT#MA\r\n";

const uint8_t sNEXT[] PROGMEM = "AT#MD\r\n";

const uint8_t sPREVIOUS[] PROGMEM = "AT#ME\r\n";

const uint8_t sRING[] PROGMEM = "\r\n";

const uint8_t sIDENTIFY[] PROGMEM = "\r\n";

const uint8_t sNEWLINE[] PROGMEM = "\r\n";

const uint8_t sDASH[] PROGMEM = "";

const uint8_t sHEX[] PROGMEM = "";

const uint8_t sVERSION[] PROGMEM = "";

#else

const uint8_t sDATAERR[] PROGMEM = "dataerr\r\n";

const uint8_t sOVERFLOW[] PROGMEM = "overflow\r\n";

const uint8_t sMDISABLE[] PROGMEM = "MDISABLE\r\n";

const uint8_t sMENABLE[] PROGMEM = "MENABLE\r\n";

const uint8_t sMINQUIRY[] PROGMEM = "MINQUIRY\r\n";

const uint8_t sPRV_LIST[] PROGMEM = "PRV_LIST\r\n";

const uint8_t sNXT_LIST[] PROGMEM = "NXT_LIST\r\n";

const uint8_t sLIST1[] PROGMEM = "LIST1\r\n";

const uint8_t sLIST2[] PROGMEM = "LIST2\r\n";

const uint8_t sLIST3[] PROGMEM = "LIST3\r\n";

const uint8_t sLIST4[] PROGMEM = "LIST4\r\n";

const uint8_t sLIST5[] PROGMEM = "LIST5\r\n";

const uint8_t sLIST6[] PROGMEM = "LIST6\r\n";

const uint8_t sRANDOM[] PROGMEM = "RANDOM\r\n";

const uint8_t sPLAY[] PROGMEM = "PLAY\r\n";

const uint8_t sSCAN[] PROGMEM = "SCAN\r\n";

const uint8_t sSTOP[] PROGMEM = "STOP\r\n";

const uint8_t sNEXT[] PROGMEM = "NEXT\r\n";

const uint8_t sPREVIOUS[] PROGMEM = "PREVIOUS\r\n";

const uint8_t sRING[] PROGMEM = "RING\r\n";

const uint8_t sIDENTIFY[] PROGMEM = "Audi Concert I Multimedia Gateway Ver.";

const uint8_t sNEWLINE[] PROGMEM = "\r\n";

const uint8_t sDASH[] PROGMEM = "_";

const uint8_t sHEX[] PROGMEM = {

  '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0, 'A', 0, 'B', 0, 'C', 0, 'D', 0, 'E', 0, 'F', 0

};

const uint8_t sVERSION[] PROGMEM = {

  VER_MAJOR, '.', VER_MINOR, VER_PATCHLEVEL, 0

};
#endif




uint8_t sendreg;

uint8_t sendbitcount; // Used in SendByte routine



uint8_t disc;

uint8_t track;

uint8_t minute;

uint8_t second;



uint8_t scanptr; // pointer to command byte to inspect next

uint8_t fsr;

uint8_t scanbyte; // most recently retrieved command byte

uint8_t cmdcode; // command code received from head unit (byte 3)



// these storage bytes are for the ISR to save process state so that it

// doesn't adversely affect the main loop code. you must -not- use these

// variables for anything else, as the ISR -will- corrupt them.



uint8_t intwsave;

uint8_t intstatussave;

uint8_t intfsrsave;



// the 'capbusy' flag will be set when the ISR is busy capturing a command

// packet from the head unit. The TMR0 ISR will clear it once the recieve

// timeout has been exceeded or the PWTX capture ISR will clear it once

// 32 bits have been captured (command packets are supposed to be 32 bits

// long only).



uint8_t capbusy;



// 'mix' and 'scan' flags specify whether we want to light up the MIX light

// or SCAN display on the head unit.



uint8_t mix;

uint8_t scan;

uint8_t playing;

uint8_t cd_button = 0;



// The ISR will set 'dataerr' flag if it detected a framing error

// or 'overflow' if it overflowed the capture buffer queue.

uint8_t overflow;

uint8_t dataerr;



#ifdef DUMPMODE

// The ISR will set 'startbit' flag if it detected a start bit.

uint8_t startbit;

#endif







uint16_t captime; // timer count of low pulse (temp)

int8_t capbit; // bits left to capture for this byte

int8_t capbitpacket; // bits left to capture for the entire packet

uint8_t capptr; // pointer to packet capture buffer loc



uint8_t BIDIstate; // pointer to the current state handler routine

int8_t BIDIcount; // counts how long to stay in current state

uint8_t ACKcount; // number of ACK bits to set.

uint8_t discload; // next disc number to load



int8_t poweridentcount; // counts down until we should send VWCDPICx.x

uint8_t secondcount; // counts down until one second has passed

int8_t scancount; // used to count down displaying SCAN mode



uint8_t txinptr;

uint8_t txoutptr;

uint8_t display_byte_buffer_mau8[8]; // holds display bytes sent to the head unit

uint8_t const *txbuffer[TX_BUFFER_END]; // 39-26-1 = 12 serial output strings queue

uint8_t capbuffer[CAP_BUFFER_END]; // 64-39-1 = 24 bytes for head unit command

uint8_t counter_10ms_u8 = 0; // counter for 10ms intervals

uint8_t flag_50ms = false; // indicates that a period of 50ms isover
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
uint8_t counter_timer0_overflows = 0; //timer0 overflow counts to calc 10ms
#endif

/* -- Modul Global Function Prototypes ------------------------------------- */



static void ScanCommandBytes(void);

static void DumpFullCommand(void);

static void DecodeCommand(void);

static uint8_t GetCaptureByte(void);

static void SetStateIdle(void);

static void SetStatePlay(void);

static void SetStateInitPlay(void);

static void SetStatePlayLeadIn(void);

static void SetStateTrackLeadIn(void);

static void SendDisplayBytes(void);

static void SendDisplayBytesNoCD(void);

static void SendDisplayBytesInitCD(void);

static void SendFrameByte(uint8_t byte_u8);

static void SendByte(uint8_t byte_u8);

static void EnqueueString(const uint8_t *addr PROGMEM);

static void EnqueueHex(uint8_t hexbyte_u8);

static void ResetTime(void);

static void SetStateIdleThenPlay(void);

static void SetStateTP(void);

static void SendStateIdle(void);

static void SendStatePlayLeadInEnd(void);

static void SendPacket(void);

static void SendStateInitPlayEnd(void);

static void SendStateInitPlayAnnounceCD(void);

static void SendStatePlayLeadInAnnounceCD(void);

static void SendStateTP(void);

static void printstr_p(const char *s);

#define TRUE 1

#define FALSE 0



/* -- Makros --------------------------------------------------------------- */



/* -- Implementation Functions --------------------------------------------- */



//-----------------------------------------------------------------------------

/*!
 
 \brief     Init_VWCDC
 
 
 
 initialization for cdc protocol
 
 
 
 \author     Koelling
 
 \date       26.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



void Init_VWCDC(void)

{
  cli();
  //on arduino timer0 is used for millis(), we change prescaler, but also need to disable overflow interrupt
  TIMSK0 = 0x00;


  //  DDRA |= _BV(DDA6); // debug pin
  
  RADIO_CLOCK_DDR |= _BV(RADIO_CLOCK);

  RADIO_DATA_DDR  |= _BV(RADIO_DATA);

  RADIO_COMMAND_DDR &= ~_BV(RADIO_COMMAND); // input capture as input

  RADIO_COMMAND_PORT |= _BV(RADIO_COMMAND); // enable pull up





  //Timer1 init

  //Used for timing the incoming commands from headunit

  TCCR1A = 0x00; // Normal port operation, OC1A/OC1B/OC1C disconnected

  TCCR1B = _BV(ICNC1); // noise canceler, int on falling edge

  TCCR1B |= _BV(CS11); // prescaler = 8 -> 1 timer clock tick is 0.5µs long





  //Timer 5 Init

  //Timer 5 used to time the intervals between package bytes

  OCR5A = 175; // 4µs x 175 = 700µs
  TCCR5A=TCCR5B=0;
  TCCR5A |= _BV(WGM52); // Timer5 in CTC Mode

  TCCR5B |= _BV(CS51); // prescaler = 64 -> 1 timer clock tick is 4us long
    TCCR5B |= _BV(CS50);





  capptr = 0; // indirect pointer to capture buffer

  scanptr = 0;

  capbit = -8;

  txinptr = 0; // queue pointers

  txoutptr = 0;



  capbusy = FALSE; // reset flags

  mix = FALSE;

  scan = FALSE;

  playing = FALSE;

  overflow = FALSE;

  dataerr = FALSE;



#ifdef DUMPMODE

    startbit = FALSE;

#endif

  ACKcount = 0;



  // these values can be set depending on the state of mp3

  // it has to be evaluated wether CD number can be grater than 6

  disc = 0x41; // CD 1

    track = 0x01; // track 1



    poweridentcount = POWERIDENTWAIT;



  ResetTime();

  SetStateIdleThenPlay();



  TIFR1 |= _BV(ICF1); // clear pending interrupt

  TIMSK1 |= _BV(ICIE1); // enable input capture interrupt on timer1


  EnqueueString(sIDENTIFY);

  EnqueueString(sVERSION);

  EnqueueString(sNEWLINE);

  EnqueueString(sRING);


  //Timer 0 init

  //Timer 0 used to time the interval between each update

#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)

  //no CTc mode, we must overflow
  TIMSK |= _BV(TOIE0);

  TCCR0B |= _BV(CS00) + _BV(CS01); // prescaler = 64 -> timer clock tick is 4us long
  
  //timer0 overflow after 256counts, oveflow interup routine is fired every 1024us (4*256)
  //we need 50 overflows to count to 50ms
  #define _TIMER0_OVERFLOW_COUNTS 50

#else

  OCR0A = _10MS; // 10ms Intervall

  TCCR0A = 0x00; // Normal port operation, OC0 disconnected

  TCCR0A |= _BV(WGM01); // CTC mode 

  TCCR0B |= _BV(CS00) + _BV(CS02); // prescaler = 1024 -> 1 timer clock tick is 64us long

  TIMSK0 |= _BV(OCIE0A); // enable output compare interrupt on timer0

#endif






  SendPacket(); // force first display update packet


sei();
//    SREG |= 0x80;   // enable interrupts

}

//-----------------------------------------------------------------------------

/*!
 
 \brief    ISR(TIMER2_COMPA_vect)
 
 
 
 Timer2 ensures 700µs timing between display package bytes
 
 Shift bytes out to head unit
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



ISR(TIMER5_COMPA_vect)
{
  static uint8_t display_byte_counter_u8 = 0;
  uint8_t byte_u8;
  TCCR5B &= ~_BV(CS50); // stop Timer5
  TCCR5B &= ~_BV(CS51);
  TCNT5 = 0; // clear Timer2
  TIFR5 |= _BV(OCF5A);

  if (display_byte_counter_u8 < 8)
  {
    byte_u8 = display_byte_buffer_mau8[display_byte_counter_u8];

#ifdef DUMPMODE2
    Serial.print("|");
    Serial.print(byte_u8,HEX);
    Serial.print("|");
#endif

    for (sendbitcount = -8; sendbitcount != 0; sendbitcount++)
    {
      RADIO_CLOCK_PORT |= _BV(RADIO_CLOCK); // SCLK high
      _delay_loop_1(40);
      if ((byte_u8 & 0x80) == 0) // mask highest bit and test if set
      {
        RADIO_CLOCK_PORT |= _BV(RADIO_DATA); // DATA high
      }
      else
      {
        RADIO_CLOCK_PORT &= ~_BV(RADIO_DATA); // DATA low
      }

      byte_u8 <<= 1; // load the next bit
      RADIO_CLOCK_PORT &= ~_BV(RADIO_CLOCK); // SCLK low
      _delay_loop_1(40);
    }
    display_byte_counter_u8++;
    TCCR5B |= _BV(CS51); // prescaler = 64 -> 1 timer clock tick is 4us long
    TCCR5B |= _BV(CS50);

  }
  else
  {
    display_byte_counter_u8 = 0;
    TIMSK5 &= ~_BV(OCIE5A); // disable output compare interrupt on timer5
  }
}



//-----------------------------------------------------------------------------

/*!
 
 \brief     ISR(TIMER0_COMP_vect)
 
 *on atmega8 overflow is used
 
 
 
 timer0 output compare interrupt service routine for cdc protocol
 
 radio display update
 
 
 
 \author     Koelling
 
 \date       04.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------


#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)

ISR(TIMER0_OVF_vect){
  counter_timer0_overflows++;

  if(counter_timer0_overflows = _TIMER0_OVERFLOW_COUNTS )
  {
    counter_timer0_overflows=0;

      flag_50ms = TRUE;

  }
  TIFR &= ~(1 << TOV0);
  TCNT0 = 5;// to get overflowed after 1000us 1024-(6x4us)=1000us  counting from 0... 0,1,2,3,4,5 = 6ticks
}

#else

ISR(TIMER0_COMPA_vect)

{

  counter_10ms_u8++;

  if (counter_10ms_u8 == 5)

  {

    counter_10ms_u8 = 0;

    flag_50ms = TRUE;

  }

}
#endif


//-----------------------------------------------------------------------------

/*!
 
 \brief     ISR(TIMER1_OVF_vect)
 
 
 
 timer1 overflow interrupt service routine for cdc protocol
 
 
 
 \author     Koelling
 
 \date       26.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



ISR(TIMER1_OVF_vect)

{

  //Serial.println("TIMER1_OVF_vect");

  TIMSK1 &= ~_BV(TOIE1); // disable further timer 1 interrupts

  capbusy = FALSE; // set flag signifying packet capture done



  if (capbit > -8) // are we already capturing on a blank byte?

  {

    dataerr = TRUE;

    // Note: This should never happen on normal head unit sending 32 bit

    //        command strings with error free data.

    //

    // if the capture bits were not a complete 8 bits, we need to finish

    // rotating the bits upward so that the data is nicely formatted



    while (capbit != 0) // have we finished rotating all bits up?

    {

      capbuffer[capptr] <<= 1; // rotate in 0 bit

      capbit++;

    }

    capbit = -8;

    capptr++; // move to new capture byte

    if (capptr == CAP_BUFFER_END) // have we gone past the end of the

    { // capture buffer?

      capptr = 0; // yes, roll over to beginning

    }

    if (capptr == scanptr) // have we overflowed the capture queue?

    {

      overflow = TRUE; // yes, set error flag

    }

  }

}



//-----------------------------------------------------------------------------

/*!
 
 \brief     ISR(TIMER1_CAPT_vect)
 
 
 
 input capture interrupt service routine for cdc protocol
 
 
 
 \author     Koelling
 
 \date       26.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



ISR(TIMER1_CAPT_vect)

{

  captime = ICR1; // save a copy of current TMR1 count

  // in case PWTXCaptureBit needs it

  TCNT1 = 0; // clear timer1



  if ((RADIO_COMMAND_PIN & _BV(RADIO_COMMAND)) == 0)

  {

    // We have interrupted at beginning of low pulse (falling edge)

    // Low pulse length must be timed to determine bit value



    TIFR1 |= _BV(TOV1); // clear timer1 overflow flag

    TIMSK1 |= _BV(TOIE1); // enable timer1 interrupt on overflow

    TCCR1B |= _BV(ICES1); // change input capture to rising edge

    TIFR1 |= _BV(ICF1); // clear input capture interrupt request flag

  }

  else

  {

    // We have interrupted at beginning of high pulse (rising edge)

    // High pulse length doesn't matter. We need to check out

    // captured low pulse width if we are capturing data at the moment

    capbusy = TRUE;

    TCCR1B &= ~_BV(ICES1); // change input capture to falling edge

    TIFR1 |= _BV(ICF1); // clear input capture interrupt request flag



    if (TIMSK1 & _BV(TOIE1)) // are we trying to capture data?

    {

      capbusy = TRUE;

      TIMSK1 &= ~_BV(TOIE1); // turn off capturing time for high pulse

      //Serial.println(captime);

      if (captime > STARTTHRESHOLD)

      { // yes, start bit

#ifdef DUMPMODE

        startbit = TRUE;

#endif

        capbitpacket = PKTSIZE;

        // don't store start bits, just frame around them

        if (capbit > -8) // are we already capturing on a blank byte?

        {

          dataerr = TRUE;

          // Note: This should never happen on normal head unit sending 32 bit

          //       command strings with error free data.

          //

          // if the capture bits were not a complete 8 bits, we need to finish

          // rotating the bits upward so that the data is nicely formatted



          while (capbit != 0) // have we finished rotating all bits up?

          {

            capbuffer[capptr] <<= 1; // rotate in 0 bit

            capbit++;

          }

          capbit = -8;

          capptr++; // move to new capture byte

          if (capptr == CAP_BUFFER_END) // have we gone past the end of the

          { // capture buffer?

            capptr = 0; // yes, roll over to beginning

          }

          if (capptr == scanptr) // have we overflowed the capture queue?

          {

            overflow = TRUE; // yes, set error flag

          }

        }

      }

      else

      { // no, just a regular data bit

        if (captime > LOWTHRESHOLD)

        { // yes, go ahead and store this data

          capbuffer[capptr] <<= 1; // nope



          if (captime > HIGHTHRESHOLD)

          {

            capbuffer[capptr] |= 1;

          }

          capbitpacket++;

          if (capbitpacket == 0)

          {

            // we've received PKTSIZE number of bits, so let's assume that we're done

            // capturing bits for now.

            capbusy = FALSE; // clear capture busy flag

          }

          capbit++;

          if (capbit == 0) // have we collected all 8 bits?

          { // yep, get ready to capture next 8 bits

            capbit = -8;

            capptr++; // move to new capture byte

            if (capptr == CAP_BUFFER_END) // have we gone past the end of the

            { // capture buffer?

              capptr = 0; // yes, roll over to beginning

            }

            if (capptr == scanptr) // have we overflowed the capture queue?

            {

              overflow = TRUE; // yes, set error flag

            }

          }

        }

      }

    }

  }

}



//-----------------------------------------------------------------------------

/*!
 
 \brief     CDC_Protocol(void)
 
 
 
 cyclic called main program for cdc protocol (50ms?)
 
 
 
 \author     Koelling
 
 \date       26.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



void CDC_Protocol(void)

{

  uint8_t decimal_adjust_u8;



  if (flag_50ms == TRUE)

  {

    flag_50ms = FALSE;

    SendPacket();

    scancount++;

    if (scancount == 0)

    {

      scancount = SCANWAIT;

      scan = FALSE; // turn off scan display

    }

    secondcount++;

    if (secondcount == 0)

    {

      secondcount = SECONDWAIT;

      poweridentcount++;


      if (poweridentcount == 0)

      {

        poweridentcount = POWERIDENTWAIT;

        EnqueueString(sIDENTIFY);

        EnqueueString(sVERSION);

        EnqueueString(sNEWLINE);

      }

      second++; // increment the time display

      decimal_adjust_u8 = second & 0x0F; // skip past hexidecimal codes

      if (decimal_adjust_u8 == 0x0A) // are with at xA?

      {

        second += 6; // yes, add 6 and we'll be at x0 instead

      }

      if (second == 0x60)

      {

        second = 0;

        minute++;

        decimal_adjust_u8 = minute & 0x0F; // skip past hexidecimal codes

        if (decimal_adjust_u8 == 0x0A) // are with at xA?

        {

          minute += 6; // yes, add 6 and we'll be at x0 instead

        }

        if (minute == 0xA0) // have we gone beyond 99 minutes?

        {

          minute = 0;

        }

      }

    }

  }



  if (overflow == TRUE) // has the command receive code detected

  { // an overflow error?

    overflow = FALSE; // clear error flag

    EnqueueString(sOVERFLOW);

  }

  if (dataerr == TRUE) // has the command receive code detected

  { // a framing type data error?

    dataerr = FALSE; // clear error flag

    EnqueueString(sDATAERR);

  }

#ifndef DUMPMODE

  ScanCommandBytes();

#else

  if (startbit == TRUE) // have we just recieved a start bit?

  {

    startbit = FALSE;

    EnqueueString(sNEWLINE); // yes, start a new line

  }

  fsr = scanptr;

  while (GetCaptureByte() == TRUE)

  {

    scanptr = fsr;

    EnqueueHex(scanbyte);

  }

#endif





  while (txoutptr != txinptr)

  {

    printstr_p((char*) txbuffer[txoutptr]);

    txoutptr++;

    if (txoutptr == TX_BUFFER_END)

    {

      txoutptr = 0;

    }

  }

}




//-----------------------------------------------------------------------------

/*!
 
 \brief    void DecodeCommand(void)
 
 
 
 decode cmdcode and do required actions
 
 
 
 ;--------------------------------------------------------------------------
 
 ; Button Push Packets
 
 ;--------------------------------------------------------------------------
 
 ; 532C609F Mix 1
 
 ; 532CE01F Mix 6
 
 ; 532CA05F Scan
 
 ;     Note: Blaupunkt Gamma V head unit will continue to send scan key code
 
 ;       unless display is switched into scan mode.
 
 ;       (reported by tony.gilbert@orange.co.uk)
 
 ; 532C10EF Head Unit mode change. Emitted at power up, power down, and
 
 ;        any mode change. (disable playing)
 
 ; 532C58A7 Seek Back Pressed
 
 ; 532CD827 Seek Forward Pressed
 
 ; 532C7887 Dn
 
 ; 532CA857 Dn on Mk3 premium (Adam Yellen <adam@yellen.com>)
 
 ; 532CF807 Up
 
 ; 532C6897 Up on Mk3 premium (Adam Yellen)
 
 ; 532C38C7 CD Change (third packet)
 
 ; 532CE41B Seek Forward Released (enable playing)
 
 ; 532CE41B Seek Back Released (enable playing)
 
 ; 532CE41B CD Mode selected. Emitted at power up (if starting in CD
 
 ;            mode), change to CD mode. (enable playing)
 
 ; 532C14EB CD Change (second packet)
 
 ; 532C0CF3 CD 1 (first packet)
 
 ; 532C8C73 CD 2 (first packet)
 
 ; 532C4CB3 CD 3 (first packet)
 
 ; 532CCC33 CD 4 (first packet)
 
 ; 532C2CD3 CD 5 (first packet)
 
 ; 532CAC53 CD 6 (first packet)
 
 ;
 
 ; Monsoon State Changes:
 
 ; 532CE41B enable playing (transition to State 2)
 
 ; 532C38C7 disc loaded inquiry (transition to State 5)
 
 ; 532C10EF disable playing (transition to State 1)
 
 ;--------------------------------------------------------------------------
 
 
 
 \author     Koelling
 
 \date       05.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void DecodeCommand(void)

{

  uint8_t decimal_adjust_u8 = 0;

#ifdef JUST_HEX_TO_SERIAL
  Serial.write(cmdcode);
#endif

  switch (cmdcode) {

  case Do_CHANGECD:

    // Head unit seems to send this after each CDx number change

    // but the CD Changer seems to completely ignore (doesn't even ACK it).

    ACKcount = 0; // do not ack this command
#ifdef PJRC
    EnqueueString(sRANDOM);
#endif

    break;



  case Do_ENABLE:

  case Do_ENABLE_MK:

    mix = FALSE;

    if (playing == FALSE)

    {

      SetStateInitPlay(); // skip this if already playing

    }
 
    EnqueueString(sMENABLE);

    break;



  case Do_LOADCD:

    if (playing == TRUE)

    {

      SetStateInitPlay(); // skip this if we're in idle mode

    }

    ResetTime();

    EnqueueString(sMINQUIRY);

    break;



  case Do_DISABLE:

    SetStateIdle(); // skip this if we're already in idle mode

#ifndef DISC_TRACK_NUMBER_FROM_MPD

//      disc = 0x41; // set back to CD 1

#endif

      EnqueueString(sMDISABLE);

    break;



  case Do_SEEKBACK:

  case Do_PREVCD:

    ResetTime();

   EnqueueString(sPRV_LIST);


#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc--;

    if ((disc & 0x0F) == 0)

    {

      disc = 0x46; // set back to CD 1

    }
#endif
    break;



  case Do_SEEKFORWARD:    

  case Do_SEEKFORWARD_MK:

    ResetTime();

    if (cd_button == FALSE) // mk don't increment when previous command was a cd button

    {

      EnqueueString(sNXT_LIST);

#ifndef DISC_TRACK_NUMBER_FROM_MPD
    
      disc++;

      if (disc > 0x46)

      {

        disc = 0x41;

      }

#endif

      // Going beyond CD9 displays hex codes on premium head unit.

      // Examples: "CD A"

      //           "CD B"

      //           "CD C" etc...

      //

      // However, going beyond CD6 mutes audio on monsoon head unit, so we

      // definitely don't want to do that.

    }

    else

    {

      cd_button = FALSE; // mk clear cd button flag

    }
    
    break;



  case Do_MIX:

  case Do_MIX_CD:

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    if (mix == FALSE)

    {

      mix = TRUE;

    }

    else

    {

      mix = FALSE;

    }

#endif

    EnqueueString(sRANDOM);

    break;



  case Do_PLAY:

    EnqueueString(sPLAY); // this will make the PJRC play/pause

    break;



  case Do_SCAN:



    scancount = SCANWAIT;

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    if (scan == FALSE)

    {

      scan = TRUE;

    }

    else

    {

      scan = FALSE;

    }

#endif

#ifdef PJRC
    EnqueueString(sPLAY); // this will make the PJRC play/pause
#else
    EnqueueString(sSCAN); // 
#endif
    break;



  case Do_UP:

  case Do_UP_MK3:

    if (playing == TRUE) // skip track lead-in if not in play mode

    {

      SetStateTrackLeadIn();

    }

    ResetTime();

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    track++;

    decimal_adjust_u8 = track & 0x0F; // skip past hexidecimal codes

    if (decimal_adjust_u8 == 0x0A) // are with at xA?

    {

      track += 6; // yes, add 6 and we'll be at x0 instead

    }

    if (track == 0xA0) // have we gone beyond Track 99?

    { // yes, rollover to Track 01 so that jog wheels

      track = 1; // can continue rolling (Audi Concert II)

    }
    
#endif
    
    EnqueueString(sNEXT);

    break;



  case Do_DOWN:

  case Do_DOWN_MK3:

    if (playing == TRUE) // skip track lead-in if not in play mode

    {

      SetStateTrackLeadIn();

    }

    ResetTime();

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    decimal_adjust_u8 = track & 0x0F; // skip past hexidecimal codes

    if (decimal_adjust_u8 == 0) // are we at x0?

    {

      track -= 6; // yes, subtract 6 and we'll be at x9 instead

    }

    track--;

    if (track == 0) // have we gone below Track 1?

    { // yes, rollover to Track 99 so that jog wheels

      track = 0x99; // can continue rolling (Audi Concert II)

    }
    
#endif
    
    EnqueueString(sPREVIOUS);

    break;



  case Do_CD1:

    cd_button = TRUE; // mk store cd button pressed
    
#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc = 0x41; // set CD 1

#endif

      EnqueueString(sLIST1);

    break;



  case Do_CD2:

    cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc = 0x42; // set CD 2

#endif

    EnqueueString(sLIST2);

    break;



  case Do_CD3:

    cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc = 0x43; // set CD 3

#endif

    EnqueueString(sLIST3);

    break;



  case Do_CD4:

    cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc = 0x44; // set CD 4

#endif

    EnqueueString(sLIST4);

    break;



  case Do_CD5:

    cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc = 0x45; // set CD 5

#endif

    EnqueueString(sLIST5);

    break;



  case Do_CD6:

    cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

    disc = 0x46; // set CD 6

#endif

    EnqueueString(sLIST6);

    break;

    case Do_TP:
      if (playing == TRUE) {
        SetStateTP();
      } else {
        SetStateInitPlay();
      }
      break;

  default:



/* if execution reaches here, we have verified that we got
 * a valid command packet, but the command code received is not
 * one that we understand.
 *
 * Dump the unknown command code for the user to view.
 */



    EnqueueString(sDASH);

    EnqueueHex(cmdcode);

    EnqueueString(sNEWLINE);

    break;

  }

}

int main()

{
#ifdef BLUETOOTH
  Serial.begin(115200);
#else
  Serial.begin(9600);
#endif

  Init_VWCDC();

#ifdef DISC_TRACK_NUMBER_FROM_MPD
  //start in idle mode
  SetStateIdle();
#endif
  

  while (1)

  {

#ifdef DISC_TRACK_NUMBER_FROM_MPD
  if (Serial.available() > 0) {
                  int r = Serial.read();
		//r has new data
		if(r <= 0xFF)
		{
			//send CD No.
			if((r & 0xF0) == 0xC0)
			{
				if (r == 0xCA)
                                        {
                                          scan = TRUE;
                                        }
				else if (r == 0xCB)
                                        {
					  mix = TRUE;
                                        }
				else if (r == 0xCC)
                                        {
                                          SetStatePlay();
                                        }
				else if (r == 0xCD)
                                        {
                                          mix = FALSE;
                                          scan = FALSE;
                                          playing=FALSE;
                                          SetStateIdle();
                                        }
                                else if (r == 0xCE)
                                        {
                                          mix = FALSE;
                                        }                                
				else
					if ((r & 0x0F) != ( disc & 0x0F))
                                          { 
                                          disc = (r & 0x4F);
                                          }
			}
			//send TR No.
			else 
				if (track != r)
                                  {track = r;
                                    ResetTime();
                                  }
		}
  }
#endif

    CDC_Protocol();

  }



}



static void printstr_p(const char *s)

{

  char c;



  for (c = pgm_read_byte(s); c; ++s, c = pgm_read_byte(s))

  {
    Serial.print(c);
    
    if (c == '\n')

      break;

  }

}

// eof //

 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Ну а за денежку кто нибудь согласится помочь?, я не совсем уж наглец, чужое потраченное время ценю, я ардуино специально купил чтоб, собрать это устройство (эммулятор сд чейнджера), отступать уже поздно, жалко потраченных денег на компоненты, не получив то чего хотел.. Поэтому прошу помощи не безвозмездно 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Проблема, конкретно в том что магнитола не определяет устройство, как сд чейнджер

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Фото подключения ?

StepaVVka
Offline
Зарегистрирован: 29.07.2019

 

 

audi concert pin ------------- arduino pin

data-out      -----------------    d8

clock    ---------------------     d13

data-in  --------------------      d11

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

А общая земля где ? Не факт что это взлетит с этой платой на 3.3 V.

sadman41
Offline
Зарегистрирован: 19.10.2016

Плата нормальная, там отдельный стаб на 3,3V, о чём написано. А вот земли отдельной (COM) на магнитолу не видать. Конечно, есть вариант, что она с питанием приходит. 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Плата запитана от магнитолы ? На сам чип какое питание приходит 3.3 или 5 ? 

MEGA надо подключать как написано в строках 198-200

sadman41
Offline
Зарегистрирован: 19.10.2016

К кому вопрос? На этой меге два стаба - 5V и 3,3V. МК работает на 5V/16Mhz. По фото питание засунуто в VIn, т.е. напряжение подаётся на МК через AMS1117-5.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Питание отдельное у ардуино  от 5в шины блока питания ATX, магнитола запитана от него же только 12 вольт. Просто дома больше нечем запитать 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Спасибо, а где эти порты у меня нету таких портов на меге?

StepaVVka
Offline
Зарегистрирован: 29.07.2019

sadman41 пишет:

К кому вопрос? На этой меге два стаба - 5V и 3,3V. МК работает на 5V/16Mhz. По фото питание засунуто в VIn, т.е. напряжение подаётся на МК через AMS1117-5.

т.е. я не правильно питание подал?  Просто извините парни, что мозг еб* , я первый раз с ардуино и микроконтролерами связался.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

komandir, sadman41 парни может кто нибудь возьмется, помочь мне ? не за бесплатно, по цене договоримся

StepaVVka
Offline
Зарегистрирован: 29.07.2019

ах да сейчас посмотрел как я подключил к блоку питания, масса магнитолы и ардуино взята с одной точки 

 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

bluetooth модуля на фото нет, потому что еще не подключал его, так, как проблема в другом что магнитола не видит ардуинку

StepaVVka
Offline
Зарегистрирован: 29.07.2019
C:\Users\Администратор\Documents\Arduino\sketch_jul25a\cdc_arduino_ported_k9spud_vwcdpic_for_mega\cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino:186:0: warning: "RADIO_COMMAND" redefined
 
C:\Users\Администратор\Documents\Arduino\sketch_jul25a\cdc_arduino_ported_k9spud_vwcdpic_for_mega\cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino:185:0: note: this is the location of the previous definition
 
C:\Users\Администратор\Documents\Arduino\sketch_jul25a\cdc_arduino_ported_k9spud_vwcdpic_for_mega\cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino:191:0: warning: "RADIO_CLOCK" redefined
 
C:\Users\Администратор\Documents\Arduino\sketch_jul25a\cdc_arduino_ported_k9spud_vwcdpic_for_mega\cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino:190:0: note: this is the location of the previous definition
 
C:\Users\Администратор\Documents\Arduino\sketch_jul25a\cdc_arduino_ported_k9spud_vwcdpic_for_mega\cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino:195:0: warning: "RADIO_DATA" redefined
 
C:\Users\Администратор\Documents\Arduino\sketch_jul25a\cdc_arduino_ported_k9spud_vwcdpic_for_mega\cdc_arduino_ported_k9spud_vwcdpic_for_mega.ino:194:0: note: this is the location of the previous definition
 
Скетч использует 3660 байт (1%) памяти устройства. Всего доступно 253952 байт.
Глобальные переменные используют 240 байт (2%) динамической памяти, оставляя 7952 байт для локальных переменных. Максимум: 8192 байт.
 
Прикладываю лог, при заливки скетча
negavoid
Offline
Зарегистрирован: 09.07.2016

StepaVVka, вы понимаете, что возмездная помощь будет стоить дороже, чем новая навороченная магнитола с экраном для фильмов?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018
 
0198 //#define RADIO_COMMAND 49 //PL0(ICP4)
0199 //#define RADIO_DATA  43 //PL6
0200 //#define RADIO_CLOCK 42 //PL7

Написаны номера ног 49 43 42 - что тут не ясного ? На плате же есть дырочки с такими номерами ??? 8 11 13 нашли же как то ???

StepaVVka
Offline
Зарегистрирован: 29.07.2019

тогда да я переподключил, правильно, уже дошло что это пины d49 d43 d42

StepaVVka
Offline
Зарегистрирован: 29.07.2019

negavoid пишет:

StepaVVka, вы понимаете, что возмездная помощь будет стоить дороже, чем новая навороченная магнитола с экраном для фильмов?

я тот человек который выкинул такую магнитолу, и купил штатную, что бы придать олдскульности салону автомобиля, но добавить современные плюшки .. Поэтому готов платить, тем более с нуля код писать не нужно есть же исходник, только помочь запустить, потому что с ардуино впервые

StepaVVka
Offline
Зарегистрирован: 29.07.2019

просто меня смутили, обозначения pl6 pl7 и тд

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Komandir? возьмешься мне помочь? оплатить могу только на карту или яндекс деньги... Все равно не определяет магнитола, сд чейнджер.. Магнитола точно исправная, потому, что я на этой магнитоле другой скетч запускал в связке с ардуино нано, но там был только аукс, без модуля блютуз 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

ИМХО надо 49 и 43 поменять местами.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Komandir пишет:

ИМХО надо 49 и 43 поменять местами.

ОК, попробую

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Нет, поменял местами 49,43 все равно не определяет, там в логе при прошивке выше я скинул, вылазят какие то ошибки, может в них дело?

sadman41
Offline
Зарегистрирован: 19.10.2016

RADIO_COMMAND и др. дефайны должны быть в одном экземпляре. Один раскомментарен, остальные закомментарены.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

186 191 195 строки можно закомментировать, но дело не в них думаю.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Komandir пишет:
186 191 195 строки можно закомментировать, но дело не в них думаю.

ок, попробую, все же стоит попытаться 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

закоментировал строки, скетч загрузился без ошибок

StepaVVka
Offline
Зарегистрирован: 29.07.2019

#define RADIO_ACC 3 //PE5 (INT5)

что за строка? зажигание ACC ?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Radio_acc нигде не использовано в коде.
Не знаю как пережили устройства "выход на выход" при неверном порядке 43 49.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Komandir пишет:
Radio_acc нигде не использовано в коде. Не знаю как пережили устройства "выход на выход" при неверном порядке 43 49.

А можно это как то проверить? ну всмысле, залить какой нибудь тестовый скетч, и замерить мультиметром что на выходе?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

В проектах есть мой виртуальный осциллограф, можно написать скетч моргающий выводами и посмотреть как оно на самом деле

магнитолу проверить подключив к ней UNO рабочую, о которой речь шла выше

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Только что, подключил atmega328, все работает, магнитола определила устройство.

Скетч вот этот

/*****************************************************************************
 Audi/Volkswagen Audi Interface
 Target: arduino atmega328(tested)
 attinu85 (tested)
 Author: Vincent
 Date: January, 2011
 Version: 0.01
 Originally ported from VWCDPIC Project:
 http://www.k9spud.com/vwcdpic/
 Ported from Matthias Koelling's AVR Code:
 www.mikrocontroller.net/attachment/31279/vwcdc.c
   ---------------------------------
 16. Mar 2015:
 https://github.com/tomaskovacik/
 arduino duemilanove works:
 UNO,Duemilanove,nanoe ... atmegax8 base boards:
 RADIO PIN -> arduino pin
 DataOut -> digital 2 (INT0)
 DataIn -> digital 11(PB3)
 Clock -> digital 13(PB5)
 PC PIN -> arduino pin
 Serial TX -> digital 0 (PD0)
 Serial RX -> digital 1 (PD1)
 ANDROID support:
 PREVIOUS BUTTON -> digital 7 (PD7)
 PLAY BUTTON -> digital 6 (PD6)
 NEXT BUTTON -> digital 5 (PD5)
 to enable android remote control over headphone buttons emulation uncoment #define ANDROID_HEADPHONES
 for one button control (SONY) uncoment #define ANDROID_HEADPHONES_ONE_BUTTON
 android headphone support, pinout:
 play button control:arduino pin 5 (chip pin 11)
 previous button control: arduino pin 9 (chip pin 15)
 next button control: arduino pin 6 (chip pin 12)
 6. Aug 2015 tomaskovacik
 - 2 8-bit timers used
 - INT0 is used
 - attiny85 pinout
 - merge with attiny85 port
 8. Oct 2015 tomas
 - init support for arduino 3-button remote control over headphone mic line
 - init support for sony single buttone remote control on headphone mic line
 ATTINYx5 version:
 RADIO PIN -> ATTINYx5 PIN
 DataOut -> 7 (INT0)
 DataIn -> 6 (PB0)
 Clock -> 5 (PB1)
 PC PIN -> ATTINYx5 PIN
 Serial TX -> 2 (PB3) using tinydebug lib
 Serial RX -> not connected
 what you need to install:
 ATTinycore: https://github.com/SpenceKonde/ATTinyCore (supported directly in arduino(from version 1.6.3) via board manager )
 TinyDebugSerial from: https://github.com/jscrane/TinyDebugSerial (download and extract into libraries Arduino folder)
 select attiny25/45/85 board from tools-> board -> (ATTinyCore) ATtiny25/45/85
 select attiny85 from tools->chip->ATtiny85
 select internal 8Mhz from tools->Clock -> 8MHz (internal)
 to use digispark uncoment line //#define DIGISPARK
 then use 16MHz-noUSB settings
 tested with ATTinyCore with Digispark support: https://github.com/tomaskovacik/ATTinyCore/
 maybe will be merged in oficial ATTinyCore in the future
   
 kovo 1.jul 2019
 - atmega324 using INT2 /on pins INT0 and INT1 is 2nd uart
 kovo 3.ju l2019
 - attiny167 using ICP1/digi10 for command and 0 and 1 for data/clk pins
 *****************************************************************************/
// #define DIGISPARK

#ifdef DIGISPARK
# include < avr/power.h>
#endif

# if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
# define TCCR2A TCCR2
# define TCCR2B TCCR2
# define COM2A1 COM21
# define COM2A0 COM20
# define OCR2A OCR2
# define TIMSK2 TIMSK
# define OCIE2A OCIE2
# define TIMER2_COMPA_vect TIMER2_COMP_vect
# define TIMSK1 TIMSK
# define TIFR1 TIFR
# define ICIE1 TICIE1
# define TIMSK0 TIMSK
# define TIFR0 TIFR
# define OCF2A OCF2
# define TCCR0A TCCR0
# define TCCR0B TCCR0
# define EIMSK GICR
# define OCIE0A OCIE0
# define EICRA MCUCR
# define EIFR GIFR
#endif

//  uncoment this to have original fSerial outputs for PJRC players
// #define PJRC

/*  enable hex control command on Serial line to control mpd control
 script with shyd.de control script
*/
// #define JUST_HEX_TO_SERIAL

/ *  enable bluetooth module control over Serial line
 XS3868
*/
// #define BLUETOOTH

/*
 read disc# track# status over serial line
*/
// #define DISC_TRACK_NUMBER_FROM_MPD

/*
 ANDROID HEADPRONES SUPPORT
 HTC: 3buttons, 220ohm previous|0ohm play/pause|470ohm next
*/
// #define ANDROID_HEADPHONES

/*
 ANDROID HEADPHONES SUPORT
 SONY: 1button mode: 1xpush play/pause;2xpush previous;3xpush next
*/
// #define ANDROID_HEADPHONES_ONE_BUTTON
   
# ifdef ANDROID_HEADPHONES_ONE_BUTTON / / just to be shure
# define ANDROID_HEADPHONES
#endif


# if defined(__AVR_ATtiny85__)
//https://github.com/jscrane/TinyDebugSerial
//#ifdef DIGISPARK
/ no softwarserial in digispark .
#include <TinyDebugSerial.h>
TinyDebugSerial mySerial = TinyDebugSerial();
//#else
//#include <SoftwareSerial.h>
//SoftwareSerial mySerial(NULL, PB3);
//#endif
// tiny has only Rx, so by default we disable all features which use TX
#undef DISC_TRACK_NUMBER_FROM_MPD
#undef ANDROID_HEADPHONES
#undef ANDROID_HEADPHONES_ONE_BUTTON
# define Serial mySerial
#else
#include <HardwareSerial.h>
#endif



/* -- Includes ------------------------------------------------------------- */

//#include <util/delay.h>

/ *  -- Configuration Parameters --------------------------------------------- */



/* -- Makros --------------------------------------------------------------- */



/* -- Defines -------------------------------------------------------------- */

# define TRUE 1



//  Low period of PWTX line:

// 0: ~650us

//  1: ~1.77ms

//  S: ~4.57ms


//  one tick is 0.5µs
# define STARTTHRESHOLD  6400             / /  greater than this signifies START bit
# define HIGHTHRESHOLD   2496        / /  greater than this signifies 1 bit.
# define LOWTHRESHOLD    512         / /  greater than this signifies 0 bit.

# define PKTSIZE-32             / /  command packets are 32 bits long.

//  do not refresh head unit faster than 5.5ms (currently not implemented)

//  5.24s slow refresh rate when head unit in FM/AM/Tape mode (not implemented)



// #define REFRESH_PERIOD 50 // default to refresh head unit every 50.0ms

# define SECONDWAIT-20          / /  wait 20 * 50ms to get 1 second (50ms*20 = 1000ms = 1s)

# define POWERIDENTWAIT-10          / /  wait 10 * 1s to 10 seconds between VWCDPICx.x display

# define SCANWAIT-100         / /  wait 100 * 50ms to get 5sec (50ms*100 = 5000ms = 5s)

# define _50MS            500

# define _700US            7

# define TX_BUFFER_END   12

# define CAP_BUFFER_END	24

// android headphones
#ifdef ANDROID_HEADPHONES

# define ANDROID_PUSH_COUNT 2  / / 100ms push - how long push take

# define ANDROID_DELAY_COUNT 1  / / 50ms delay - how long we wait between pushes

#endif

#ifdef ANDROID_HEADPHONES_ONE_BUTTON

# define ANDROID_PLAY_COUNT 1  / / how much pushes need to make it play

# define ANDROID_NEXT_COUNT 2  / / how much pushes need to make it next

# define ANDROID_PREV_COUNT 3  / / how much pushes need to make it previous

#endif

# define VER_MAJOR       ' 1 '

# define VER_MINOR       ' 1 '

# define VER_PATCHLEVEL  ' d'

# if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
# define RADIO_COMMAND PB2
#define RADIO_COMMAND_DDR  DDRB
#define RADIO_COMMAND_PORT PORTB
#define RADIO_COMMAND_PIN PINB
# define RADIO_CLOCK PB1
# define RADIO_CLOCK_DDR DDRB
# define RADIO_CLOCK_PORT PORTB
# define RADIO_DATA PB0
# define RADIO_DATA_DDR DDRB
# define RADIO_DATA_PORT PORTB

#elif defined(__AVR_ATmega328__) || defined(__AVR_ATmega328A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PA__) || defined(__AVR_ATmega328PB__) || \
      defined(__AVR_ATmega168__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) || \
 defined(__AVR_ATmega88__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega88PB__)

//INT0 = PD2
# define RADIO_COMMAND PD2
# define RADIO_COMMAND_DDR DDRD
# define RADIO_COMMAND_PORT PORTD
# define RADIO_COMMAND_PIN PIND
# define RADIO_CLOCK PB5
# define RADIO_CLOCK_DDR DDRB
# define RADIO_CLOCK_PORT PORTB
# define RADIO_DATA PB3
# define RADIO_DATA_DDR DDRB
# define RADIO_DATA_PORT PORTB

#elif defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__)

//INT2 = PD6
# define RADIO_COMMAND PB2 / / PD
# define RADIO_COMMAND_DDR DDRB
# define RADIO_COMMAND_PORT PORTB
# define RADIO_COMMAND_PIN PINB
# define RADIO_CLOCK PB7
# define RADIO_CLOCK_DDb DDB7
# define RADIO_CLOCK_DDR DDRB
# define RADIO_CLOCK_PORT PORTB
# define RADIO_DATA PB5
# define RADIO_DATA_DDb DDB5
# define RADIO_DATA_DDR DDRB
# define RADIO_DATA_PORT PORTB

# elif defined(__AVR_ATtiny167__)
//ICP1 = PA4
# define RADIO_COMMAND PA4 / / ICP1 10
# define RADIO_COMMAND_DDR DDRA
# define RADIO_COMMAND_PORT PORTA
# define RADIO_COMMAND_PIN PINA
# define RADIO_CLOCK PB1 // 1
# define RADIO_CLOCK_DDb DDB1
# define RADIO_CLOCK_DDR DDRB
# define RADIO_CLOCK_PORT PORTB
# define RADIO_DATA PB0 / / 0
# define RADIO_DATA_DDb DDB0
# define RADIO_DATA_DDR DDRB
# define RADIO_DATA_PORT PORTB

#endif

#ifdef ANDROID_HEADPHONES

# define ANDROID_NEXT PD5 / / android next button control arduino pin 5 (chip pin 11)

# define ANDROID_NEXT_DDR DDRD

# define ANDROID_NEXT_PORT PORTD


# define ANDROID_PLAY PD6 / / android play button control arduino pin 6 (chip pin 12)

# define ANDROID_PLAY_DDR DDRD

# define ANDROID_PLAY_PORT PORTD


# define ANDROID_PREV PD7 / / android previous button control arduino pin 7 (chip pin 13)

# define ANDROID_PREV_DDR DDRD

# define ANDROID_PREV_PORT PORTD

#endif

//  Command Codes

// -------------

//

//  First byte is always 53

//  Second byte is always 2C

//  Third and Fourth bytes always add up to FF

//  All command codes seem to be a multiple of 4.

//

//

// 53 2C 0C F3 CD 1

//  53 2C 10 EF DISABLE

//  53 2C 14 EB Change CD (ignored)

//  53 2C 18 E7 Previous CD (only on Audi Concert <)

//  53 2C 2C D3 CD 5 (first packet)

//  53 2C 38 C7 Change CD/Next CD (aka MINQUIRY)

//  53 2C 4C B3 CD 3 (first packet)

//  53 2C 58 A7 Seek Back Pressed

//  53 2C 60 9F Mix 1

//  53 2C 68 97 Up on Mk3 premium (Adam Yellen)

// 53 2C 78 87 Dn

//  53 2C 8C 73 CD 2 (first packet)

// 53 2C A0 5F Scan

// 53 2C A4 5B something to do with power on (Audi Concert)

// 53 2C A8 57 Dn on Mk3 premium (Adam Yellen <adam@yellen.com>)

// 53 2C AC 53 CD 6 (first packet)

//  53 2C CC 33 CD 4 (first packet)

//  53 2C D8 27 Seek Forward Pressed

//  53 2C E0 1F Mix 6

//  53 2C E4 1B ENABLE

// 53 2C F8 07 Up





// #define Do_PLAY 0x08 // mix button held down (RCD300 head unit only)

# define  Do_PLAY           0x03  / /  mix button held down (RCD300 head unit only)

# define  Do_LOADCD			0x01	/ /  not used

# define  Do_ENABLE_MK      0x08  //  mk concert1

# define  Do_CD1            0x0C  / /  CD 1

# define  Do_DISABLE        0x10  / /  DISABLE

# define  Do_CHANGECD       0x14  / /  Change CD (changer ignores & no ACK)

# define  Do_PREVCD         0x18  / /  PREVIOUS CD (Audi Concert head unit)

# define  Do_CD5            0x2C  / /  CD 5

# define  Do_TP             0x30  / /  TP info (TP button pressed)

# define  Do_SEEKFORWARD_MK 0x38  / /  mk concert 1 LOAD CD (aka MINQUIRY).

//  Also means "Next CD" if no CD button pressed

# define  Do_CD3            0x4C  / /  CD 3

# define  Do_SEEKBACK       0x58  / /  SEEK BACK

# define  Do_MIX_CD         0x60  / /  MIX 1 (mix tracks within one disc)

# define  Do_UP_MK3         0x68  / /  UP (Mk3 head unit)

# define  Do_DOWN           0x78  / /  DOWN

# define  Do_CD2            0x8C  / /  CD 2

# define  Do_SCAN           0xA0  / /  SCAN

# define  Do_UNKNOWNCMD     0xA4  / /  power on CD mode?? (Audi Concert head unit)

# define  Do_DOWN_MK3       0xA8  / /  DOWN (Mk3 head unit only)

# define  Do_CD6            0xAC  / /  CD 6

# define  Do_CD4            0xCC  / /  CD 4

# define  Do_SEEKFORWARD    0xD8  / /  Seek Forward

# define  Do_MIX            0xE0  / /  MIX 6 (mix tracks across all discs)

# define  Do_ENABLE         0xE4  / /  ENABLE

# define  Do_UP             0xF8  / /  UP

// #define DUMPMODE
// #define DUMPMODE2

enum STATES

{

 StateIdle,

 StateIdleThenPlay,

 StateInitPlay,

 StateInitPlayEnd,

 StateInitPlayAnnounceCD,

 StatePlayLeadIn,

 StatePlayLeadInEnd,

 StatePlayLeadInAnnounceCD,

 StateTrackLeadIn,

 StatePlay,
  
 StateTP

};



/* -- Types ---------------------------------------------------------------- */



/ *  -- Extern Global Variables ---------------------------------------------- */

#ifdef BLUETOOTH

const uint8_t sDATAERR[] PROGMEM = "\r\n";

const uint8_t sOVERFLOW[] PROGMEM = "\r\n";

const uint8_t sMDISABLE[] PROGMEM = "AT#MA\r\n";

const uint8_t sMENABLE[] PROGMEM = "AT#MA\r\n";

const uint8_t sMINQUIRY[] PROGMEM = "MINQUIRY\r\n";

const uint8_t sPRV_LIST[] PROGMEM = "AT#MA\r\n";

const uint8_t sNXT_LIST[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST1[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST2[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST3[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST4[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST5[] PROGMEM = "AT#MA\r\n";

const uint8_t sLIST6[] PROGMEM = "AT#MA\r\n";

const uint8_t sRANDOM[] PROGMEM = " RANDOM\r\n";

const uint8_t sPLAY[] PROGMEM = "AT#MA\r\n";

const uint8_t sSCAN[] PROGMEM = "SCAN\r\n";

const uint8_t sSTOP[] PROGMEM = " AT#MA\r\n";

const uint8_t sNEXT[] PROGMEM = "AT#MD\r\n";

const uint8_t sPREVIOUS[] PROGMEM = "AT#ME\r\n";

const uint8_t sRING[] PROGMEM = "\r\n";

const uint8_t sIDENTIFY[] PROGMEM = "\r\n";

const uint8_t sNEWLINE[] PROGMEM = "\r\n";

const uint8_t sDASH[] PROGMEM = "";

const uint8_t sHEX[] PROGMEM = "";

const uint8_t sVERSION[] PROGMEM = "";

#else

const uint8_t sDATAERR[] PROGMEM = "dataerr\r\n";

const uint8_t sOVERFLOW[] PROGMEM = " overflow\r\n";

const uint8_t sMDISABLE[] PROGMEM = "MDISABLE\r\n";

const uint8_t sMENABLE[] PROGMEM = "MENABLE\r\n";

const uint8_t sMINQUIRY[] PROGMEM = "MINQUIRY\r\n";

const uint8_t sPRV_LIST[] PROGMEM = "PRV_LIST\r\n";

const uint8_t sNXT_LIST[] PROGMEM = "NXT_LIST\r\n";

const uint8_t sLIST1[] PROGMEM = "LIST1\r\n";

const uint8_t sLIST2[] PROGMEM = "LIST2\r\n";

const uint8_t sLIST3[] PROGMEM = "LIST3\r\n";

const uint8_t sLIST4[] PROGMEM = "LIST4\r\n";

const uint8_t sLIST5[] PROGMEM = "LIST5\r\n";

const uint8_t sLIST6[] PROGMEM = "LIST6\r\n";

const uint8_t sRANDOM[] PROGMEM = " RANDOM\r\n";

const uint8_t sPLAY[] PROGMEM = "PLAY\r\n";

const uint8_t sSCAN[] PROGMEM = "SCAN\r\n";

const uint8_t sSTOP[] PROGMEM = " STOP\r\n";

const uint8_t sNEXT[] PROGMEM = "NEXT\r\n";

const uint8_t sPREVIOUS[] PROGMEM = "PREVIOUS\r\n";

const uint8_t sRING[] PROGMEM = "RING\r\n";

const uint8_t sIDENTIFY[] PROGMEM = "Audi Concert I Multimedia Gateway Ver.";

const uint8_t sNEWLINE[] PROGMEM = "\r\n";

const uint8_t sDASH[] PROGMEM = "_";

const uint8_t sTP[] PROGMEM = "TP\r\n";

const uint8_t sHEX[] PROGMEM = {

  '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0, 'A', 0, 'B', 0, 'C', 0, 'D', 0, 'E', 0, 'F', 0

};

const uint8_t sVERSION[] PROGMEM = {

  VER_MAJOR, '.', VER_MINOR, VER_PATCHLEVEL, 0

};
#endif




uint8_t sendreg;

uint8_t sendbitcount; // Used in SendByte routine



uint8_t disc=1;

uint8_t track=1;

uint8_t minute = 0;

uint8_t second = 0;



uint8_t scanptr; // pointer to command byte to inspect next

uint8_t fsr;

uint8_t scanbyte; // most recently retrieved command byte

uint8_t cmdcode; // command code received from head unit (byte 3)



// these storage bytes are for the ISR to save process state so that it

// doesn't adversely affect the main loop code. you must -not- use these

// variables for anything else, as the ISR -will- corrupt them.



uint8_t intwsave;

uint8_t intstatussave;

uint8_t intfsrsave;



// the 'capbusy' flag will be set when the ISR is busy capturing a command

// packet from the head unit. The TMR0 ISR will clear it once the recieve

// timeout has been exceeded or the PWTX capture ISR will clear it once

// 32 bits have been captured (command packets are supposed to be 32 bits

// long only).



uint8_t capbusy;



// 'mix' and 'scan' flags specify whether we want to light up the MIX light

// or SCAN display on the head unit.



uint8_t mix;

uint8_t scan;

uint8_t playing;

uint8_t cd_button = 0;

uint8_t mix_button = 0;


// The ISR will set 'dataerr' flag if it detected a framing error

// or 'overflow' if it overflowed the capture buffer queue.

uint8_t overflow;

uint8_t dataerr;



#ifdef DUMPMODE

// The ISR will set 'startbit' flag if it detected a start bit.

uint8_t startbit;

#endif







uint16_t captime; // timer count of low pulse (temp)

uint16_t captime_ovf; //overflow counts of 8bit timer1

int8_t capbit; // bits left to capture for this byte

int8_t capbitpacket; // bits left to capture for the entire packet

uint8_t capptr; // pointer to packet capture buffer loc



uint8_t BIDIstate; // pointer to the current state handler routine

int8_t BIDIcount; // counts how long to stay in current state

uint8_t ACKcount; // number of ACK bits to set.

uint8_t discload; // next disc number to load



int8_t poweridentcount; // counts down until we should send VWCDPICx.x

uint8_t secondcount; // counts down until one second has passed

int8_t scancount; // used to count down displaying SCAN mode



uint8_t txinptr;

uint8_t txoutptr;

uint8_t display_byte_buffer_mau8[8]; // holds display bytes sent to the head unit

uint8_t const *txbuffer[TX_BUFFER_END]; // 39-26-1 = 12 serial output strings queue

uint8_t capbuffer[CAP_BUFFER_END]; // 64-39-1 = 24 bytes for head unit command


uint16_t counter_50ms = _50MS; // counter for 10ms intervals 100us*500=50ms - just for counting second

int counter_to_send_packet = _50MS; // intervals betwen packets?

uint8_t flag_50ms = false; // indicates that a period of 50ms isover

uint8_t display_byte_counter_u8 = 0;

#ifdef ANDROID_HEADPHONES

//play button: tested: play button pushed for 100ms = 10 cycles of 10ms counter
int8_t play_count = 0;
//next button: tested: next button pushed for 100ms = 10 cycles of 10ms counter
#ifndef ANDROID_HEADPHONES_ONE_BUTTON
int8_t next_count = 0;
//prev button: tested: prev button pushed twise for 100ms = 2x20 cycles of 10ms counter,
uint8_t prev_count = 0;
#endif
//test: 10m between updates
uint8_t prev_count_delay = 0;
#ifdef ANDROID_HEADPHONES_ONE_BUTTON
uint8_t play_count_delay = 0;
uint8_t play_count_push = 0;
#endif
#endif


/* -- Modul Global Function Prototypes ------------------------------------- */



static void ScanCommandBytes(void);

static void DumpFullCommand(void);

static void DecodeCommand(void);

static uint8_t GetCaptureByte(void);

static void SetStateIdle(void);

static void SetStatePlay(void);

static void SetStateInitPlay(void);

static void SetStatePlayLeadIn(void);

static void SetStateTrackLeadIn(void);

static void SendDisplayBytes(void);

static void SendDisplayBytesNoCD(void);

static void SendDisplayBytesInitCD(void);

static void SendFrameByte(uint8_t byte_u8);

static void SendByte(uint8_t byte_u8);

static void EnqueueString(const uint8_t *addr PROGMEM);

static void EnqueueHex(uint8_t hexbyte_u8);

static void ResetTime(void);

static void SetStateIdleThenPlay(void);

static void SetStateTP(void);

static void SendStateIdle(void);

static void SendStatePlayLeadInEnd(void);

static void SendPacket(void);

static void SendStateInitPlayEnd(void);

static void SendStateInitPlayAnnounceCD(void);

static void SendStatePlayLeadInAnnounceCD(void);

static void SendStateTP(void);

static void printstr_p(const char *s);

static void android_buttons();

#define TRUE 1

#define FALSE 0



/* -- Makros --------------------------------------------------------------- */



/* -- Implementation Functions --------------------------------------------- */



//-----------------------------------------------------------------------------

/*!
  \brief     Init_VWCDC
  initialization for cdc protocol
  \author     Koelling
  \date       26.09.2007
  \param[in]  none
  \param[out] none
  \return     void
*/

//-----------------------------------------------------------------------------


uint8_t port=0;
void Init_VWCDC(void)

{
#ifdef DIGISPARK
clock_prescale_set(clock_div_2);
#endif

cli();
  //on arduino timer0 is used for millis(), we change prescaler, but also need to disable overflow interrupt
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
  TIMSK = 0x00;
#elif defined (__AVR_ATtiny167__)
  TIMSK0 = 0x00;
  TIMSK1 = 0x00;
#else
  TIMSK0 = 0x00;
#endif

  RADIO_CLOCK_DDR |= _BV(RADIO_CLOCK);

  RADIO_DATA_DDR  |= _BV(RADIO_DATA);

  RADIO_COMMAND_DDR &= ~_BV(RADIO_COMMAND); // input capture as input

  RADIO_COMMAND_PORT |= _BV(RADIO_COMMAND); // enable pull up

  
#ifdef ANDROID_HEADPHONES

  ANDROID_PLAY_DDR |= _BV(ANDROID_PLAY);
  ANDROID_NEXT_DDR |= _BV(ANDROID_NEXT);
  ANDROID_PREV_DDR |= _BV(ANDROID_PREV);
  ANDROID_PREV_PORT &= ~_BV(ANDROID_PREV);
  ANDROID_PLAY_PORT &= ~_BV(ANDROID_PLAY);
  ANDROID_NEXT_PORT &= ~_BV(ANDROID_NEXT);

#endif

  //attinx5 - > timer1
  //atmegax8 -> timer0
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
  TCCR1 = 0x00;
  TCNT1 = 0;
  TIMSK = 0x00;
  TCCR1 |= _BV(CS11) | _BV(CS10); //prescaler 4 @ 8MHz tick ever 0.5us but we have 8bit timer, need to catch overflows
  TIMSK |= _BV(TOIE1); //enable execution of overflow interrupt handling vector
#elif defined(__AVR_ATtiny167__) //digispark pro
  TCCR1A = 0x00; // Normal port operation, OC1A/OC1B/OC1C disconnected
  TCCR1B = _BV(ICNC1); // noise canceler, int on falling edge
  TCCR1B |= _BV(CS11); // prescaler = 8 -> 1 timer clock tick is 0.5µs long
#else //atmega chips .. timer0 is used for 100us ticks to time 700us between packet to head unit and for second (50ms mark)
  TCCR0A = 0x00;
  TCCR0B = 0x00;
  TCNT0 = 0;
  TIMSK0 = 0x00;
  TCCR0B |= _BV(CS01); //prescaler 8 @ 16MHz tick ever 0.5us but we have 8bit timer, need to catch overflows
  TIMSK0 |= _BV(TOIE0); //enable execution of overflow interrupt handling vector
#endif


  //Timer 2 init (timer0 on attin85)
  //Timer 2 used to make all 100us timing
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
  TCCR0A = 0x00; // Normal port operation, OC0 disconnected
  TCCR0A |= _BV(WGM01); // CTC mode
  TCCR0B |= _BV(CS01);// prescaler = 8 -> 1 timer clock tick is 1us long
  OCR0A = 100;//run compare rutine every 100us;
  TCNT0 = 0;
  TIMSK |= _BV(OCIE0A); // enable output compare interrupt A on timer0
#elif defined(__AVR_ATtiny167__)
  TCCR0A = 0x00; // Normal port operation, OC0 disconnected
  TCCR0B = 0x00;
  TCCR0A |= _BV(WGM01); // CTC mode
  TCCR0B |= _BV(CS01);// prescaler = 8 -> 1 timer clock tick is 1us long
  OCR0A = 100;//run compare rutine every 100us;
  TCNT0 = 0;
  TIMSK0 |= _BV(OCIE0A); // enable output compare interrupt A on timer0
#else
  TCCR2A = 0x00; // Normal port operation, OC0 disconnected
  TCCR2B = 0x00; // Normal port operation, OC0 disconnected
  TCCR2A |= _BV(WGM21); // CTC mode
  TCCR2B |= _BV(CS21);// prescaler = 8 -> 1 timer clock tick is 0.5us long @ 16Mhz
  OCR2A = 200;//run compare rutine every 100us, 0.5x200
  TCNT2 = 0;
  TIMSK2 |= _BV(OCIE2A); // enable output compare interrupt A on timer0
#endif


#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
  GIMSK |= _BV(INT0); //INT0 enable
  MCUCR |= _BV(ISC01);
  MCUCR &= ~_BV(ISC00);// falling edge fire interupt routine
#elif defined(__AVR_ATtiny167__)
  TIFR1 |= _BV(ICF1); // clear pending interrupt
  TIMSK1 |= _BV(ICIE1); // enable input capture interrupt on timer1
#elif defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__)
  EIMSK |= _BV(INT2); //INT0 enable
  EICRA |= _BV(ISC21);
  EICRA &= ~_BV(ISC20);// falling edge fire interupt routine
#else
  EIMSK |= _BV(INT0); //INT0 enable
  EICRA |= _BV(ISC01);
  EICRA &= ~_BV(ISC00);// falling edge fire interupt routine
#endif


  capptr = 0; // indirect pointer to capture buffer

  scanptr = 0;

  capbit = -8;

  txinptr = 0; // queue pointers

  txoutptr = 0;



  capbusy = FALSE; // reset flags

  mix = FALSE;

  scan = FALSE;

  playing = FALSE;

  overflow = FALSE;

  dataerr = FALSE;



#ifdef DUMPMODE

  startbit = FALSE;

#endif

  ACKcount = 0;


  // these values can be set depending on the state of mp3

  // it has to be evaluated wether CD number can be grater than 6

  disc = 0x41; // CD 1

  track = 0x01 ; // track 1

  poweridentcount = POWERIDENTWAIT;



  ResetTime();

  SetStateIdleThenPlay();

  EnqueueString(sIDENTIFY);

  EnqueueString(sVERSION);

  EnqueueString(sNEWLINE);

  EnqueueString(sRING);

  SendPacket(); // force first display update packet

  sei();

}

//-----------------------------------------------------------------------------

/*!
  \brief    ISR(TIMER2_COMPA_vect)
  Timer2 ensures 700µs timing between display package bytes
  Shift bytes out to head unit
  \author     Koelling
  \date       06.10.2007
  \param[in]  none
  \param[out] none
  \return     none
*/

//-----------------------------------------------------------------------------


  
void OutputPacket(void)
{

  static uint8_t display_byte_counter_u8 = 0;

  uint8_t byte_u8;

  if (display_byte_counter_u8 < 8)

  {

    byte_u8 = display_byte_buffer_mau8[display_byte_counter_u8];



#ifdef DUMPMODE2

    Serial.print("|");

    Serial.print(byte_u8, HEX);

    Serial.print("|");

#endif


    for (sendbitcount = -8; sendbitcount != 0; sendbitcount++)

    {

      RADIO_CLOCK_PORT |= _BV(RADIO_CLOCK); // SCLK high

      //_delay_loop_1(40);

      if ((byte_u8 & 0x80) == 0) // mask highest bit and test if set

      {

        RADIO_DATA_PORT |= _BV(RADIO_DATA); // DATA high

      }

      else

      {

        RADIO_DATA_PORT &= ~_BV(RADIO_DATA); // DATA low

      }



      byte_u8 <<= 1; // load the next bit

      RADIO_CLOCK_PORT &= ~_BV(RADIO_CLOCK); // SCLK low

      //_delay_loop_1(40);

    }

  }
  counter_to_send_packet = _700US;

  display_byte_counter_u8++;

  if (display_byte_counter_u8 == 8)
  { //wait 50ms
    display_byte_counter_u8 = 0;
    counter_to_send_packet = _50MS;
  }
}



//-----------------------------------------------------------------------------

/*!
  \brief     ISR(TIMER0_COMP_vect)
  on atmega8 overflow is used
  timer0 output compare interrupt service routine for cdc protocol
  radio display update
  \author     Koelling
  \date       04.10.2007
  \param[in]  none
  \param[out] none
  \return     void
*/

//-----------------------------------------------------------------------------

#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny167__)
ISR(TIMER0_COMPA_vect)
{

  TCNT0 = 0;
#else
ISR(TIMER2_COMPA_vect) //100us
{

  TCNT2 = 0;
#endif
  counter_50ms--;

  if (counter_to_send_packet > 0) counter_to_send_packet--; //if we are under = we sending something out...

  if (counter_50ms == 0)

  {

    counter_50ms = _50MS;

    flag_50ms = TRUE;
#ifdef ANDROID_HEADPHONES
    android_buttons();
#endif
  }

  if (counter_to_send_packet == 0)

  {
    counter_to_send_packet--; //make it -1 to stop counting..
    OutputPacket();

  }

}


//-----------------------------------------------------------------------------

/*!
  \brief     ISR(TIMER1_OVF_vect)
  timer1 overflow interrupt service routine for cdc protocol
  \author     Koelling
  \date       26.09.2007
  \param[in]  none
  \param[out] none
  \return     void
*/

//-----------------------------------------------------------------------------


#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny167__)
ISR(TIMER1_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif

{
  /*
    has 8bit timer, max value=255
    pulses are: 4500 us startbit = 9000 pulses = 35*255+75
    550 us logic 1  = 1100 pulses = 4*255+80
    1700 us logic 0  = 3400 pulses = 13*255+85
  */

#if !defined(__AVR_ATtiny167__)
  captime_ovf = captime_ovf + 0xFF;
#endif

  if (captime_ovf > 20000)//35*255= 8925, 65536 = REAL OVERFLOW
  {
    captime_ovf = 0;
    captime = 0;
    //disable timer:
    
    capbusy = FALSE;



#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
    MCUCR |= _BV(ISC01);
    MCUCR &= ~_BV(ISC00);// change input capture to falling edge
    GIFR  |= _BV(INTF0); // clear input  interrupt request flag
#elif defined(__AVR_ATtiny167__)
    TIFR1 |= _BV(ICF1); // clear pending interrupt
    TIMSK1 |= _BV(ICIE1); // enable input capture interrupt on timer1
#elif defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__)
    EICRA |= _BV(ISC21);
    EICRA &= ~_BV(ISC20);// change input capture to falling edge
    EIFR  |= _BV(INTF2); // clear input  interrupt request flag
#else
    EICRA |= _BV(ISC01);
    EICRA &= ~_BV(ISC00);// change input capture to falling edge
    EIFR  |= _BV(INTF0); // clear input  interrupt request flag
#endif
    
  }

}



//-----------------------------------------------------------------------------

/*!
  \brief     ISR(INT0_vect)
  input capture interrupt service routine for cdc protocol
  \author     Koelling
  \date       26.09.2007
  \param[in]  none
  \param[out] none
  \return     void
*/

//-----------------------------------------------------------------------------


#if defined(__AVR_ATtiny167__)
ISR(TIMER1_CAPT_vect)
#elif defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__)
ISR(INT2_vect)
#else
ISR(INT0_vect)
#endif
{

#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
  captime = captime_ovf + TCNT1;
  TCNT1 = 0; //clear timer1
#elif defined(__AVR_ATtiny167__)
  captime = ICR1;
  TCNT1 = 0; //clear timer1
#else
  captime = captime_ovf + TCNT0;
  TCNT0 = 0; // clear timer0
#endif

  captime_ovf = 0;

  if ((RADIO_COMMAND_PIN & _BV(RADIO_COMMAND)) == 0)

  {
    // We have interrupted at beginning of low pulse (falling edge)

    // Low pulse length must be timed to determine bit value

#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
    TIFR  |= _BV(TOV1); // clear timer1 overflow flag
    TIMSK |= _BV(TOIE1); // enable timer1 interrupt on overflow
    MCUCR |= _BV(ISC01) | _BV(ISC00); // change input capture to rising edge
    GIFR  |= _BV(INTF0); // clear input  interrupt request flag
#elif defined(__AVR_ATtiny167__)
    TIFR1 |= _BV(TOV1); // clear timer1 overflow flag
    TIMSK1 |= _BV(TOIE1); // enable timer1 interrupt on overflow
    TCCR1B |= _BV(ICES1); // change input capture to rising edge
    TIFR1 |= _BV(ICF1); // clear input capture interrupt request flag
#elif defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__)
    TIFR0  |= _BV(TOV0); // clear time0 overflow flag
    TIMSK0 |= _BV(TOIE0); // enable timer0 interrupt on overflow
    EICRA |= _BV(ISC21) | _BV(ISC20); // change input capture to rising edge
    EIFR  |= _BV(INTF2); // clear input  interrupt request flag
#else
    TIFR0  |= _BV(TOV0); // clear time0 overflow flag
    TIMSK0 |= _BV(TOIE0); // enable timer0 interrupt on overflow
    EICRA |= _BV(ISC01) | _BV(ISC00); // change input capture to rising edge
    EIFR  |= _BV(INTF0); // clear input  interrupt request flag
#endif

  }

  else

  {

    // We have interrupted at beginning of high pulse (rising edge)

    // High pulse length doesn't matter. We need to check out

    // captured low pulse width if we are capturing data at the moment

    capbusy = TRUE;



#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
    MCUCR |= _BV(ISC01);
    MCUCR &= ~_BV(ISC00);// change input capture to falling edge
    GIFR  |= _BV(INTF0); // clear input  interrupt request flag

    if (TIMSK & _BV(TOIE1)) // are we trying to capture data?
#elif defined(__AVR_ATtiny167__)
    TCCR1B &= ~_BV(ICES1); // change input capture to falling edge
    TIFR1 |= _BV(ICF1); // clear input capture interrupt request flag
    
    if (TIMSK1 & _BV(TOIE1)) // are we trying to capture data?
#elif defined(__AVR_ATmega324__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__)
    EICRA |= _BV(ISC21);
    EICRA &= ~_BV(ISC20);// change input capture to falling edge
    EIFR  |= _BV(INTF2); // clear input  interrupt request flag

    if (TIMSK0 & _BV(TOIE0)) // are we trying to capture data?
#else
    EICRA |= _BV(ISC01);
    EICRA &= ~_BV(ISC00);// change input capture to falling edge
    EIFR  |= _BV(INTF0); // clear input  interrupt request flag

    if (TIMSK0 & _BV(TOIE0)) // are we trying to capture data?
#endif
    {

      capbusy = TRUE;

#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__)
      TIMSK &= ~_BV(TOIE1); // turn off capturing time for high pulse
#elif defined(__AVR_ATtiny167__)
     TIMSK1 &= ~_BV(TOIE1); // turn off capturing time for high pulse
#else
      TIMSK0 &= ~_BV(TOIE0); // turn off capturing time for high pulse
#endif

      if (captime > STARTTHRESHOLD)

      { // yes, start bit

#ifdef DUMPMODE

        startbit = TRUE;

#endif

        capbitpacket = PKTSIZE;

        // don't store start bits, just frame around them

        if (capbit > -8) // are we already capturing on a blank byte?

        {

          dataerr = TRUE;
          
          // Note: This should never happen on normal head unit sending 32 bit

          //       command strings with error free data.

          //

          // if the capture bits were not a complete 8 bits, we need to finish

          // rotating the bits upward so that the data is nicely formatted



          while (capbit != 0) // have we finished rotating all bits up?

          {

            capbuffer[capptr] <<= 1; // rotate in 0 bit

            capbit++;

          }

          capbit = -8;

          capptr++; // move to new capture byte

          if (capptr == CAP_BUFFER_END) // have we gone past the end of the

          { // capture buffer?

            capptr = 0; // yes, roll over to beginning

          }

          if (capptr == scanptr) // have we overflowed the capture queue?

          {

            overflow = TRUE; // yes, set error flag

          }

        }

      }

      else

      { // no, just a regular data bit

        if (captime > LOWTHRESHOLD)

        { // yes, go ahead and store this data

          capbuffer[capptr] <<= 1; // nope



          if (captime > HIGHTHRESHOLD)

          {

            capbuffer[capptr] |= 1;

          }

          capbitpacket++;

          if (capbitpacket == 0)

          {

            // we've received PKTSIZE number of bits, so let's assume that we're done

            // capturing bits for now.

            capbusy = FALSE; // clear capture busy flag

          }

          capbit++;

          if (capbit == 0) // have we collected all 8 bits?

          { // yep, get ready to capture next 8 bits

            capbit = -8;

            capptr++; // move to new capture byte

            if (capptr == CAP_BUFFER_END) // have we gone past the end of the

            { // capture buffer?

              capptr = 0; // yes, roll over to beginning

            }

            if (capptr == scanptr) // have we overflowed the capture queue?

            {

              overflow = TRUE; // yes, set error flag

            }

          }

        }

      }
      

    }

  }

}



//-----------------------------------------------------------------------------

/*!
  \brief     CDC_Protocol(void)
  cyclic called main program for cdc protocol (50ms?)
  \author     Koelling
  \date       26.09.2007
  \param[in]  none
  \param[out] none
  \return     void
*/

//-----------------------------------------------------------------------------



void CDC_Protocol(void)

{

  uint8_t decimal_adjust_u8;



  if (flag_50ms == TRUE)

  {
    
    flag_50ms = FALSE;

    SendPacket();

    scancount++;

    if (scancount == 0)

    {

      scancount = SCANWAIT;

      scan = FALSE; // turn off scan display

    }

    secondcount++;

    if (secondcount == 0)

    {

      secondcount = SECONDWAIT;

      poweridentcount++;


      if (poweridentcount == 0)

      {

        poweridentcount = POWERIDENTWAIT;

        EnqueueString(sIDENTIFY);

        EnqueueString(sVERSION);

        EnqueueString(sNEWLINE);

      }

      second++; // increment the time display

      decimal_adjust_u8 = second & 0x0F; // skip past hexidecimal codes

      if (decimal_adjust_u8 == 0x0A) // are with at xA?

      {

        second += 6; // yes, add 6 and we'll be at x0 instead

      }

      if (second == 0x60)

      {

        second = 0;

        minute++;

        decimal_adjust_u8 = minute & 0x0F; // skip past hexidecimal codes

        if (decimal_adjust_u8 == 0x0A) // are with at xA?

        {

          minute += 6; // yes, add 6 and we'll be at x0 instead

        }

        if (minute == 0xA0) // have we gone beyond 99 minutes?

        {

          minute = 0;

        }

      }

    }

  }



  if (overflow == TRUE) // has the command receive code detected

  { // an overflow error?

    overflow = FALSE; // clear error flag

    EnqueueString(sOVERFLOW);

  }

  if (dataerr == TRUE) // has the command receive code detected

  { // a framing type data error?

    dataerr = FALSE; // clear error flag

    EnqueueString(sDATAERR);

  }

#ifndef DUMPMODE

  ScanCommandBytes();

#else

  if (startbit == TRUE) // have we just recieved a start bit?

  {

    startbit = FALSE;

    EnqueueString(sNEWLINE); // yes, start a new line

  }

  fsr = scanptr;

  while (GetCaptureByte() == TRUE)

  {

    scanptr = fsr;

    EnqueueHex(scanbyte);

  }

#endif





  while (txoutptr != txinptr)

  {

    printstr_p((char*) txbuffer[txoutptr]);

    txoutptr++;

    if (txoutptr == TX_BUFFER_END)

    {

      txoutptr = 0;

    }

  }

}




//-----------------------------------------------------------------------------

/*!
  \brief    void DecodeCommand(void)
  decode cmdcode and do required actions
  ;--------------------------------------------------------------------------
  ; Button Push Packets
  ;--------------------------------------------------------------------------
  ; 532C609F Mix 1
  ; 532CE01F Mix 6
  ; 532CA05F Scan
  ;     Note: Blaupunkt Gamma V head unit will continue to send scan key code
  ;       unless display is switched into scan mode.
  ;       (reported by tony.gilbert@orange.co.uk)
  ; 532C10EF Head Unit mode change. Emitted at power up, power down, and
  ;        any mode change. (disable playing)
  ; 532C58A7 Seek Back Pressed
  ; 532CD827 Seek Forward Pressed
  ; 532C7887 Dn
  ; 532CA857 Dn on Mk3 premium (Adam Yellen <adam@yellen.com>)
  ; 532CF807 Up
  ; 532C6897 Up on Mk3 premium (Adam Yellen)
  ; 532C38C7 CD Change (third packet)
  ; 532CE41B Seek Forward Released (enable playing)
  ; 532CE41B Seek Back Released (enable playing)
  ; 532CE41B CD Mode selected. Emitted at power up (if starting in CD
  ;            mode), change to CD mode. (enable playing)
  ; 532C14EB CD Change (second packet)
  ; 532C0CF3 CD 1 (first packet)
  ; 532C8C73 CD 2 (first packet)
  ; 532C4CB3 CD 3 (first packet)
  ; 532CCC33 CD 4 (first packet)
  ; 532C2CD3 CD 5 (first packet)
  ; 532CAC53 CD 6 (first packet)
  ;
  ; Monsoon State Changes:
  ; 532CE41B enable playing (transition to State 2)
  ; 532C38C7 disc loaded inquiry (transition to State 5)
  ; 532C10EF disable playing (transition to State 1)
  ;--------------------------------------------------------------------------
  \author     Koelling
  \date       05.10.2007
  \param[in]  none
  \param[out] none
  \return     void
*/

//-----------------------------------------------------------------------------



static void DecodeCommand(void)

{

  uint8_t decimal_adjust_u8 = 0;

#ifdef JUST_HEX_TO_SERIAL
  Serial.write(cmdcode);
#endif

  switch (cmdcode) {

    case Do_CHANGECD:

      // Head unit seems to send this after each CDx number change

      // but the CD Changer seems to completely ignore (doesn't even ACK it).

      ACKcount = 0; // do not ack this command
#ifdef PJRC
      EnqueueString(sRANDOM);
#endif

      break;



    case Do_ENABLE:

    case Do_ENABLE_MK:

      mix = FALSE;

      if (playing == FALSE)

      {

        SetStateInitPlay(); // skip this if already playing

      }
if(!mix_button)
      EnqueueString(sMENABLE);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_LOADCD:

      if (playing == TRUE)

      {

        SetStateInitPlay(); // skip this if we're in idle mode

      }

      ResetTime();

      EnqueueString(sMINQUIRY);

      break;



    case Do_DISABLE:



      SetStateIdle(); // skip this if we're already in idle mode

      EnqueueString(sMDISABLE);

      break;



    case Do_SEEKBACK:

    case Do_PREVCD:


#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc--;

      track = 1;

      ResetTime();

      if ((disc & 0x0F) == 0)

      {

        disc = 0x46; // set back to CD 1

      }
#endif

      EnqueueString(sPRV_LIST);



      break;



    case Do_SEEKFORWARD:

    case Do_SEEKFORWARD_MK:



      if (cd_button == FALSE) // mk don't increment when previous command was a cd button

      {
        EnqueueString(sNXT_LIST);

#ifndef DISC_TRACK_NUMBER_FROM_MPD

        ResetTime();

        track = 1;

        disc++;

        if (disc > 0x46)

        {

          disc = 0x41;

        }

#endif

        // Going beyond CD9 displays hex codes on premium head unit.

        // Examples: "CD A"

        //           "CD B"

        //           "CD C" etc...

        //

        // However, going beyond CD6 mutes audio on monsoon head unit, so we

        // definitely don't want to do that.

      }

      else

      {

        cd_button = FALSE; // mk clear cd button flag

      }

      break;



    case Do_MIX:

    case Do_MIX_CD:

  mix_button=1;

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      if (mix == FALSE)

      {

        mix = TRUE;

      }

      else

      {

        mix = FALSE;

      }

#endif

      EnqueueString(sRANDOM);

      break;



    case Do_PLAY:

      EnqueueString(sPLAY); // this will make the PJRC play/pause

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_SCAN:



      scancount = SCANWAIT;

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      if (scan == FALSE)

      {

        scan = TRUE;

      }

      else

      {

        scan = FALSE;

      }

#endif

#ifdef PJRC
      EnqueueString(sPLAY); // this will make the PJRC play/pause
#else
      EnqueueString(sSCAN); //
#endif

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_UP:

    case Do_UP_MK3:

      if (playing == TRUE) // skip track lead-in if not in play mode

      {

        SetStateTrackLeadIn();

      }



#ifndef DISC_TRACK_NUMBER_FROM_MPD

 track++;

      ResetTime();

 decimal_adjust_u8 = track & 0x0F; / /  skip past hexidecimal codes

      if (decimal_adjust_u8 == 0x0A) / /  are with at xA?

      {

 track += 6; / /  yes, add 6 and we'll be at x0 instead

      }

      if (track == 0xA0) //  have we gone beyond Track 99?

 {// yes, rollover to Track 01 so that jog wheels

 track = 1; / /  can continue rolling (Audi Concert II)

      }

#endif

      EnqueueString(sNEXT);

#ifdef ANDROID_HEADPHONES
#ifdef ANDROID_HEADPHONES_ONE_BUTTON
 play_count_delay = ANDROID_DELAY_COUNT;
 play_count_push = ANDROID_NEXT_COUNT;
#else
 next_count = ANDROID_PUSH_COUNT; / /  100ms high on ANDROID_NEXT pin
#endif
#endif

      break;



    case Do_DOWN:

    case Do_DOWN_MK3:

      if (playing == TRUE) / /  skip track lead-in if not in play mode

      {

        SetStateTrackLeadIn();

      }

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      decimal_adjust_u8 = track & 0x0F; // skip past hexidecimal codes

      if (decimal_adjust_u8 == 0) // are we at x0?

      {

        track -= 6; // yes, subtract 6 and we'll be at x9 instead

      }

      track--;

      ResetTime();

      if (track == 0) // have we gone below Track 1?

      { // yes, rollover to Track 99 so that jog wheels

        track = 0x99; // can continue rolling (Audi Concert II)

      }

#endif

      EnqueueString(sPREVIOUS);

#ifdef ANDROID_HEADPHONES
#ifdef ANDROID_HEADPHONES_ONE_BUTTON
      play_count_delay = ANDROID_DELAY_COUNT;
      play_count_push = ANDROID_PREV_COUNT;
#else
      prev_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PREV pin
      prev_count_delay = ANDROID_DELAY_COUNT; // 50ms high on ANDROID_PREV pin
#endif
#endif

      break;



    case Do_CD1:

      cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc = 0x41; // set CD 1

      ResetTime();

#endif

      EnqueueString(sLIST1);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_CD2:


      cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc = 0x42; // set CD 2

      ResetTime();

#endif

      EnqueueString(sLIST2);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_CD3:

      cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc = 0x43; // set CD 3

      ResetTime();

#endif

      EnqueueString(sLIST3);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_CD4:

      cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc = 0x44; // set CD 4

      ResetTime();

#endif

      EnqueueString(sLIST4);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_CD5:

      cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc = 0x45; // set CD 5

      ResetTime();

#endif

      EnqueueString(sLIST5);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;



    case Do_CD6:

      cd_button = TRUE; // mk store cd button pressed

#ifndef DISC_TRACK_NUMBER_FROM_MPD

      disc = 0x46; // set CD 6

      ResetTime();

#endif

      EnqueueString(sLIST6);

#ifdef ANDROID_HEADPHONES
      play_count = ANDROID_PUSH_COUNT; // 100ms high on ANDROID_PLAY pin
#endif

      break;

    case Do_TP:
    
      if (playing == TRUE) {
        SetStateTP();
      } else {
        SetStateInitPlay();
      }
    
       EnqueueString(sTP);

    break;

    default:



      /* if execution reaches here, we have verified that we got
         a valid command packet, but the command code received is not
         one that we understand.
         Dump the unknown command code for the user to view.
      */



      EnqueueString(sDASH);

      EnqueueHex(cmdcode);

      EnqueueString(sNEWLINE);

      break;

  }

}

int main()

{
#ifdef BLUETOOTH
  Serial.begin(9600);
#else
  Serial.begin(9600);
#endif
  Init_VWCDC();

  //start in idle mode
  //SetStateIdle();



  while (1)

  {

#ifdef DISC_TRACK_NUMBER_FROM_MPD
    if (Serial.available() > 0) {
      int r = Serial.read();
      //r has new data
      if (r <= 0xFF)
      {
        //send CD No.
        if ((r & 0xF0) == 0xC0)
        {
          if (r == 0xCA)
          {
 scan = TRUE;
          }
          else if (r == 0xCB)
          {
 mix = TRUE;
          }
          else if (r == 0xCC)
          {
            SetStatePlay();
          }
          else if (r == 0xCD)
          {
 mix = FALSE;
 scan = FALSE;
 playing = FALSE;
            SetStateIdle();
          }
          else if (r == 0xCE)
          {
 mix = FALSE;
          }
          else if ((r & 0x0F) != ( disc & 0x0F))
          {
 disc = (r & 0x4F);
          }
        }
        // send TR No.
        else if (track != r)
        {
 track = r;
          ResetTime();
        }
      }
    }
#endif

    CDC_Protocol();

  }
}

//

 

 

function.ino

//-----------------------------------------------------------------------------

/*!
 
 \brief    void ScanCommandBytes(void)
 
 
 
 ScanCommandBytes - Looks in the command receive buffer and tries
 
 to identify valid command codes.
 
 
 
 \author     Koelling
 
 \date       05.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void ScanCommandBytes(void)

{



  fsr = scanptr;



FirstByteLoop:

  //printstr_p(PSTR("1"),DEBUG);

  if (GetCaptureByte() == FALSE)

  {

    return;

  }



FirstByteTest:

  //printstr_p(PSTR("2"),DEBUG);

  if (scanbyte == 0x53)

  {

    goto SecondByte;

  }

  // this byte doesn't match the beginning of a normal command packet,

  EnqueueHex(scanbyte);

  scanptr = fsr; // save scanptr, won't look at this byte again

  goto FirstByteLoop;



SecondByte:

  //printstr_p(PSTR("3"),DEBUG);

  if (GetCaptureByte() == FALSE)

  {

    return;

  }

  if (scanbyte == 0x2C) // verify that byte 2 is 0x2C)

  {

    goto ThirdByte;

  }

  // the first byte was a match, but the second byte failed.

  // dump first byte and then see if this one is the real first byte.

  EnqueueHex(0x53);

  goto FirstByteTest;



ThirdByte:

  //printstr_p(PSTR("4"),DEBUG);

  if (GetCaptureByte() == FALSE)

  {

    return;

  }

  cmdcode = scanbyte; // save command code for later use.



FourthByte:

  //printstr_p(PSTR("5"),DEBUG);

  if (GetCaptureByte() == FALSE)

  {

    return;

  }

  // if execution reaches here, we have already verified that

  // bytes 1 and 2 are valid for a command packet.



  // verify that (Byte 3 + Byte 4) = 0xFF

  if ((cmdcode + scanbyte) == 0xFF)

  {

    //printstr_p(PSTR("6"),DEBUG);



    if ((cmdcode & 0x03) == 0) // verify that Byte 3 is a multiple of 4

    {

      //printstr_p(PSTR("7"),DEBUG);



      ACKcount = -4; // acknowledge command

      scanptr = fsr; // save scanptr, won't look at this byte again



      // Now, let's jump to the section of code that handles the

      // command we just received.



      DecodeCommand();

      //printstr_p(PSTR("\n"),DEBUG);



    }

    else

    {

      DumpFullCommand(); // ABORT: dump invalid packet for display

    }

  }

  else

  {

    DumpFullCommand(); // ABORT: dump invalid packet for display

  }

}



//-----------------------------------------------------------------------------

/*!
 
 \brief    void DumpFullCommand(void)
 
 
 
 dump all received command bytes
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void DumpFullCommand(void)

{

  fsr = scanptr; // restart back at the beginning of the packet

  if (GetCaptureByte() == TRUE) // send byte 1

  {

    EnqueueHex(scanbyte);

  }

  if (GetCaptureByte() == TRUE) // send byte 2

  {

    EnqueueHex(scanbyte);

  }

  if (GetCaptureByte() == TRUE) // send byte 3

  {

    EnqueueHex(scanbyte);

  }

  if (GetCaptureByte() == TRUE) // send byte 4

  {

    EnqueueHex(scanbyte);

  }

  EnqueueString(sNEWLINE);

  scanptr = fsr; // save scanptr, won't look at this byte again

}

//-----------------------------------------------------------------------------

/*!
 
 \brief    uint8_t GetCaptureByte(void)
 
 
 
 checks wether a command byte is still in queue
 
 
 
 \author     Koelling
 
 \date       05.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     FALSE ->	no more bytes to collect
 
 TRUE  -> scanbyte contains next byte
 
 */

//-----------------------------------------------------------------------------



static uint8_t GetCaptureByte(void)

{

  uint8_t return_u8 = FALSE;

  // have we already caught up with capturer?

  if (fsr != capptr)

  {

    scanbyte = capbuffer[fsr]; // get a byte from the capture buffer

    fsr++;

    if (fsr == CAP_BUFFER_END) // have we overflowed the

    { // capture buffer?

      fsr = 0;

    } // yes, roll over to beginning

    return_u8 = TRUE;

  }

  return return_u8;

}



//-----------------------------------------------------

// Display Update Packets

//-----------------------------------------------------



//-----------------------------------------------------------------------------

/*!
 
 \brief    void SetStateIdle(void)
 
 
 
 Idle State
 
 74 BE FE FF FF FF 8F 7C
 
 74 BE FE FF FF FF 8F 7C
 
 ...
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SetStateIdle(void)

{

  playing = FALSE;

  BIDIstate = StateIdle;

}

static void SetStateTP(void)
{
  playing = FALSE;
  BIDIstate = StateTP;
}

//-----------------------------------------------------------------------------

/*!
 
 \brief     SetStateIdleThenPlay(void)
 
 
 
 Real CD Changer doesn't really do this, but we're gonna do it to try
 
 and make sure we unmute the audio even if the user didn't connect
 
 the PW-TX pin properly.
 
 
 
 \author     Koelling
 
 \date       27.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SetStateIdleThenPlay(void)

{

  playing = 0;

  BIDIstate = StateIdleThenPlay;

  BIDIcount = -20;

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void (void)
 
 
 
 set state to play mode
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SetStatePlay(void)

{

  playing = TRUE;

  BIDIstate = StatePlay;

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SetStateInitPlay(void)
 
 
 
 Initiate Playing
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SetStateInitPlay(void)

{

  playing = TRUE;

  BIDIstate = StateInitPlay;

  discload = 0xD1; //0xFF - 0x2E

  BIDIcount = -24;

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SetStatePlayLeadIn(void)
 
 
 
 34 BE FE FF FF FF AE 3C (play lead-in)
 
 34 2E ED DE AF B7 FF 3C
 
 34 BE FE FF FF FF AE 3C
 
 34 2E ED DE AF B7 FF 3C
 
 34 BE FE FF FF FF AE 3C
 
 34 2E ED DE AF B7 FF 3C
 
 34 BE FE FF FF FF AE 3C
 
 34 2E ED DE AF B7 FF 3C
 
 34 BE FE FF FF FF AE 3C
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SetStatePlayLeadIn(void)

{

  playing = TRUE;

  BIDIstate = StatePlayLeadIn;

  BIDIcount = -10;

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SetStateTrackLeadIn(void)
 
 
 
 34BEFEFFEEFFCF3C (playing)
 
 n34BEFEFFEEFFCF3C
 
 14BEFDFFFFFFCF1C (ack)
 
 14BEFDFFFFFFAE1C (track lead in)
 
 14BEFDFFFFFFAE1C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFAE3C
 
 34BEFDFFFFFFCF3C (playing)
 
 34BEFDFFFFFFCF3C
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SetStateTrackLeadIn(void)

{

  playing = TRUE;

  BIDIstate = StateTrackLeadIn;

  BIDIcount = -12;

}



// TODO: We might implement one more state machine for

// the CHANGECD/INQUIRY command. (mute byte goes 0x6F and 0xFF cd load

// while changer is busy motoring next CD into position). Then

// again, maybe we don't need to implement any busy states since

// we are instantly ready (no motoring here!).



// =========================================================================

// SEND DISPLAY UPDATE PACKETS

// =========================================================================





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SendDisplayBytes(void)
 
 
 
 send display bytes to head unit
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SendDisplayBytes(void)

{

  SendByte(disc); // disc display value

  SendDisplayBytesNoCD();

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SendDisplayBytesNoCD(void)
 
 
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SendDisplayBytesNoCD(void)

{

  uint8_t send_byte_u8 = 0;



  SendByte(track);

  SendByte(minute);

  SendByte(second);



  // D4 - scan on, mix on

  // D0 - scan on, mix off

  // 04 - scan off, mix on

  // 00 - scan off, mix off



  if (mix == TRUE) // mode (scan/mix)

  {

    send_byte_u8 |= 0x20; // turn on mix light

  }

  if (scan == TRUE)

  {

    send_byte_u8 |= 0x10; // turn on scan display

  }

  SendByte(send_byte_u8);

}



//-----------------------------------------------------------------------------

/*!
 
 \brief    void SendDisplayBytesInitCD(void)
 
 
 
 When sending an "init cd" packet, we need to send it the number of
 
 tracks and whatnot available on the CD. Required on Audi Concert II so
 
 that track up/dn buttons work.
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SendDisplayBytesInitCD(void)

{

  SendByte(0x99); // number of tracks total (99)?

  SendByte(0x99); // total minutes?

  SendByte(0x59); // total seconds?

  SendByte(0x49);//0xFF - 0xB7 = 48, 53, 31, 25, and 37 seen from real CDC,

  // no idea what it really means.

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SendFrameByte(uint8_t byte_u8)
 
 
 
 SendFrameByte - sends a framing byte to head unit (first and last bytes).
 
 
 
 If the ACK flag is set, we modify the send byte to send an
 
 acknowledgement.
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  byte_u8 -> byte to send
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SendFrameByte(uint8_t byte_u8)

{

  if (ACKcount == 0)

  {

    SendByte(byte_u8);

  }

  else

  {

    byte_u8 |= 0x20; // flag acknowledgement

    ACKcount++;

    SendByte(byte_u8);

  }

}





//-----------------------------------------------------------------------------

/*!
 
 \brief    void SendFrameByte(uint8_t byte_u8)
 
 
 
 SendByte - sends a byte to head unit.
 
 
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  byte_u8 -> byte to send
 
 \param[out] none
 
 \return     none
 
 
 
 */

//-----------------------------------------------------------------------------



static void SendByte(uint8_t byte_u8)

{

  static uint8_t display_byte_counter_u8 = 0;

  // wait for head unit to store sent byte

  // 335us didn't work so good on late 2003 wolfsburg double din,

  // so we now wait 700us instead.

  display_byte_buffer_mau8[display_byte_counter_u8] = byte_u8;

  display_byte_counter_u8++;

  if (display_byte_counter_u8 == 8)

  {

    display_byte_counter_u8 = 0;

  }

}





//-----------------------------------------------------------------------------

/*!
 
 \brief     void EnqueueString(const uint8_t addr PROGMEM)
 
 
 
 EnqueueString - Adds a new string pointer into the outgoing serial string
 
 queue.
 
 
 
 \author     Koelling
 
 \date       02.10.2007
 
 
 
 \param[in]  const uint8_t addr PROGMEM -> start address of string to display
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void EnqueueString(const uint8_t *addr PROGMEM)

{
#ifndef JUST_HEX_TO_SERIAL

  txbuffer[txinptr] = addr;

  txinptr++;

  if (txinptr == TX_BUFFER_END)

  {

    txinptr = 0;

  }

#endif
}



//-----------------------------------------------------------------------------

/*!
 
 \brief     void EnqueueHex(uint8_t hexbyte_u8)
 
 
 
 The byte is converted to a two byte ASCII hexidecimal string
 
 
 
 \author     Koelling
 
 \date       05.10.2007
 
 
 
 \param[in]  uint8_t hexbyte -> hexbyte to display
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void EnqueueHex(uint8_t hexbyte_u8)

{

  uint8_t nibble_u8;



  nibble_u8 = hexbyte_u8 >> 4; // send high nibble first

  nibble_u8 <<= 1; // multiply high nibble by 2

  EnqueueString(&sHEX[nibble_u8]);



  nibble_u8 = hexbyte_u8 & 0x0F; // prepare low nibble

  nibble_u8 <<= 1; // multiply low nibble by 2

  EnqueueString(&sHEX[nibble_u8]);

}



//-----------------------------------------------------------------------------

/*!
 
 \brief     ResetTime(void)
 
 
 
 reset time information
 
 
 
 \author     Koelling
 
 \date       27.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void ResetTime(void)

{

  secondcount = SECONDWAIT;

  second = 0;

  minute = 0;

}



//-----------------------------------------------------------------------------

/*!
 
 \brief     void SendStateIdle(void)
 
 
 
 send data for idle state
 
 
 
 \author     Koelling
 
 \date       29.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SendStateIdle(void)

{

  secondcount = SECONDWAIT; // stop display from ticking time

  SendFrameByte(0x8B);//FF - 0x74

  SendDisplayBytes();

  SendByte(0x70);//FF - 0x8F, mutes audio on Monsoon head units

  SendFrameByte(0x83);//FF - 0x7C

}

static void SendStateTP(void)
{ //B4 BE EF FE DB FF DF BC 
  secondcount = SECONDWAIT; // stop display from ticking time
  SendFrameByte(0x4B);//FF - 0x4b
  SendDisplayBytes();
  SendByte(0x20);
  SendFrameByte(0x43);//FF - 0x7C
}

//-----------------------------------------------------------------------------

/*!
 
 \brief     SendStatePlayLeadInEnd(void)
 
 
 
 send data for state PlayLeadInEnd
 
 
 
 \author     Koelling
 
 \date       29.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SendStatePlayLeadInEnd(void)

{

  SendFrameByte(0xC3);//FF - 0x3C

  BIDIcount++;

  if (BIDIcount == 0)

  {

    SetStatePlay();

  }

}



//-----------------------------------------------------------------------------

/*!
 
 \brief     SendStateInitPlayEnd(void)
 
 
 
 send data for state StateInitPlayEnd
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SendStateInitPlayEnd(void)

{

  SendFrameByte(0xC3);//FF - 0x3C

  BIDIcount++;

  if (BIDIcount == 0)

  {

    SetStatePlayLeadIn();

  }

}





//-----------------------------------------------------------------------------

/*!
 
 \brief     SendStateInitPlayAnnounceCD(void)
 
 
 
 send data for state StateInitPlayAnnounceCD
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SendStateInitPlayAnnounceCD(void)

{

  // 0xF6..0xF0: CD-ROM Loaded (seen on changer)

  // 0xE6..0xE0: CD-ROM Loaded. (made up)

  // 0x96..0x90: Slot Empty (seen on changer)

  // 0x86..0x80: Slot Empty (made up)

  // 0xD6..0xD0: AUDIO CD Loaded. (seen on changer)

  SendByte(discload);

  if (discload == 0xD6)

  {

    discload = 0xD1;

  }

  else

  {

    discload++;

  }

  SendDisplayBytesInitCD();

  SendByte(0x00);//0xFF - 0xFF

  SendStateInitPlayEnd();

}



//-----------------------------------------------------------------------------

/*!
 
 \brief     SendStatePlayLeadInAnnounceCD(void)
 
 
 
 send data for state StatePlayLeadInAnnounceCD
 
 
 
 \author     Koelling
 
 \date       06.10.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SendStatePlayLeadInAnnounceCD(void)

{

  SendByte((disc & 0x0F) | 0xD0);

  SendDisplayBytesInitCD();

  SendByte(0x00);//0xFF - 0xFF

  SendStatePlayLeadInEnd();

}





//-----------------------------------------------------------------------------

/*!
 
 \brief     void SendPacket(void)
 
 
 
 depending on BIDIstate data packet will be sent
 
 
 
 \author     Koelling
 
 \date       27.09.2007
 
 
 
 \param[in]  none
 
 \param[out] none
 
 \return     void
 
 */

//-----------------------------------------------------------------------------



static void SendPacket(void)

{

  switch (BIDIstate) {
    case StateTP:
      SendStateTP();
      break;
  case StateIdle:

    SendStateIdle();

    break;



  case StateIdleThenPlay:

    BIDIcount++;

    if (BIDIcount == 0)

    {

      SetStateInitPlay();

      SendStateIdle();

    }

    else

    {

      SendStateIdle();

    }

    break;



    // 34 2E ED DE AF B7 FF 3C

    // 34 BE FE FF FF FF EF 3C

    // 34 2D EB BE AB AC FF 3C

    // 34 BE FE FF FF FF EF 3C

    // 34 2C EC CE AA CE FF 3C

    // 34 BE FE FF FF FF EF 3C

    // 34 2B EE EE B7 DA FF 3C

    // 34 BE FE FF FF FF EF 3C

    // 34 2A EB BE A6 C8 FF 3C

    // 34 BE FE FF FF FF EF 3C

    // 34 69 00 FF FF FF FF 3C

    // 34 BE FE FF FF FF EF 3C



  case StateInitPlay:

    secondcount = SECONDWAIT; // stop display from ticking time

    SendFrameByte(0xCB);//0xFF - 0x34

    if ((BIDIcount & 0x01) == 0)

    {

      SendStateInitPlayAnnounceCD();

      break;

    }

    SendDisplayBytes();

    SendByte(0x10);//0xFF - 0xEF



  case StateInitPlayEnd:

    SendStateInitPlayEnd();

    break;



  case StateInitPlayAnnounceCD:

    SendStateInitPlayAnnounceCD();

    break;



  case StatePlayLeadIn:

    // 34 BE FE FF FF FF AE 3C (play lead-in)

    // 34 2E ED DE AF B7 FF 3C

    // 34 BE FE FF FF FF AE 3C

    // 34 2E ED DE AF B7 FF 3C

    // 34 BE FE FF FF FF AE 3C

    // 34 2E ED DE AF B7 FF 3C

    // 34 BE FE FF FF FF AE 3C

    // 34 2E ED DE AF B7 FF 3C

    // 34 BE FE FF FF FF AE 3C

    secondcount = SECONDWAIT; // stop display from ticking time

    SendFrameByte(0xCB);//0xFF - 0x34



    if ((BIDIcount & 0x01) == 0)

    {

      SendStatePlayLeadInAnnounceCD();

      break;

    }

    SendDisplayBytes();

    SendByte(0x51);//0xFF - 0xAE



  case StatePlayLeadInEnd:

    SendStatePlayLeadInEnd();

    break;



  case StatePlayLeadInAnnounceCD:

    SendStatePlayLeadInAnnounceCD();

    break;



  case StateTrackLeadIn:

    secondcount = SECONDWAIT; // stop display from ticking time

    SendFrameByte(0xCB);//0xFF - 0x34

    SendDisplayBytes();

    SendByte(0x51);//0xFF - 0xAE

    SendFrameByte(0xC3);//0xFF - 0x3C

    BIDIcount++;



    if (BIDIcount == 0)

    {

      break;

    }

    SetStatePlay();

    break;



  case StatePlay:

    SendFrameByte(0xCB);//0xFF - 0x34

    SendDisplayBytes();

    SendByte(0x30);//0xFF - 0xCF

    SendFrameByte(0xC3);//FF - 0x3C

    break;

  default:

    break;

  }

}


static void android_buttons(){

  
#ifdef ANDROID_HEADPHONES

    //android headphone control, this is fired every 50ms
    //play button

    if(play_count > 0){
      Serial.println("play");
  Serial.println(play_count);
  Serial.println(next_count);
  Serial.println(prev_count);
      play_count--;

      ANDROID_PLAY_PORT |= (1<<ANDROID_PLAY); //high
      
      
    } else {
  
      ANDROID_PLAY_PORT &= ~_BV(ANDROID_PLAY); //low

#ifdef ANDROID_HEADPHONES_ONE_BUTTON

      if(play_count_delay > 0 ){ //counting delay low

        play_count_delay--;

	if(play_count_delay==0 && play_count_push>0){

          play_count = ANDROID_PUSH_COUNT;
          
          play_count_delay=ANDROID_DELAY_COUNT;
          
          if (play_count_push>0) play_count_push--;
        }
      }

#endif

    }

#ifndef ANDROID_HEADPHONES_ONE_BUTTON

    //next button

    if(next_count > 0){
      Serial.println("next");
  Serial.println(play_count);
  Serial.println(next_count);
  Serial.println(prev_count);
      next_count--;

      ANDROID_NEXT_PORT |= _BV(ANDROID_NEXT); //high

    } else {

      ANDROID_NEXT_PORT &= ~_BV(ANDROID_NEXT); //low
    }

    //prev button, double push, head unit goes to previous song, no to start of the song
    if(prev_count > 0){
      Serial.println("prev");
  Serial.println(play_count);
  Serial.println(next_count);
  Serial.println(prev_count);
      prev_count--;
      
      ANDROID_PREV_PORT |= _BV(ANDROID_PREV); //high

    } else {
      //wait between pushes

      ANDROID_PREV_PORT &= ~_BV(ANDROID_PREV); //low


      if(prev_count_delay > 0 ){ //we ended first push and do not finished second push

        prev_count_delay--;

	if(prev_count_delay==0) //we are at last run of delay loop

          prev_count = ANDROID_PUSH_COUNT;

      }

    }

#endif

#endif

}

static void printstr_p(const char *s)

{

  char c;



  for (c = pgm_read_byte(s); c; ++s, c = pgm_read_byte(s))

  {
    Serial.print(c);

    if (c == '\n')

      break;

  }

}

 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

как на этом скетч, теперь подключить bluetooth xs3868, пока я еще чего нибудь не спалил ? Komandir помоги с этим

StepaVVka
Offline
Зарегистрирован: 29.07.2019

раскоментировать строку ?

106 // #define BLUETOOTH

подключение

rx-tx

tx-rx 

?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

На модуль нельзя подавать 5 вольт. Если запитать его от 3.3 тогда надо хотябы по резистору 2.7К в каждую пару Rx<-Tx для согласования. Ну и строку расскомментировать.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Komandir пишет:

На модуль нельзя подавать 5 вольт. Если запитать его от 3.3 тогда надо хотябы по резистору 2.7К в каждую пару Rx<-Tx для согласования. Ну и строку расскомментировать.

Так?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Да.

StepaVVka
Offline
Зарегистрирован: 29.07.2019

ОК, о результате напишу, получилось или нет 

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Раскоментировал строку // #define BLUETOOTH

теперь ошибка по скетчу

C:\Users\Администратор\Documents\Arduino\sketch\vwcdemu\vwcdc\vwcdc.ino: In function 'void DecodeCommand()':
 
vwcdc:2410:22: error: 'sTP' was not declared in this scope
 
exit status 1
'sTP' was not declared in this scope
 

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

В каком именно скетче ?

В том что выше вроде есть всё:

0574const uint8_t sTP[] PROGMEM = "TP\r\n";

StepaVVka
Offline
Зарегистрирован: 29.07.2019

atmega 328 который скетч, самый верхний уже не пытаюсь запустить 

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Закомментируй 2233 - в первом скетче такой строки нет в DO_TP

StepaVVka
Offline
Зарегистрирован: 29.07.2019

Komandir дружище как с тобой лично связаться? ..... Все заработало, bluetooth переключение треков работает.

пришло убрать сопротивления 2,7k

от 3,3в блютуз модуль не заводится, пришлось влупить 5в

в скетче поправил строки 

2264 #ifdef BLUETOOTH
2265   Serial.begin(9600);
2266 #else
2267   Serial.begin(9600);
2268 #endif
2269   Init_VWCDC();

9600 поменял на 115200

Так как на самом модуле bluetooth мне не удалось понизить скорость до 9600

и все заработало как должно

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

whatsapp

AUX
Offline
Зарегистрирован: 28.09.2020

Автор выкатил обнову и поддержку BK8000L

  • bluetooth support for modules with AT commands (ovc3860 based: XS3868, S3860M-S, BLK-MD-SPK-B), BK8000L - one way only, no feedback from module - TODO

Но что это значит про "один путь" в переводе?
XS3868 стоит очень дорого, с доставкой с Али у меня 12-14$
Если есть у кого возможность, помогите одолеть пожалуйста.

sadman41
Offline
Зарегистрирован: 19.10.2016

One Way в данном случае, по контексту - без проверки результата. Просто подача команды.

AUX
Offline
Зарегистрирован: 28.09.2020

Какие проблемы это под собой имеет в отличии от рекомендуемого модуля?

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, что бывает, когда сержант командует красить газон и уходит жрать и спать, не контролируя процесс выполнения?

AUX
Offline
Зарегистрирован: 28.09.2020

Хм, а у Вас однозначно преподавательский талант! Понял, принял, осознал, спасибо :)
Видимо придётся копить или ждать поддержку чего то нового, хотел другу подарок сделать. На край, у автора есть без блютуза вариант с AUX.