BuffaloCon

tmjuju

Administration Team
Staff member
21 January 2007
21,658
BuffaloCon

Μιας και μια έγχρωμη TFT καθυστερεί να φτάσει στα χέρια και έχω βαρεθεί να περιμένω…
Είπα να πιάσω τον κώδικα του DimDim http://www.avclub.gr/forum/showthre...-Sabre-ES9018-based-DACs-(Buffalo-32s-II-III) και να τον μετατρέψω ώστε η επικοινωνία να γίνεται μέσω της σειριακής θύρας επικοινωνίας που έχει το arduino.

Σίγουρα έχω αφήσει πολύ άχρηστο κώδικα από τις δύο προηγούμενες υλοποιήσεις στις οποίες βασίστηκα, ενώ θα γίνουν προσθήκες, κυνηγητό Bugs κ.ο.κ.

Για την ώρα πάντως παίζει.
Κλικιτι κλικ

Code:
 /**************************************************************************************************
 * BuffaloCon Code: My adaptation of the TFT HIFIDUINO code for Serial Port
 *
 * v.00.01 11/04/12 : - Initial Implementation
 *                    - Lots of unused variables from previous projects need to be removed
 *                    - Extra timer in main loop prints every INTERVAL some text
 *
 * The bellow comments (be HIFIDUINO or TFT HIFIDUINO) sill largelly apply
 *
 * Getting Started:
 * - Open a Serial connection to COM<X> where your arduino is connected. Use putty or any other sw.
 * - Wait for the banners to apear, Press ? key for Help
 ***************************************************************************************************/

 /**************************************************************************************************
 * TFT HIFIDUINO Code: My adaptation of the HiFiDUINO code so that is displays on a colour TFT.
 * 
 * v.0.51 11/03/12 : - Contains a few minor bugs but for the most part works.
 *                   - Includes support of source selection on Buffalo III boards.  
 *                   - The Apple remote codes are changed to another device's that I had handy.
 *                   - Has not been tested with I2S sources.
 *
 * The below comments (be HIFIDUINO) still largely apply.
 *
 ***************************************************************************************************/
 
 /***************************************************************************************************
 * HIFIDUINO Code: Supports Buffalo II 80Mhz and 100Mhz, stereo and dual mono. 
 * 
 * Change log:
 * v. B1.0b 01/07/12:- Compatible with Arduino 1.0 (but not backward compatible)
 *                   - Fixed Minor (potential) bugs
 *                   - Two additional settings: Oversampling bypass and jitter eliminator bypass 
 * ...NOTE COMMENTS REMOVED... 
 ***************************************************************************************************/
 
 /***************************************************************************************************
 * Code starts here
 ***************************************************************************************************/
 
// LIBRARIES
#include <Wire.h> // For I2C
#include <EEPROM.h> // We will use the eeprom to store values

// CONSTANT DEFINITION
/******************* Code Customization Section *********************/


/* First: Choose the clock frequency you have and comment the other */

#define USE80MHZ  
//#define USE100MHZ

/* Second: Choose your configuration

   | CONFIGURATION       | #define DUALMONO | #define TPAPHASE |
   |---------------------|------------------|------------------|
   | Dual mono in-phase  | un-comment       | comment          |
   | Dual mono TPA phase | un-comment       | un-comment       |
   | Stereo              | comment          | comment          |
   |---------------------|------------------|------------------|    */

//#define DUALMONO
//#define TPAPHASE

/* Optionally choose the number of inputs. 6 is the max without 
   modifying the code. You could lower the number of input choices
   here                                                             */

#define ICHO 8

/* Optionally change the name of the inputs. Use blanks if necessary */

char no0[] = "COAX 1";
char no1[] = "OPT 1";
char no2[] = "OPT 2";
char no3[] = "AES/EBU";
char no4[] = "COAX 2";
char no5[] = "COAX 3";
char no6[] = "I2S 1";
char no7[] = "I2S 2";

/* Make sure you use the correct chip address for each board

   for stereo Buffalo: use address 0x90
   for dual mono: Use address 0x90 for mono left Buffalo 
                  Use address 0x92 for mono right Buffalo           */

/********************************************************************/

#define DEFAULTATTNU 0x04 //-50 dB this is 50x2=100 or 0x64. Sabre32 is 0 to -127dB in .5dB steps
#define MAXATTNU 0xC6     //-99dB this is 99X2=198 or 0xC6 -Can go higher but LCD shows 2 digits
#define MINATTNU 0x00     //-0 dB -Maximum volume is -0 dB
#define DIM 0x8C          //-70 dB this is 70x2=140 or 0x8C. Dim volume
#define RAMP 10           // Additional msec delay per 1 db for ramping up to volume after dim

#define VOLUPPIN 4       // Button to increase  volume or RotEnc A terminal
#define VOLDOWNPIN 2     // Button to decrease volume or RotEnc B terminal
#define SELECTPIN 5      // Switch to select function
// #define BRIPIN 6         // Pin to control the LCD brightness with analogWrite
#define REMOTEPIN 9      // Pin for IR receiver (remote control)

#define INTERVAL_SAMPLE 2     // Time interval in SECONDS for refreshing the sample rate
#define INTERVAL_BOUNCE 2     // Time in milliseconds to debounce the rotary encoder
#define INTERVAL_SWITCHBOUNCE 200  // Time in milliseconds to debounce switch
#define INTERVAL_SELECT 4     // Time in sec to exit select mode when no activity

#define VOL 0  // The order of selection when clicking the select switch
#define FIR 3  // FIR filter selection
#define IIR 4  // IIR filter selection
#define QTZ 6  // Quantizer selection
#define INP 1  // Input selection
#define INF 2  // Input format selection
#define DPL 5  // DPLL bandwidth setting
#define NCH 7  // Notch selection
#define PLM 8  // DPLL mode
#define OSF 9  // Oversampling

#define B 0xFF  // The character for a completely filled box
#define A 0x20  // The character for blank

// Order of settings in the array for each input
#define FORMATVAL 0
#define FIRVAL 1
#define IIRVAL 2
#define DPLLVAL 3
#define QUANVAL 4
#define NOTCHVAL 5
#define PLMVAL 6

// Number of valid choices for each parameter
// There is one more: ICHO defined above
#define FORMATCHO 2 // SPDIF, I2S/DSD
#define FIRCHO 2    // Fast, slow
#define IIRCHO 4    // PCM, 50k, 60k, 70k
#define DPLLCHO 8   // Lowest to Best 8 values
#define QUANCHO 6   // 6bT, 7bP, 7bT, 8bP, 8bT, 9bP
#define NOTCHCHO 6  // /4 to /64
#define PLMCHO 3    // Normal x1 (NOR), Multiplier x128 (MUL), Bypass (OFF)
#define MAXPARAM 8  // Total number of parameters to keep track for each input. The 8th is for OSF
                    // But we don't keep track of that. It always starts with Oversampling on and 
                    // the function is a toggle (on/off). This is why there is no "OSFCHO"

// VARIABLE DECLARATION

// Register variables: used for registers that have lots of options. They are initialized here
// with valid values, but will eventually be overwritten by the values in EEPROM
byte reg14=0xF9; // Default value for register 14. We use a variable for reg 14 because it controls
                 // several parameters: IIR, FIR, differential whereas the other registers typically
                 // controls a single parameter.
byte reg25=0;    // 0= allow all settings
byte reg17L=0x1C;  // Auto SPDIF, 8-channel mode, other defaults
                   // reg17L is used for stereo and for left channel if set for MONO
#ifdef DUALMONO
byte reg17R=0x9D;  // Auto SPDIF, MONO RIGHT CHANNEL, other defaults
#endif DUALMONO

byte reg10=0xCE; // jitter ON, dacs unmute, other defaults

unsigned long displayMillis = 0;   // Stores last recorded time for display interval
unsigned long debounceMillis = 0;  // Stores last recorded time for switch debounce interval
unsigned long selectMillis = 0;    // Stores last recorded time for being in select mode
unsigned long sr = 0;              // Stores the incoming sample rate. Used for auto OSF bypass for 80MHz crystal

byte input=0;                 // The current input to the DAC
byte currAttnu=DEFAULTATTNU;  // Variable to hold the current attenuation value

byte select;          // To record current select position (FIL, VOL, DPLL, etc)

boolean selectMode;   // To indicate whether in select mode or not
boolean SPDIFValid;   // To indicate whether SPDIF valid data
boolean spdifIn;      // To indicate whether in I2S/DSD or SPDIF input format mode
boolean bypassOSF=false; // false=no bypass; This is the default condition at startup
boolean primed=false; // To indicate if dpll has been conditioned (once at startup)
boolean dimmed=false; // To indicate dim (mute) or not
byte pulse=0;         // Used by the "heartbeat" display
byte Status;          // To hold value of Sabre32 status register
byte StatusS;        // To hold value of Sabre32 SPDIF status register

// The following variables for the new s/pdif info feature
boolean pro_cons;
boolean samp1;
boolean samp2;
boolean samp3;
boolean samp4;
boolean bitd1;
boolean bitd2;
boolean bitd3;
boolean bitd4;

// The array holds the parameters for each input
// The current input is recorded after the array
byte settings[ICHO][MAXPARAM];  // Array to hold parameter values

void writeSettings(){
  for(byte i=0;i<ICHO;i++) {
    for (byte j=0;j<MAXPARAM;j++) {
      EEPROM.write((i*MAXPARAM)+j,settings[i][j]);
    }
  }
  EEPROM.write(ICHO*MAXPARAM,input); // Write the current input in a variable location after the array
}

void readSettings(){
  for(byte i=0;i<ICHO;i++) {
    for (byte j=0;j<MAXPARAM;j++) {
      settings[i][j]=EEPROM.read((i*MAXPARAM)+j);
    }
  }
  input=EEPROM.read(ICHO*MAXPARAM);  // Read the last saved input setting
}
  
/*
READING THE SAMPLE RATE
 
 The sample rate can be calculated by reading the DPLL 32-bit register. For SPDIF DPLL value 
 is divided by (2^32/Crystal-Frequency). In Buffalo II (original), the Crystal frequency is
 80,000,000 Hz. In Arduino (and other small microprocessors) it is NOT advisable to do floating point
 math because "it is very slow"; therefore integer math will be used to calculate the sample rate.
 
 The value of 2^32/80,000,000 is 53.687091 (which is a floating point number). If we use the 
 integer part (53 or 54) we get the following results for a 44.1K sample rate signal:  divided by 53 
 the result is 44.677K; divided by 54, the result is 43.849K. Clearly there are large errors from 
 being confined to integer math. The actual result, if we use floating point math and use all the 
 significant digits is 44,105 Hz (the 5 Hz deviation from ideal 44100 Hz is within the specification
 of SPDIF and the tolerances of the crystals and clocks involved)
 
 In order to increase the accuracy of the integer calculation, we can use more of the significant 
 digits of the divisor. I did some evaluation of the DPLL register values for sample rates ranging 
 from 44.1K to 192K and noticed that I could multiply the value of the DPLL number by up to 
 400 without overflowing the 32-bits. Therefore, since we have 32 bit number to work with, we 
 can multiply the DPLL number by  up to 400 and then divide by 400X53.687091=21475. If we do this, 
 we obtain 44.105K which is the same as the exact value.
 
 I used a spreadsheet to calculate the multipliers for SPDIF and I2S and for both 80Mhz and 100Mhz
 
 SPDIF 80Mhz:  x80, %4295
 SPDIF 100Mhz: x20, %859
 I2S 80Mhz:     x1, %3436
 I2S 100Mhz:    x4, %10995 (higher multiplier will overflow the 32bit value for 384KHz SR)
                x5, %13744 (More accurate but only works up to 192KHz SR)
 
 For I2S input format the dpll number is divided by (2^32*64/Crystal-Frequency) Note the 64 factor.
 The value of this is 3435.97 which rounds off nicely to 3436 (which is only 0.0008% error). The
 resultant value for the sample rate is the same wheter in spdif or I2S mode.
 */

// Sample rate reading routines

volatile unsigned long DPLLNum; // Variable to hold DPLL value

byte readDPLL(byte regAddr) {
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.write(regAddr);          // Queues the address of the register
  Wire.endTransmission();       // Sends the address of the register
  Wire.requestFrom(0x48,1);     // Hard coded to Buffalo, request one byte from address
                                // specified with Wire.write()/wire.endTransmission()
  //while(!Wire.available()) {  // Wait for byte to be available on the bus
  if(Wire.available())          // Wire.available indicates if data is available
    return Wire.read();         // Wire.read() reads the data on the wire
  else
    return 0;                   // In no data in the wire, then return 0 to indicate error
}

unsigned long sampleRate() {
  DPLLNum=0;
  // Reading the 4 registers of DPLL one byte at a time and stuffing into a single 32-bit number
  DPLLNum|=readDPLL(31);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(30);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(29);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(28);
  // The following calculation supports 80 MHz oscillator
  if (SPDIFValid){
    #ifdef USE80MHZ
    DPLLNum*=80;      // Calculate SR for SPDIF -80MHz part
    DPLLNum/=4295;    // Calculate SR for SDPIF -80MHz part
    #endif
    #ifdef USE100MHZ
    DPLLNum*=20;      // Calculate SR for SPDIF -100MHz part 
    DPLLNum/=859;     // Calculate SR for SDPIF -100MHz part
    #endif
  }
  else {              // Different calculation for SPDIF and I2S
    #ifdef USE80MHZ
    DPLLNum/=3436;    // Calculate SR for I2S -80MHz part
    #endif
    #ifdef USE100MHZ
    DPLLNum*=4;      // Calculate SR for I2S -100MHz part
    DPLLNum/=10995;  // Calculate SR for I2S -100MHz part
    #endif
  }
  if(bypassOSF)      // When OSF is bypassed, the magnitude of DPLL is reduced by a factor of 64
    DPLLNum*=64;
  return DPLLNum;
}

// Reading the status register. There is a status register providing the following information:
// 1- dsd or pcm mode
// 1- spdif valid or invalid
// 3- spdif mode enabled or disabled. 
// 4- Jitter Eliminator locked/not locked to incoming signal

byte readStatus() {             // Hardcoded to the status register
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.write(27);               // Hard coded to status register
  Wire.endTransmission();
  Wire.requestFrom(0x48,1);     // Hard coded to Buffalo, request one byte from address
                                // specified with Wire.write()
  //while(!Wire.available()) {  // Wait for byte to be available on the bus
  if(Wire.available())
    return Wire.read();         // Return the value returned by specified register
  else
    return 0;
}

// Reading the SPDIF status register. There is a status register providing the following information:
// 1- dsd or pcm mode
// 1- spdif valid or invalid
// 3- spdif mode enabled or disabled. 
// 4- Jitter Eliminator locked/not locked to incoming signal

byte readSPDIFStatus() {             // Hardcoded to the status register
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.write(48);               // Hard coded to status register
  Wire.endTransmission();
  Wire.requestFrom(0x48,1);     // Hard coded to Buffalo, request one byte from address
                                // specified with Wire.write()
  //while(!Wire.available()) {  // Wait for byte to be available on the bus
  if(Wire.available())
    return Wire.read();         // Return the value returned by specified register
  else
    return 0;
}


/*
CONTROLLING THE DIGITAL ATTENUATION (VOLUME) -and other registers IN THE DAC
 
 The device address of Sabre DAC Datasheet specifies the address as 0x90 which is an 8-bit value.
 The wire library in Arduino uses 7-bit device addresses and the 8th R/W bit is added automatically
 depending on whether you use the write call [beginTransmission()] or the read call [requestFrom()].
 Therefore, you will use the 7 most significant bits of the 8-bit address.
 In our example, 0x90 becomes 0x48 as follows:
 0x90: 10010000 (we eliminate the rightmost bit to get I2C address)
 0x48: 1001000
 When using dual-mono configuration, the other device can be set to addres 0x92
 0x92: 10010010 (we eliminate the rightmost bit to get I2C address)
 0x49: 1001001
 */

void writeSabreReg(byte regAddr, byte regVal)
{
  Wire.beginTransmission(0x48); //Hard coded to the the Sabre/Buffalo device address
  Wire.write(regAddr); // Specifying the address of register
  Wire.write(regVal); // Writing the value into the register
  Wire.endTransmission();
  
  #ifdef DUALMONO
  Wire.beginTransmission(0x49); //Hard coded to the the other Sabre/Buffalo device address
  Wire.write(regAddr); // Specifying the address of register
  Wire.write(regVal); // Writing the value into the register
  Wire.endTransmission();
  #endif DUALMONO
}

void setSabreVolume(byte regVal)
{
  writeSabreReg(0, regVal); // set up volume in DAC1
  writeSabreReg(1, regVal); // set up volume in DAC2
  writeSabreReg(2, regVal); // set up volume in DAC3
  writeSabreReg(3, regVal); // set up volume in DAC4
  writeSabreReg(4, regVal); // set up volume in DAC5
  writeSabreReg(5, regVal); // set up volume in DAC6
  writeSabreReg(6, regVal); // set up volume in DAC7
  writeSabreReg(7, regVal); // set up volume in DAC8
}

void rampUp()
{
  byte i=(DIM-currAttnu); 
  for(byte dimval=DIM;dimval>currAttnu;dimval--){
    setSabreVolume(dimval);
//    tft.setRotation(3);
//    tft.setCursor(130, 100);
//    tft.setTextColor(vol_color);
//    tft.setTextSize(6);
//    tft.setRotation(3);
//    tft.fillRoundRect(130, 100, 200, 60, 0, vol_back_col);
//    tft.print("-");
//    tft.print(dimval/2);
//    tft.println("dB");

      Serial.print("-");
      Serial.print(dimval/2);
      Serial.print("dB");

    delay((RAMP)*(1+(10/i*i)));
    i--;
  }
}

// Because of register 17 sets MONO/8-channel, different values are written into different chips
void writeSabreLeftReg(byte regAddr, byte regVal)
{
  Wire.beginTransmission(0x48); // Hard coded to the the Sabre/Buffalo device address for stereo
                                // or mono left. For stereo same as writeSabreReg()
  Wire.write(regAddr);          // Specifying the address of register
  Wire.write(regVal);           // Writing the value into the register
  Wire.endTransmission();
}

#ifdef DUALMONO
void writeSabreRightReg(byte regAddr, byte regVal)
{
  Wire.beginTransmission(0x49); //Hard coded to the the Sabre/Buffalo device address
  Wire.write(regAddr); // Specifying the address of register
  Wire.write(regVal); // Writing the value into the register
  Wire.endTransmission();
}
#endif DUALMONO

/*
 The following function prints a bar at the left most column to indicate that we are in "select"
 mode. One can choose any character as the "bar" For example, I used the solid square character
 */
void printSelectBar(){
  
 Serial.print("---printSelectBar");
 }

void removeSelectBar(){
  
   Serial.print("---removeSelectBar");
 }


void setAndPrintDPLL(byte value){

  Serial.print("DPLL B/W: ");
  
  switch(value){
  case 0:
    bitSet(reg25,1);            // Reg 25: set bit 1 for "use best dpll"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for best dpll
    Serial.println("Auto");
    break;
  case 1:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x85);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Lowest");
    break;
  case 2:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x89);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Low");
    break;
  case 3:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x8D);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Low-Med");
    break;
  case 4:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x91);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Medium");
    break;
  case 5:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x95);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Med-High");
    break;
  case 6:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x99);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("High");
    break;
  case 7:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x9D);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Highest");
    break;
  }
}

void setAndPrintDPLLMode(byte value){ // Set the DPLL Mode
  Serial.print("DPLL Mode:");
  
  switch(value){
  case 0:
    bitSet(reg10,3);           // Set bit 3 of reg 10: jitter reduction ON
    writeSabreReg(0x0A,reg10);
    bitSet(reg25,0);           // Set bit 0 of reg 25 for x128 DPLL bandwidth
    writeSabreReg(0x19,reg25);
    Serial.println("x128");
    break;
  case 1:
    bitSet(reg10,3);           // Set bit 3 of reg 10: jitter reduction ON
    writeSabreReg(0x0A,reg10);
    bitClear(reg25,0);         // Clear bit 0 of reg 25 for x1 DPLL bandwidth
    writeSabreReg(0x19,reg25);
    Serial.println("x1");
    break;
  case 2:
    bitClear(reg10,3);         // Clear bit 3 of reg 10: jitter reduction bypass
    writeSabreReg(0x0A,reg10);
    Serial.println("NOS");
    break;
  }
}

void setAndPrintBypassOSF(){         // This is just a toggle function
  if(bypassOSF==true){
    bypassOSF=false;
    bitClear(reg17L,6);              // Reg 17: clear bypass oversampling bit in register
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: bypass OSF off
    #ifdef DUALMONO
    bitClear(reg17R,6);              // Reg 17: clear bypass oversampling bit in register -dual mono
    writeSabreRightReg(0x11,reg17R); // Reg 17: bypass OSF off
    #endif DUALMONO
    

    Serial.print("Over/ling:");                 // Indicate oversampling is ON (^)

    Serial.print("On");  
}
  else {
    bypassOSF=true;
    bitSet(reg17L,6);                // Reg 17: set bypass oversampling bit in register
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: bypass OSF on
    #ifdef DUALMONO
    bitSet(reg17R,6);                // Reg 17: set bypass oversampling bit in register -dual mono 
    writeSabreRightReg(0x11,reg17R); // Reg 17: bypass OSF on
    #endif DUALMONO
    Serial.print("Over/ling:");                 // Indicate no oversampling (.)
    Serial.println("Off");                 
  }
}

void setAndPrintFirFilter(byte value){
  Serial.print("Filter:");
  switch(value){
  case 0:
    bitSet(reg14,0);           // Set bit 0 of reg 14 for sharp fir
    writeSabreReg(0x0E,reg14);
    Serial.println("Sharp FIR");
    break;
  case 1:
    bitClear(reg14,0);         // Clear bit 0 of reg 14 for slow fir
    writeSabreReg(0x0E,reg14);
    Serial.println("Slow FIR");
    break;
  }
}

void setAndPrintIirFilter(byte value){
  Serial.print("IIR:");
  //tft.setCursor(10, 32);
  switch(value){
  case 0:                        // | | | | | |0|0| | IIR Bandwidth: Normal (for PCM)
    bitClear(reg14,1);           // Clear bit 1
    bitClear(reg14,2);           // Clear bit 2
    writeSabreReg(0x0E,reg14);
    Serial.println("PCM");
    break;
  case 1:                        // | | | | | |0|1| | IIR Bandwidth: 50k (for DSD) (D)
    bitSet(reg14,1);             // Set bit 1
    bitClear(reg14,2);           // Clear bit 2
    writeSabreReg(0x0E,reg14);
    Serial.print("50K");
    break;
  case 2:                        // | | | | | |1|0| | IIR Bandwidth: 60k (for DSD)
    bitSet(reg14,2);             // Set bit 2
    bitClear(reg14,1);           // Clear bit 1
    writeSabreReg(0x0E,reg14);
    Serial.println("60K");
    break;
  case 3:                        // | | | | | |1|1| | IIR Bandwidth: 70k (for DSD)
    bitSet(reg14,1);             // Set bit 1
    bitSet(reg14,2);             // Set bit 2
    writeSabreReg(0x0E,reg14);
    Serial.println("70K");
    break;
  }
}


void setAndPrintQuantizer(byte value){

  Serial.print("Qtz:");
   
  switch(value){
  case 0:                        // 6-bit true diff
    bitSet(reg14,3);             // True differential
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0x00);    // 6-bit quantizer
    Serial.println("6bT");
    break;
  case 1:                        // 7-bit pseudo diff
    bitClear(reg14,3);           // Pseudo diff
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0x55);    // 7-bit quantizer
    Serial.println("7bP");
    break;
  case 2:                        // 7-it true diff
    bitSet(reg14,3);             // True differential
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0x55);    // 7-bit quantizer
    Serial.println("7bT");
    break;
  case 3:                        // 8-bit pseudo diff
    bitClear(reg14,3);           // Pseudo diff
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0xAA);    // 8-bit quantizer
    Serial.println("8bP");
    break;  
  case 4:                        // 8-bit true diff
    bitSet(reg14,3);             // True differential
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0xAA);    // 8-bit quantizer
    Serial.println("8bT");
    break;
  case 5:                        // 9-bit pseudo diff
    bitClear(reg14,3);           // Pseudo diff
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0xFF);    // 9-bit quantizer
    Serial.println("9bP");
    break; 
  }
}

void setAndPrintNotch(byte value){
  Serial.print("Notch:");
  switch(value){
  case 0:
    writeSabreReg(0x0C,0x20);    // No notch delay
    Serial.println("NON");
    break;
  case 1:
    writeSabreReg(0x0C,0x21);    // notch delay=mclk/4
    Serial.println("/04");
    break;
  case 2:
    writeSabreReg(0x0C,0x23);    // notch delay=mclk/8
    Serial.println("/08");
    break;
  case 3:
    writeSabreReg(0x0C,0x27);    // notch delay=mclk/16
    Serial.println("/16");
    break;  
  case 4:
    writeSabreReg(0x0C,0x2F);    // notch delay=mclk/32
    Serial.println("/32");
    break;
  case 5:
    writeSabreReg(0x0C,0x3F);    // notch delay=mclk/64
    Serial.println("/64");
    break; 
  }
}

void setAndPrintInputFormat(byte value){
  // This register also controls mono-8channel operation, thus more code...

  Serial.print("Input:");
 
  switch(value){
  case 0:
    writeSabreReg(0x08,0xE8);        // Reg 8: Enable SPDIF input format
    bitSet(reg17L,3);                // Reg 17: auto spdif detection ON -Set bit 3
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: write value into register
    #ifdef DUALMONO
    bitSet(reg17R,3);                // Reg 17: auto spdif detection ON -Set bit 3
    writeSabreRightReg(0x11,reg17R); // Reg 17: write value into register
    #endif DUALMONO
    spdifIn=true;                    // Indicates input format is spdif. For label for input format
    Serial.println("S/PDIF");
    break;
  case 1:
    bitClear(reg17L,3);              // Reg 17: manual SPDIF -Clear bit 3
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: Auto spdif detection OFF
    #ifdef DUALMONO
    bitClear(reg17R,3);              // Reg 17: manual SPDIF -Clear bit 3
    writeSabreRightReg(0x11,reg17R); // Reg 17: Auto spdif detection OFF
    #endif DUALMONO
    writeSabreReg(0x08,0x68);        // Reg 8: Enable I2S/DSD input format
    spdifIn=false;                   // Set variable to indicate input format is I2S/DSD mode
    Serial.println("I2S/DSD");
    break;
  //tft.write(127);                    // Print Arrow to indicate this is input seletion and not signal
  }
}

void setAndPrintInput(byte value){

  Serial.print("Input:");
    
  setAndPrintInputFormat(settings[input][FORMATVAL]%FORMATCHO);  // Setup input format value
  setAndPrintFirFilter(settings[input][FIRVAL]%FIRCHO);          // Setup FIR filter value
  setAndPrintIirFilter(settings[input][IIRVAL]%IIRCHO);          // Setup IIR filter value
  setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO);             // Setup the DPLL value
  setAndPrintQuantizer(settings[input][QUANVAL]%QUANCHO);        // Setup quantizer value
  setAndPrintNotch(settings[input][NOTCHVAL]%NOTCHCHO);          // Setup notch delay value
  setAndPrintDPLLMode(settings[input][PLMVAL]%PLMCHO);            // Setup dpll mode value




  switch (value){
  case 0:
    writeSabreReg(0x12,0x01);        // Set SPDIF to input #1
    Serial.println(no0);
    break;
  case 1:
    writeSabreReg(0x12,0x02);        // Set SPDIF to input #2
    Serial.print(no1);
    break;
  case 2:
    writeSabreReg(0x12,0x04);        // Set SPDIF to input #3
    Serial.println(no2);
    break;
  case 3:
    writeSabreReg(0x12,0x08);        // Set SPDIF to input #4
    Serial.println(no3);
    break;
  case 4:
    writeSabreReg(0x12,0x10);        // Set SPDIF to input #5
    Serial.println(no4);
    break;
  case 5:
    writeSabreReg(0x12,0x20);        // Set SPDIF to input #6
    Serial.println(no5);
    break;
  case 6:
    writeSabreReg(0x12,0x40);        // Set SPDIF to input #7
    Serial.println(no6);
    break;
  case 7:
    writeSabreReg(0x12,0x80);        // Set SPDIF to input #8
    Serial.println(no7);
    break;
  }
}

// Array index into parts of big numbers. Each number consists of 9 custom characters
// in a 3x3 matrix. To print a number, you use the array index corresponding to the number
// times 3. For example to print the number 5, you will print bn1[15], bn1[16] and bn1[17]
// for the first row of the large number, and then bn2[15], bn2[16] and bn2[17] and so on.

//            0      1      2      3      4      5      6      7      8      9    
char bn1[]={B,2,1, 2,1,A, 2,2,1, 2,2,1, 0,A,B, B,2,2, B,2,2, 2,2,B, B,2,1, B,2,1};
char bn2[]={B,A,B, A,B,A ,0,6,5, A,2,1, 5,6,B, 2,2,1, B,6,7, A,0,5, B,6,B, 5,6,B};
char bn3[]={4,3,B, 3,B,3, B,3,3, 4,3,B, A,A,B, 4,3,B, 4,3,B, A,B,A, 4,3,B, A,A,B};


void startDac1(){               // Set registers not requiring display info
  bitSet(reg10,0);              // Set bit zero for reg 10: Mute DACs
  writeSabreReg(0x0A,reg10);    // Mute DACs. Earliest we can mute the DACs to avoid full vol
  setSabreVolume(currAttnu);    // Reg 0 to Reg 7 Set volume registers with startup volume level
  writeSabreReg(0x0D,0x00);     // DAC in-phase
  writeSabreReg(0x13,0x00);     // DACB anti-phase
  writeSabreReg(0x25,0x00);     // Use built in filter for stage 1 and stage 2
  writeSabreReg(0x0E,reg14);    // Reg 14: BuffII input map, trueDiff, normal IIR and Fast rolloff
                                // Reg 14: except BuffII input map setting, the others will be
                                // redefined.
  /*
    The code below may provide some mitigation to the white noise during silence
    #ifdef USE80MHZ
    writeSabreReg(0x10,0x08);     // Reg 16: Turn automute loopback -only to mitigate 352.8KHz noise
    writeSabreReg(0x09,0x10);     // Reg 9: Set automute time 4x less than default (value is in denom.)
    #endif USE80MHZ
  */
  
  #ifdef DUALMONO                // DAC registers default to stereo. Set to MONO L/R for dual MONO
  bitSet(reg17L,0);              // Set for MONO left channel. Right ch variable is already set for MONO
  writeSabreLeftReg(0x11,reg17L);
  writeSabreRightReg(0x11,reg17R);
  #endif DUALMONO

  #ifdef TPAPHASE  
  /* The outputs on each side of each MONO board will be in opposite phase. In order to do this
     the phase of the odd dacs are out of phase with the even dacs. Further, buffalo is configured
     such that (In dual mono mode) the channel on the DAC which is opposite of the selected channel  
     carries the same analog signal but in anti-phase (odd dacs are the left channel;
     even dacs are the right channel)
     See http://hifiduino.wordpress.com/sabre32/ for further explaination
  */
  writeSabreLeftReg(0x0D,0x22);  // MONO LEFT DACx: odd dacs=in-phase; even dacs=anti-phase
  // writeSabreLeftReg(0x13,0x00);  // MONO LEFT DACBx: all dacs anti-phase with respect to DACx
  writeSabreRightReg(0x0D,0x11); // MONO RIGHT DACx: odd dacs=anti-phase; even dacs=in-phase
  // writeSabreRightReg(0x13,0x00); // MONO RIGHT DACBx: all dacs anti-phase with respect to DACx
  #endif TPAPHASE
}

void startDac2(){
  readSettings();
  setAndPrintInput(input);


  Serial.print("Over/ling:");                 

  Serial.print("On");                   // Indicate oversampling is ON (since this is the default)

  Serial.print("-");
  Serial.print(currAttnu/2);    // Print default volume level
  Serial.println("dB");
  bitClear(reg10,0);                 // Clear bit zero of reg 10: unmute DACs
  writeSabreReg(0x0A,reg10);         // Unmute DACs
}

// The following function attempts to "prime" the DPLL by going through all settings of the DPLL
// May help the i2s locking problem???

void primeDpll(){
  bitSet(reg10,0);                   // Set bit zero of reg 10
  writeSabreReg(0x0A,reg10);         // Mute DACs.
  writeSabreReg(0x19,0x02);          // Reg 25: Allow all Best settings
  for(int i=8;i>0;i--){              // Select each DPLL settings from largest to smallest BW
    writeSabreReg(0x19,0x00);        // Reg 25: Allow all DPLL settings at 1X
    writeSabreReg(11, (125+(i*4)));  // Go through all the DPLL settings
    delay(400);

    
    //lcd.setCursor(4,2);              // To show in the screen that something is going on
    Serial.print("<|>");
    writeSabreReg(0x19,0x01);        // Reg 25: Allow all DPLL settings at 128X
    writeSabreReg(11, (161-(i*4)));  // Go through all the DPLL settings
    delay(400);
    
    //lcd.setCursor(4,2);              // To show in the screen that something is going on
    Serial.print(">|<");
  }
  setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO); // Back to original setting for dpll
  bitClear(reg10,0);                 // Clear bit zero of reg 10
  writeSabreReg(0x0A,reg10);         // Unmute DACs
}

 /***************************************************************************************************
 * Timer Code starts here
 ***************************************************************************************************/
int incomingByte = 0;   // for incoming serial data
#define INTERVAL 1             // Arbitrary time interval in minutes
unsigned long minutes=0;        // Minute count 0 to 59
unsigned long totalMinutes=0;   // Total minute count 0 to ...
unsigned long hours=0;          // Hours count 0 to ...
unsigned long lastInterval=0;   // Time in minutes of last interval

void printTime(){               // Prints hours:minutes as xx:xx
  if(hours<10)
    Serial.print("0");
  Serial.print(hours);
  Serial.print(":");
  if(minutes<10)
    Serial.print("0");
  Serial.println(minutes);
}

void keepTime(){                // Keeps track of elapsed time
  if(millis()>((60000)+(60000*minutes)+(3600000*hours))){
    minutes++;
    totalMinutes++;
    if(minutes==60){            // For every 60 minutes...
      minutes=0;                // Reset the minutes and...
      hours++;                  // Increase the hours
    }
  }
}

void printData(){
  Serial.print("Print Data");
  printTime();
}

/******************* START Print Utilities derived from setAndPrint functions *********************/

void printInputFormat(byte value){
  Serial.print("Input:");
  switch(value){
  case 0:
    Serial.println("S/PDIF");
    break;
  case 1:
    Serial.println("I2S/DSD");
    break;
  }
}

void printNotch(byte value){
  Serial.print("Notch:");
  switch(value){
  case 0:
    Serial.println("NON");
    break;
  case 1:
    Serial.println("/04");
    break;
  case 2:
    Serial.println("/08");
    break;
  case 3:
    Serial.println("/16");
    break;  
  case 4:
    Serial.println("/32");
    break;
  case 5:
    Serial.println("/64");
    break; 
  }
}

void printQuantizer(byte value){
  Serial.print("Qtz:");
  switch(value){
  case 0:                        // 6-bit true diff
    Serial.println("6bT");
    break;
  case 1:                        // 7-bit pseudo diff
    Serial.println("7bP");
    break;
  case 2:                        // 7-it true diff
    Serial.println("7bT");
    break;
  case 3:                        // 8-bit pseudo diff
    Serial.println("8bP");
    break;  
  case 4:                        // 8-bit true diff
    Serial.println("8bT");
    break;
  case 5:                        // 9-bit pseudo diff
    Serial.println("9bP");
    break; 
  }
}

void printIirFilter(byte value){
  Serial.print("IIR:");
  switch(value){
  case 0:                        // | | | | | |0|0| | IIR Bandwidth: Normal (for PCM)
    Serial.println("PCM");
    break;
  case 1:                        // | | | | | |0|1| | IIR Bandwidth: 50k (for DSD) (D)
    Serial.print("50K");
    break;
  case 2:                        // | | | | | |1|0| | IIR Bandwidth: 60k (for DSD)
    Serial.println("60K");
    break;
  case 3:                        // | | | | | |1|1| | IIR Bandwidth: 70k (for DSD)
    Serial.println("70K");
    break;
  }
}

void printFirFilter(byte value){
  Serial.print("Filter:");
  switch(value){
  case 0:
    Serial.println("Sharp FIR");
    break;
  case 1:
    Serial.println("Slow FIR");
    break;
  }
}

void printBypassOSF(){         // This is just a toggle function
  Serial.print("Over/ling:");    
  if(bypassOSF==true){
    Serial.print("On");  
  }
  else {
    Serial.println("Off");                 
  }
}

void printDPLLMode(byte value){ // Print the DPLL Mode
  Serial.print("DPLL Mode:");
  switch(value){
  case 0:
    Serial.println("x128");
    break;
  case 1:
    Serial.println("x1");
    break;
  case 2:
    Serial.println("NOS");
    break;
  }
}

void printDPLL(byte value){
  Serial.print("DPLL B/W: ");
  switch(value){
  case 0:
    Serial.println("Auto");
    break;
  case 1:
    Serial.println("Lowest");
    break;
  case 2:
    Serial.println("Low");
    break;
  case 3:
    Serial.println("Low-Med");
    break;
  case 4:
    Serial.println("Medium");
    break;
  case 5:
    Serial.println("Med-High");
    break;
  case 6:
    Serial.println("High");
    break;
  case 7:
    Serial.println("Highest");
    break;
  }
}

void printInput(byte value){
  Serial.print("Input:");  
  printInputFormat(settings[input][FORMATVAL]%FORMATCHO);  // Setup input format value
  printFirFilter(settings[input][FIRVAL]%FIRCHO);          // Setup FIR filter value
  printIirFilter(settings[input][IIRVAL]%IIRCHO);          // Setup IIR filter value
  printDPLL(settings[input][DPLLVAL]%DPLLCHO);             // Setup the DPLL value
  printQuantizer(settings[input][QUANVAL]%QUANCHO);        // Setup quantizer value
  printNotch(settings[input][NOTCHVAL]%NOTCHCHO);          // Setup notch delay value
  printDPLLMode(settings[input][PLMVAL]%PLMCHO);            // Setup dpll mode value


  switch (value){
  case 0:
    Serial.println(no0);
    break;
  case 1:
    Serial.print(no1);
    break;
  case 2:
    Serial.println(no2);
    break;
  case 3:
    Serial.println(no3);
    break;
  case 4:
    Serial.println(no4);
    break;
  case 5:
    Serial.println(no5);
    break;
  case 6:
    Serial.println(no6);
    break;
  case 7:
    Serial.println(no7);
    break;
  }
}

/******************* END Print Utilities derived from setAndPrint functions *********************/

/************************ MAIN PROGRAM ************************************************************/

void setup() {
  Serial.begin(9600);

  Wire.begin();        // Join the I2C bus as a master
  startDac1();         // First part of starting the DAC
  
  Serial.println("H I F I D U I N O");
  Serial.println("v.B1.0b  STEREO");

  #ifdef DUALMONO
  Serial.println("DUALMONO");
  #endif DUALMONO
  
  #ifdef TPAPHASE
  Serial.println("DUAL-TPA");
  #endif TPAPHASE
  
  Serial.println("(c) HiFiDUINO Jan 06 2012");
  Serial.println("(c) DimDim Mar 11 2012");
  Serial.println("(c) [email protected] Apr 11 2012");

  Serial.println("");
  Serial.println("BuffaloCon 0.1");
  Serial.println("Accepting User Input");
  Serial.println("Press ? key for help");  
  
  delay(1000);

  startDac2();  // prints all the values in the screen

}  // End setup()

// -------------------------------------loop section------------------------------------------


void loop(){
  keepTime();

  if((lastInterval+INTERVAL)==totalMinutes){
    lastInterval=totalMinutes;
    Serial.println("#Interval timer ");
    printData();
  }
  
  // Serial Port Command Controll
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    //say what you got from serial for debugging
    //Serial.print("I received: ");
    //Serial.println(incomingByte, DEC);
    
    switch (incomingByte){
    case 32:                                 // Space Bar, prints input info
      printInput(input);
      break;
    case 43:                                 // + key, volume up
      Serial.println("+++");
      if (currAttnu>MINATTNU)                // Check if not already at minimum attenuation
      {
        if(dimmed) {
          rampUp();                          // Disengage dim
          dimmed=false;
        }
        
        currAttnu-=2;                      // Decrease attenuation 1 dB (increase volume 1 db)
        setSabreVolume(currAttnu);         // Write value into registers
     
        Serial.print("-");
        Serial.print(currAttnu/2);    // Print volume level
        Serial.println("dB");
      }      
      break;    
    case 45:                                 // - key, volume down
      Serial.println("---");
      if (currAttnu<MAXATTNU)                // Check if not already at maximum attenuation
      {
        if(dimmed) {
          rampUp();                        // Disengage dim
          dimmed=false;
        }
        
        currAttnu+=2;                      // Increase 1 dB attenuation (decrease volume 1 db)
        setSabreVolume(currAttnu);         // Write value into registers

        Serial.print("-");
        Serial.print(currAttnu/2);    // Print volume level
        Serial.println("dB");
       
      }      
      break;    
      
      
    case 48:  // 0 key. This is the soft mute -dim feature
      if(dimmed){                          // Back to previous volume level 1 db at a time
        rampUp();                          // Disengage dim
        dimmed=false;
      }
      else {
        if(DIM>=currAttnu) {               // only DIM if current attenuation is lower
          setSabreVolume(DIM);             // Dim volume
          
          Serial.print("-");
          Serial.print(currAttnu/2);    // Print default volume level
          Serial.println("dB");

          dimmed=true;
        }
      }
      break;
      
    case 49:  // 1 key. Select source no. 1
      input=0;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 50:  // 2 key. Select source no. 2
      input=1;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 51:  // 3 key. Select source no. 3
      input=2;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 52:  // 4 key. Select source no. 4
      input=3;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 53:  // 5 key. Select source no. 5
      input=4;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 54:  // 6 key. Select source no. 6
      input=5;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 55:  // 7 key. Select source no. 7
      input=6;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 56:  // 8 key. Select source no. 8
      input=7;
      input%=ICHO;
      setAndPrintInput(input);
      break;

    case 102:  // f key. FIR filter selection
      settings[input][FIRVAL]++;
      setAndPrintFirFilter(settings[input][FIRVAL]%FIRCHO); 
      break;            

    case 105:  // i key. IIR filter selection
      settings[input][IIRVAL]++;
      setAndPrintIirFilter(settings[input][IIRVAL]%IIRCHO);
      break;
    case 113:  // q key. Quantizer selection
      settings[input][QUANVAL]++;
      setAndPrintQuantizer(settings[input][QUANVAL]%QUANCHO);
      break;
    case 100:  // d key. DPLL setting: separate selection for SPDIF and I2S
      settings[input][DPLLVAL]++;
      setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO);
      break;
    case 110:  // n key. Notch selection
      if (digitalRead(4) == digitalRead(2)) settings[input][NOTCHVAL]--;  // CCW
      else settings[input][NOTCHVAL]++;
      setAndPrintNotch(settings[input][NOTCHVAL]%NOTCHCHO);
      break;
    case 112:  // p key. DPLL mode selection
      if (digitalRead(4) == digitalRead(2)) settings[input][PLMVAL]--;  // CCW
      else settings[input][PLMVAL]++;
      setAndPrintDPLLMode(settings[input][PLMVAL]%PLMCHO);
      break;
    case 111:  // o key. OSF Bypass -Since this is a toggle, we just call the function
      setAndPrintBypassOSF();
      break;

    case 63:  // ? key. OSF Bypass -Since this is a toggle, we just call the function
      Serial.println("BuffaloCon Help");
      Serial.println("<key>:<command>, f:FIR, i:IIR, q:Quantizer, d:DPLL, n:Notch, p:DPLLMode, o:OSF");
      Serial.println("keys 1 to 8:select input 1 to 8");
      Serial.println("keys + -:volume up/down");
      Serial.println("key 0:mute");      
      break;
      
    }  
  }  


  // "Condition" the dpll lock once at startup to see if it helps the I2S locking
  if(!primed){
    Status=readStatus();    // Read status register
    if(Status&B00000001){   // if there is a lock a lock on a signal
      primeDpll();
      primed=true;
    }
  }
  
  // Print the sample rate, input and lock (once every "INTERVAL_SAMPLE" time)
  if((millis() - displayMillis > INTERVAL_SAMPLE*1000)&&!selectMode) {
    displayMillis = millis(); // Saving last time we display sample rate
    
    Status=readStatus();  // Read status register
    if(Status&B00000100) SPDIFValid=true; // Determine if valid spdif data
    else SPDIFValid=false;                // SR calculation depends on I2S or SPDIf
      
    // Update the sample rate display if there is a lock (otherwise, SR=0)

    if(Status&B00000001){        // There is a lock in a signal
      sr = sampleRate();
      Serial.print(sr, DEC);

      if(Status&B00001000) {      // Determines if DSD

        Serial.print("DSD ");}
      else {                    // If not DSD then it is I2S or SPDIF
        if(SPDIFValid){           // If valid spdif data, then it is spdif
          Serial.print("S/PDIF ");}
        else {
          Serial.print("I2S ");  // Otherwise it is I2S
        }}
    } 
    
    else {                       // There is no lock we print input selection
      Serial.print("No Lock");}  

    StatusS=readSPDIFStatus();  // Read SPDIF status register
    pro_cons = bitRead(StatusS, 0);
    if (pro_cons = 1){
    Serial.print("Professional");}
    else {
    Serial.print("Consumer");}
    
    
    // Heatbeat to show that the software is still running...
    if(pulse++%2){
      Serial.println(".");  // Print a "pulse" to indicate the controller is working
    }
    else {
      Serial.println("_");
      
    }
  }
  
  
}

Hardware Setup:
PC -> USB -> Arduino
Arduino pins SCLK, SDA, GND -> Buffalo pins SCLK, SDA, GND (i2c header, remove original IC)
Σημείωση
Το arduino όταν είναι συνδεδεμένο με USB, δίνει πρόσβαση σε μια (ιδεατή) σειριακή θύρα Μέσω της οποίας έχουμε αμφίδρομη επικοινωνία.

Θετικά:
Δεν απαιτείται καμία οθόνη πέραν του υπολογιστή σας. ( μια καλή LCD οθόνη μη ξεχνάμε ότι κάνει ~$40)
Πρόσβαση σε όλες τις δυνατότητες προγραμματισμού του ESS Sabre32.
Ένα καλώδιο usb για τροφοδοσία του arduino και αμφίδρομη επικοινωνία μέσω serial.
Το βουβάλι προσωπικά το έχω για ‛κάρτα ήχου’ με το PC πάντα ανοιχτό σα πηγή. Όποτε με βολεύει να έχω όλα τα controls εκεί διαθέσιμα. Κάτι σαν το interface που δίνουν οι επαγγελματικές κάρτες ήχου, με ενδείξεις για όλες τις λειτουργίες και την πραγματική κατάσταση.


Πολύ απλό Keyboard Interface:
<key>:<command>
f:FIR, i : IIR, q : Quantizer, d : DPLL, n : Notch, p : DPLLMode, o : OSF
keys 1 to 8:select input 1 to 8
keys + -:volume up/down


Screen Capture:
Code:
H I F I D U I N O
v.B1.0b  STEREO
(c) HiFiDUINO Jan 06 2012
(c) DimDim Mar 11 2012
(c) [email protected] Apr 11 2012

BuffaloCon 0.1
Accepting User Input
Press ? key for help
Input:Input:I2S/DSD
Filter:Sharp FIR
IIR:PCM
DPLL B/W: Lowest
Qtz:8bT
Notch:/04
DPLL Mode:x128
Over/ling:On-2dB
<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<DPLL B/W: Lowest
No LockProfessional_
47999I2S Professional.
47999I2S Professional_
47999I2S Professional.
47999I2S Professional_
BuffaloCon Help
<key>:<command>, f:FIR, i:IIR, q:Quantizer, d:DPLL, n:Notch, p:DPLLMode, o:OSF
keys 1 to 8:select input 1 to 8
keys + -:volume up/down
key 0:mute
47999I2S Professional.
47999I2S Professional_
47999I2S Professional.
Filter:Slow FIR
47999I2S Professional_
Input:Input:I2S/DSD
Filter:Slow FIR
IIR:PCM
DPLL B/W: Lowest
Qtz:8bT
Notch:/04
DPLL Mode:x128
47999I2S Professional.
+++
-1dB
47999I2S Professional_
Input:Input:I2S/DSD
Filter:Slow FIR
IIR:PCM
DPLL B/W: Lowest
Qtz:8bT
Notch:/04
DPLL Mode:x128
47999I2S Professional.
+++
-0dB
Input:Input:I2S/DSD
Filter:Slow FIR
IIR:PCM
DPLL B/W: Lowest
Qtz:8bT
Notch:/04
DPLL Mode:x128
47999I2S Professional_
47999I2S Professional.
47999I2S Professional_
47999I2S Professional.
47999I2S Professional_
 

tmjuju

Administration Team
Staff member
21 January 2007
21,658
Το κερασάκι στην τούρτα είναι ότι με αυτό τον τρόπο έχω
Hardware volume control
Και σε DSD
Που δε δίνουν οι λίγοι software players που δουλεύουν αυτή τη στιγμή.

Θα μου πείτε το ίδιο είναι να το έκανα και με volumite (που δεν έχω πληρώσει για να αποκτήσω). Ναι, το ίδιο είναι, απλά πατώ τα πλήκτρα + - στο πληκτρολόγιο του PC αντί να περιστρέφω το διακόπτη του volumite ή να έχω άλλο ένα τηλεκοντρόλ.
Ότι βολεύει τον καθένα :)


Μιας και το interface είναι τόσο απλό, μπορεί να χρησιμοποιηθεί σαν υποδομή για να φτιάξει κανείς και γραφικό περιβάλλον. Η σειριακή επικοινωνία είναι εύκολη μέσω πλειάδας λειτουργικών συστημάτων και άρα έχουμε μια βάση για να χτίσουμε γραφικό περιβάλλον σε όποιο λειτουργικό θέλουμε.
 
Τάσο, είναι εντυπωσιακό το πόσο γρήγορα έκανες adapt τον κώδικά μου στις ανάγκες σου.. Συγχαρητήρια!

Απ' ότι φαίνεται το παραπάνω κάνει τη δουλειά μια χαρά..


ΥΓ. Χτες τελικά παρέλαβα την οθόνη! Murphy at his best.. :D Περισσότερα δίπλα..
 

tmjuju

Administration Team
Staff member
21 January 2007
21,658
ΥΓ. Χτες τελικά παρέλαβα την οθόνη! Murphy at his best.. :D Περισσότερα δίπλα..

:D :D :D

Καθάρισα το Interface για να είναι πιο βολικό. Χωρίς hearbit μιας και είναι interactive.
Ξεχώρισα και τις printX() μέσα από τις setAndPrintX().
Εάν ξεχωρίσουν τελείως οι setX() από τις printX(), τότε με #ifdef μπορούμε να κάνουμε τον κώδικα συμβατό με όλα τα πιθανά Interfaces ανάλογα με εάν δηλώσει ο χρήστης tft/serial/ir/etc.

Code:
 /**************************************************************************************************
 * BuffaloCon Code: My adaptation of the TFT HIFIDUINO code for Serial Port
 *
 * v.00.01 11/04/12 : - Initial Implementation
 *                    - Lots of unused variables from previous projects need to be removed
 *                    - Extra timer in main loop prints every INTERVAL some text
 *
 * The bellow comments (be HIFIDUINO or TFT HIFIDUINO) sill largelly apply
 *
 * Getting Started:
 * - Open a Serial connection to COM<X> where your arduino is connected. Use putty or any other sw.
 * - Wait for the banners to apear, Press ? key for Help
 ***************************************************************************************************/

 /**************************************************************************************************
 * TFT HIFIDUINO Code: My adaptation of the HiFiDUINO code so that is displays on a colour TFT.
 * 
 * v.0.51 11/03/12 : - Contains a few minor bugs but for the most part works.
 *                   - Includes support of source selection on Buffalo III boards.  
 *                   - The Apple remote codes are changed to another device's that I had handy.
 *                   - Has not been tested with I2S sources.
 *
 * The below comments (be HIFIDUINO) still largely apply.
 *
 ***************************************************************************************************/
 
 /***************************************************************************************************
 * HIFIDUINO Code: Supports Buffalo II 80Mhz and 100Mhz, stereo and dual mono. 
 * 
 * Change log:
 * v. B1.0b 01/07/12:- Compatible with Arduino 1.0 (but not backward compatible)
 *                   - Fixed Minor (potential) bugs
 *                   - Two additional settings: Oversampling bypass and jitter eliminator bypass 
 * ...NOTE COMMENTS REMOVED... 
 ***************************************************************************************************/
 
 /***************************************************************************************************
 * Code starts here
 ***************************************************************************************************/
 
// LIBRARIES
#include <Wire.h> // For I2C
#include <EEPROM.h> // We will use the eeprom to store values

// CONSTANT DEFINITION
/******************* Code Customization Section *********************/


/* First: Choose the clock frequency you have and comment the other */

#define USE80MHZ  
//#define USE100MHZ

/* Second: Choose your configuration

   | CONFIGURATION       | #define DUALMONO | #define TPAPHASE |
   |---------------------|------------------|------------------|
   | Dual mono in-phase  | un-comment       | comment          |
   | Dual mono TPA phase | un-comment       | un-comment       |
   | Stereo              | comment          | comment          |
   |---------------------|------------------|------------------|    */

//#define DUALMONO
//#define TPAPHASE

/* Optionally choose the number of inputs. 6 is the max without 
   modifying the code. You could lower the number of input choices
   here                                                             */

#define ICHO 8

/* Optionally change the name of the inputs. Use blanks if necessary */

char no0[] = "COAX 1";
char no1[] = "OPT 1";
char no2[] = "OPT 2";
char no3[] = "AES/EBU";
char no4[] = "COAX 2";
char no5[] = "COAX 3";
char no6[] = "I2S 1";
char no7[] = "I2S 2";

/* Make sure you use the correct chip address for each board

   for stereo Buffalo: use address 0x90
   for dual mono: Use address 0x90 for mono left Buffalo 
                  Use address 0x92 for mono right Buffalo           */

/********************************************************************/

#define DEFAULTATTNU 0x04 //-50 dB this is 50x2=100 or 0x64. Sabre32 is 0 to -127dB in .5dB steps
#define MAXATTNU 0xC6     //-99dB this is 99X2=198 or 0xC6 -Can go higher but LCD shows 2 digits
#define MINATTNU 0x00     //-0 dB -Maximum volume is -0 dB
#define DIM 0x8C          //-70 dB this is 70x2=140 or 0x8C. Dim volume
#define RAMP 10           // Additional msec delay per 1 db for ramping up to volume after dim

#define VOLUPPIN 4       // Button to increase  volume or RotEnc A terminal
#define VOLDOWNPIN 2     // Button to decrease volume or RotEnc B terminal
#define SELECTPIN 5      // Switch to select function
// #define BRIPIN 6         // Pin to control the LCD brightness with analogWrite
#define REMOTEPIN 9      // Pin for IR receiver (remote control)

#define INTERVAL_SAMPLE 60     // Time interval in SECONDS for refreshing the sample rate
#define INTERVAL_BOUNCE 2     // Time in milliseconds to debounce the rotary encoder
#define INTERVAL_SWITCHBOUNCE 200  // Time in milliseconds to debounce switch
#define INTERVAL_SELECT 4     // Time in sec to exit select mode when no activity

#define VOL 0  // The order of selection when clicking the select switch
#define FIR 3  // FIR filter selection
#define IIR 4  // IIR filter selection
#define QTZ 6  // Quantizer selection
#define INP 1  // Input selection
#define INF 2  // Input format selection
#define DPL 5  // DPLL bandwidth setting
#define NCH 7  // Notch selection
#define PLM 8  // DPLL mode
#define OSF 9  // Oversampling

#define B 0xFF  // The character for a completely filled box
#define A 0x20  // The character for blank

// Order of settings in the array for each input
#define FORMATVAL 0
#define FIRVAL 1
#define IIRVAL 2
#define DPLLVAL 3
#define QUANVAL 4
#define NOTCHVAL 5
#define PLMVAL 6

// Number of valid choices for each parameter
// There is one more: ICHO defined above
#define FORMATCHO 2 // SPDIF, I2S/DSD
#define FIRCHO 2    // Fast, slow
#define IIRCHO 4    // PCM, 50k, 60k, 70k
#define DPLLCHO 8   // Lowest to Best 8 values
#define QUANCHO 6   // 6bT, 7bP, 7bT, 8bP, 8bT, 9bP
#define NOTCHCHO 6  // /4 to /64
#define PLMCHO 3    // Normal x1 (NOR), Multiplier x128 (MUL), Bypass (OFF)
#define MAXPARAM 8  // Total number of parameters to keep track for each input. The 8th is for OSF
                    // But we don't keep track of that. It always starts with Oversampling on and 
                    // the function is a toggle (on/off). This is why there is no "OSFCHO"

// VARIABLE DECLARATION

// Register variables: used for registers that have lots of options. They are initialized here
// with valid values, but will eventually be overwritten by the values in EEPROM
byte reg14=0xF9; // Default value for register 14. We use a variable for reg 14 because it controls
                 // several parameters: IIR, FIR, differential whereas the other registers typically
                 // controls a single parameter.
byte reg25=0;    // 0= allow all settings
byte reg17L=0x1C;  // Auto SPDIF, 8-channel mode, other defaults
                   // reg17L is used for stereo and for left channel if set for MONO
#ifdef DUALMONO
byte reg17R=0x9D;  // Auto SPDIF, MONO RIGHT CHANNEL, other defaults
#endif DUALMONO

byte reg10=0xCE; // jitter ON, dacs unmute, other defaults

unsigned long displayMillis = 0;   // Stores last recorded time for display interval
unsigned long debounceMillis = 0;  // Stores last recorded time for switch debounce interval
unsigned long selectMillis = 0;    // Stores last recorded time for being in select mode
unsigned long sr = 0;              // Stores the incoming sample rate. Used for auto OSF bypass for 80MHz crystal

byte input=0;                 // The current input to the DAC
byte currAttnu=DEFAULTATTNU;  // Variable to hold the current attenuation value

byte select;          // To record current select position (FIL, VOL, DPLL, etc)

boolean selectMode;   // To indicate whether in select mode or not
boolean SPDIFValid;   // To indicate whether SPDIF valid data
boolean spdifIn;      // To indicate whether in I2S/DSD or SPDIF input format mode
boolean bypassOSF=false; // false=no bypass; This is the default condition at startup
boolean primed=false; // To indicate if dpll has been conditioned (once at startup)
boolean dimmed=false; // To indicate dim (mute) or not
byte pulse=0;         // Used by the "heartbeat" display
byte Status;          // To hold value of Sabre32 status register
byte StatusS;        // To hold value of Sabre32 SPDIF status register

// The following variables for the new s/pdif info feature
boolean pro_cons;
boolean samp1;
boolean samp2;
boolean samp3;
boolean samp4;
boolean bitd1;
boolean bitd2;
boolean bitd3;
boolean bitd4;

// The array holds the parameters for each input
// The current input is recorded after the array
byte settings[ICHO][MAXPARAM];  // Array to hold parameter values

void writeSettings(){
  for(byte i=0;i<ICHO;i++) {
    for (byte j=0;j<MAXPARAM;j++) {
      EEPROM.write((i*MAXPARAM)+j,settings[i][j]);
    }
  }
  EEPROM.write(ICHO*MAXPARAM,input); // Write the current input in a variable location after the array
}

void readSettings(){
  for(byte i=0;i<ICHO;i++) {
    for (byte j=0;j<MAXPARAM;j++) {
      settings[i][j]=EEPROM.read((i*MAXPARAM)+j);
    }
  }
  input=EEPROM.read(ICHO*MAXPARAM);  // Read the last saved input setting
}
  
/*
READING THE SAMPLE RATE
 
 The sample rate can be calculated by reading the DPLL 32-bit register. For SPDIF DPLL value 
 is divided by (2^32/Crystal-Frequency). In Buffalo II (original), the Crystal frequency is
 80,000,000 Hz. In Arduino (and other small microprocessors) it is NOT advisable to do floating point
 math because "it is very slow"; therefore integer math will be used to calculate the sample rate.
 
 The value of 2^32/80,000,000 is 53.687091 (which is a floating point number). If we use the 
 integer part (53 or 54) we get the following results for a 44.1K sample rate signal:  divided by 53 
 the result is 44.677K; divided by 54, the result is 43.849K. Clearly there are large errors from 
 being confined to integer math. The actual result, if we use floating point math and use all the 
 significant digits is 44,105 Hz (the 5 Hz deviation from ideal 44100 Hz is within the specification
 of SPDIF and the tolerances of the crystals and clocks involved)
 
 In order to increase the accuracy of the integer calculation, we can use more of the significant 
 digits of the divisor. I did some evaluation of the DPLL register values for sample rates ranging 
 from 44.1K to 192K and noticed that I could multiply the value of the DPLL number by up to 
 400 without overflowing the 32-bits. Therefore, since we have 32 bit number to work with, we 
 can multiply the DPLL number by  up to 400 and then divide by 400X53.687091=21475. If we do this, 
 we obtain 44.105K which is the same as the exact value.
 
 I used a spreadsheet to calculate the multipliers for SPDIF and I2S and for both 80Mhz and 100Mhz
 
 SPDIF 80Mhz:  x80, %4295
 SPDIF 100Mhz: x20, %859
 I2S 80Mhz:     x1, %3436
 I2S 100Mhz:    x4, %10995 (higher multiplier will overflow the 32bit value for 384KHz SR)
                x5, %13744 (More accurate but only works up to 192KHz SR)
 
 For I2S input format the dpll number is divided by (2^32*64/Crystal-Frequency) Note the 64 factor.
 The value of this is 3435.97 which rounds off nicely to 3436 (which is only 0.0008% error). The
 resultant value for the sample rate is the same wheter in spdif or I2S mode.
 */

// Sample rate reading routines

volatile unsigned long DPLLNum; // Variable to hold DPLL value

byte readDPLL(byte regAddr) {
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.write(regAddr);          // Queues the address of the register
  Wire.endTransmission();       // Sends the address of the register
  Wire.requestFrom(0x48,1);     // Hard coded to Buffalo, request one byte from address
                                // specified with Wire.write()/wire.endTransmission()
  //while(!Wire.available()) {  // Wait for byte to be available on the bus
  if(Wire.available())          // Wire.available indicates if data is available
    return Wire.read();         // Wire.read() reads the data on the wire
  else
    return 0;                   // In no data in the wire, then return 0 to indicate error
}

unsigned long sampleRate() {
  DPLLNum=0;
  // Reading the 4 registers of DPLL one byte at a time and stuffing into a single 32-bit number
  DPLLNum|=readDPLL(31);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(30);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(29);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(28);
  // The following calculation supports 80 MHz oscillator
  if (SPDIFValid){
    #ifdef USE80MHZ
    DPLLNum*=80;      // Calculate SR for SPDIF -80MHz part
    DPLLNum/=4295;    // Calculate SR for SDPIF -80MHz part
    #endif
    #ifdef USE100MHZ
    DPLLNum*=20;      // Calculate SR for SPDIF -100MHz part 
    DPLLNum/=859;     // Calculate SR for SDPIF -100MHz part
    #endif
  }
  else {              // Different calculation for SPDIF and I2S
    #ifdef USE80MHZ
    DPLLNum/=3436;    // Calculate SR for I2S -80MHz part
    #endif
    #ifdef USE100MHZ
    DPLLNum*=4;      // Calculate SR for I2S -100MHz part
    DPLLNum/=10995;  // Calculate SR for I2S -100MHz part
    #endif
  }
  if(bypassOSF)      // When OSF is bypassed, the magnitude of DPLL is reduced by a factor of 64
    DPLLNum*=64;
  return DPLLNum;
}

// Reading the status register. There is a status register providing the following information:
// 1- dsd or pcm mode
// 1- spdif valid or invalid
// 3- spdif mode enabled or disabled. 
// 4- Jitter Eliminator locked/not locked to incoming signal

byte readStatus() {             // Hardcoded to the status register
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.write(27);               // Hard coded to status register
  Wire.endTransmission();
  Wire.requestFrom(0x48,1);     // Hard coded to Buffalo, request one byte from address
                                // specified with Wire.write()
  //while(!Wire.available()) {  // Wait for byte to be available on the bus
  if(Wire.available())
    return Wire.read();         // Return the value returned by specified register
  else
    return 0;
}

// Reading the SPDIF status register. There is a status register providing the following information:
// 1- dsd or pcm mode
// 1- spdif valid or invalid
// 3- spdif mode enabled or disabled. 
// 4- Jitter Eliminator locked/not locked to incoming signal

byte readSPDIFStatus() {             // Hardcoded to the status register
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.write(48);               // Hard coded to status register
  Wire.endTransmission();
  Wire.requestFrom(0x48,1);     // Hard coded to Buffalo, request one byte from address
                                // specified with Wire.write()
  //while(!Wire.available()) {  // Wait for byte to be available on the bus
  if(Wire.available())
    return Wire.read();         // Return the value returned by specified register
  else
    return 0;
}


/*
CONTROLLING THE DIGITAL ATTENUATION (VOLUME) -and other registers IN THE DAC
 
 The device address of Sabre DAC Datasheet specifies the address as 0x90 which is an 8-bit value.
 The wire library in Arduino uses 7-bit device addresses and the 8th R/W bit is added automatically
 depending on whether you use the write call [beginTransmission()] or the read call [requestFrom()].
 Therefore, you will use the 7 most significant bits of the 8-bit address.
 In our example, 0x90 becomes 0x48 as follows:
 0x90: 10010000 (we eliminate the rightmost bit to get I2C address)
 0x48: 1001000
 When using dual-mono configuration, the other device can be set to addres 0x92
 0x92: 10010010 (we eliminate the rightmost bit to get I2C address)
 0x49: 1001001
 */

void writeSabreReg(byte regAddr, byte regVal)
{
  Wire.beginTransmission(0x48); //Hard coded to the the Sabre/Buffalo device address
  Wire.write(regAddr); // Specifying the address of register
  Wire.write(regVal); // Writing the value into the register
  Wire.endTransmission();
  
  #ifdef DUALMONO
  Wire.beginTransmission(0x49); //Hard coded to the the other Sabre/Buffalo device address
  Wire.write(regAddr); // Specifying the address of register
  Wire.write(regVal); // Writing the value into the register
  Wire.endTransmission();
  #endif DUALMONO
}

void setSabreVolume(byte regVal)
{
  writeSabreReg(0, regVal); // set up volume in DAC1
  writeSabreReg(1, regVal); // set up volume in DAC2
  writeSabreReg(2, regVal); // set up volume in DAC3
  writeSabreReg(3, regVal); // set up volume in DAC4
  writeSabreReg(4, regVal); // set up volume in DAC5
  writeSabreReg(5, regVal); // set up volume in DAC6
  writeSabreReg(6, regVal); // set up volume in DAC7
  writeSabreReg(7, regVal); // set up volume in DAC8
}

void rampUp()
{
  byte i=(DIM-currAttnu); 
  for(byte dimval=DIM;dimval>currAttnu;dimval--){
    setSabreVolume(dimval);
//    tft.setRotation(3);
//    tft.setCursor(130, 100);
//    tft.setTextColor(vol_color);
//    tft.setTextSize(6);
//    tft.setRotation(3);
//    tft.fillRoundRect(130, 100, 200, 60, 0, vol_back_col);
//    tft.print("-");
//    tft.print(dimval/2);
//    tft.println("dB");

      Serial.print("-");
      Serial.print(dimval/2);
      Serial.print("dB");

    delay((RAMP)*(1+(10/i*i)));
    i--;
  }
}

// Because of register 17 sets MONO/8-channel, different values are written into different chips
void writeSabreLeftReg(byte regAddr, byte regVal)
{
  Wire.beginTransmission(0x48); // Hard coded to the the Sabre/Buffalo device address for stereo
                                // or mono left. For stereo same as writeSabreReg()
  Wire.write(regAddr);          // Specifying the address of register
  Wire.write(regVal);           // Writing the value into the register
  Wire.endTransmission();
}

#ifdef DUALMONO
void writeSabreRightReg(byte regAddr, byte regVal)
{
  Wire.beginTransmission(0x49); //Hard coded to the the Sabre/Buffalo device address
  Wire.write(regAddr); // Specifying the address of register
  Wire.write(regVal); // Writing the value into the register
  Wire.endTransmission();
}
#endif DUALMONO

/*
 The following function prints a bar at the left most column to indicate that we are in "select"
 mode. One can choose any character as the "bar" For example, I used the solid square character
 */
void printSelectBar(){
  
 Serial.print("---printSelectBar");
 }

void removeSelectBar(){
  
   Serial.print("---removeSelectBar");
 }


void setAndPrintDPLL(byte value){

  Serial.print("DPLL B/W: ");
  
  switch(value){
  case 0:
    bitSet(reg25,1);            // Reg 25: set bit 1 for "use best dpll"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for best dpll
    Serial.println("Auto");
    break;
  case 1:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x85);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Lowest");
    break;
  case 2:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x89);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Low");
    break;
  case 3:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x8D);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Low-Med");
    break;
  case 4:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x91);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Medium");
    break;
  case 5:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x95);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Med-High");
    break;
  case 6:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x99);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("High");
    break;
  case 7:
    bitClear(reg25,1);          // Reg 25: Clear bit 1 for "use all settings"
    writeSabreReg(0x19,reg25);  // Write value into reg 25 for all settings
    writeSabreReg(0x0B,0x9D);   // Reg 11: Set corresponding DPLL bandwidth
    Serial.println("Highest");
    break;
  }
}

void setAndPrintDPLLMode(byte value){ // Set the DPLL Mode
  Serial.print("DPLL Mode:");
  
  switch(value){
  case 0:
    bitSet(reg10,3);           // Set bit 3 of reg 10: jitter reduction ON
    writeSabreReg(0x0A,reg10);
    bitSet(reg25,0);           // Set bit 0 of reg 25 for x128 DPLL bandwidth
    writeSabreReg(0x19,reg25);
    Serial.println("x128");
    break;
  case 1:
    bitSet(reg10,3);           // Set bit 3 of reg 10: jitter reduction ON
    writeSabreReg(0x0A,reg10);
    bitClear(reg25,0);         // Clear bit 0 of reg 25 for x1 DPLL bandwidth
    writeSabreReg(0x19,reg25);
    Serial.println("x1");
    break;
  case 2:
    bitClear(reg10,3);         // Clear bit 3 of reg 10: jitter reduction bypass
    writeSabreReg(0x0A,reg10);
    Serial.println("NOS");
    break;
  }
}

void setAndPrintBypassOSF(){         // This is just a toggle function
  if(bypassOSF==true){
    bypassOSF=false;
    bitClear(reg17L,6);              // Reg 17: clear bypass oversampling bit in register
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: bypass OSF off
    #ifdef DUALMONO
    bitClear(reg17R,6);              // Reg 17: clear bypass oversampling bit in register -dual mono
    writeSabreRightReg(0x11,reg17R); // Reg 17: bypass OSF off
    #endif DUALMONO
    

    Serial.print("Over/ling:");                 // Indicate oversampling is ON (^)

    Serial.print("On");  
}
  else {
    bypassOSF=true;
    bitSet(reg17L,6);                // Reg 17: set bypass oversampling bit in register
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: bypass OSF on
    #ifdef DUALMONO
    bitSet(reg17R,6);                // Reg 17: set bypass oversampling bit in register -dual mono 
    writeSabreRightReg(0x11,reg17R); // Reg 17: bypass OSF on
    #endif DUALMONO
    Serial.print("Over/ling:");                 // Indicate no oversampling (.)
    Serial.println("Off");                 
  }
}

void setAndPrintFirFilter(byte value){
  Serial.print("Filter:");
  switch(value){
  case 0:
    bitSet(reg14,0);           // Set bit 0 of reg 14 for sharp fir
    writeSabreReg(0x0E,reg14);
    Serial.println("Sharp FIR");
    break;
  case 1:
    bitClear(reg14,0);         // Clear bit 0 of reg 14 for slow fir
    writeSabreReg(0x0E,reg14);
    Serial.println("Slow FIR");
    break;
  }
}

void setAndPrintIirFilter(byte value){
  Serial.print("IIR:");
  //tft.setCursor(10, 32);
  switch(value){
  case 0:                        // | | | | | |0|0| | IIR Bandwidth: Normal (for PCM)
    bitClear(reg14,1);           // Clear bit 1
    bitClear(reg14,2);           // Clear bit 2
    writeSabreReg(0x0E,reg14);
    Serial.println("PCM");
    break;
  case 1:                        // | | | | | |0|1| | IIR Bandwidth: 50k (for DSD) (D)
    bitSet(reg14,1);             // Set bit 1
    bitClear(reg14,2);           // Clear bit 2
    writeSabreReg(0x0E,reg14);
    Serial.print("50K");
    break;
  case 2:                        // | | | | | |1|0| | IIR Bandwidth: 60k (for DSD)
    bitSet(reg14,2);             // Set bit 2
    bitClear(reg14,1);           // Clear bit 1
    writeSabreReg(0x0E,reg14);
    Serial.println("60K");
    break;
  case 3:                        // | | | | | |1|1| | IIR Bandwidth: 70k (for DSD)
    bitSet(reg14,1);             // Set bit 1
    bitSet(reg14,2);             // Set bit 2
    writeSabreReg(0x0E,reg14);
    Serial.println("70K");
    break;
  }
}


void setAndPrintQuantizer(byte value){

  Serial.print("Qtz:");
   
  switch(value){
  case 0:                        // 6-bit true diff
    bitSet(reg14,3);             // True differential
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0x00);    // 6-bit quantizer
    Serial.println("6bT");
    break;
  case 1:                        // 7-bit pseudo diff
    bitClear(reg14,3);           // Pseudo diff
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0x55);    // 7-bit quantizer
    Serial.println("7bP");
    break;
  case 2:                        // 7-it true diff
    bitSet(reg14,3);             // True differential
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0x55);    // 7-bit quantizer
    Serial.println("7bT");
    break;
  case 3:                        // 8-bit pseudo diff
    bitClear(reg14,3);           // Pseudo diff
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0xAA);    // 8-bit quantizer
    Serial.println("8bP");
    break;  
  case 4:                        // 8-bit true diff
    bitSet(reg14,3);             // True differential
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0xAA);    // 8-bit quantizer
    Serial.println("8bT");
    break;
  case 5:                        // 9-bit pseudo diff
    bitClear(reg14,3);           // Pseudo diff
    writeSabreReg(0x0E,reg14);
    writeSabreReg(0x0F,0xFF);    // 9-bit quantizer
    Serial.println("9bP");
    break; 
  }
}

void setAndPrintNotch(byte value){
  Serial.print("Notch:");
  switch(value){
  case 0:
    writeSabreReg(0x0C,0x20);    // No notch delay
    Serial.println("NON");
    break;
  case 1:
    writeSabreReg(0x0C,0x21);    // notch delay=mclk/4
    Serial.println("/04");
    break;
  case 2:
    writeSabreReg(0x0C,0x23);    // notch delay=mclk/8
    Serial.println("/08");
    break;
  case 3:
    writeSabreReg(0x0C,0x27);    // notch delay=mclk/16
    Serial.println("/16");
    break;  
  case 4:
    writeSabreReg(0x0C,0x2F);    // notch delay=mclk/32
    Serial.println("/32");
    break;
  case 5:
    writeSabreReg(0x0C,0x3F);    // notch delay=mclk/64
    Serial.println("/64");
    break; 
  }
}

void setAndPrintInputFormat(byte value){
  // This register also controls mono-8channel operation, thus more code...

  Serial.print("Input:");
 
  switch(value){
  case 0:
    writeSabreReg(0x08,0xE8);        // Reg 8: Enable SPDIF input format
    bitSet(reg17L,3);                // Reg 17: auto spdif detection ON -Set bit 3
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: write value into register
    #ifdef DUALMONO
    bitSet(reg17R,3);                // Reg 17: auto spdif detection ON -Set bit 3
    writeSabreRightReg(0x11,reg17R); // Reg 17: write value into register
    #endif DUALMONO
    spdifIn=true;                    // Indicates input format is spdif. For label for input format
    Serial.println("S/PDIF");
    break;
  case 1:
    bitClear(reg17L,3);              // Reg 17: manual SPDIF -Clear bit 3
    writeSabreLeftReg(0x11,reg17L);  // Reg 17: Auto spdif detection OFF
    #ifdef DUALMONO
    bitClear(reg17R,3);              // Reg 17: manual SPDIF -Clear bit 3
    writeSabreRightReg(0x11,reg17R); // Reg 17: Auto spdif detection OFF
    #endif DUALMONO
    writeSabreReg(0x08,0x68);        // Reg 8: Enable I2S/DSD input format
    spdifIn=false;                   // Set variable to indicate input format is I2S/DSD mode
    Serial.println("I2S/DSD");
    break;
  //tft.write(127);                    // Print Arrow to indicate this is input seletion and not signal
  }
}

void setAndPrintInput(byte value){


    
  setAndPrintInputFormat(settings[input][FORMATVAL]%FORMATCHO);  // Setup input format value
  setAndPrintFirFilter(settings[input][FIRVAL]%FIRCHO);          // Setup FIR filter value
  setAndPrintIirFilter(settings[input][IIRVAL]%IIRCHO);          // Setup IIR filter value
  setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO);             // Setup the DPLL value
  setAndPrintQuantizer(settings[input][QUANVAL]%QUANCHO);        // Setup quantizer value
  setAndPrintNotch(settings[input][NOTCHVAL]%NOTCHCHO);          // Setup notch delay value
  setAndPrintDPLLMode(settings[input][PLMVAL]%PLMCHO);            // Setup dpll mode value


  Serial.print("Input:");

  switch (value){
  case 0:
    writeSabreReg(0x12,0x01);        // Set SPDIF to input #1
    Serial.println(no0);
    break;
  case 1:
    writeSabreReg(0x12,0x02);        // Set SPDIF to input #2
    Serial.print(no1);
    break;
  case 2:
    writeSabreReg(0x12,0x04);        // Set SPDIF to input #3
    Serial.println(no2);
    break;
  case 3:
    writeSabreReg(0x12,0x08);        // Set SPDIF to input #4
    Serial.println(no3);
    break;
  case 4:
    writeSabreReg(0x12,0x10);        // Set SPDIF to input #5
    Serial.println(no4);
    break;
  case 5:
    writeSabreReg(0x12,0x20);        // Set SPDIF to input #6
    Serial.println(no5);
    break;
  case 6:
    writeSabreReg(0x12,0x40);        // Set SPDIF to input #7
    Serial.println(no6);
    break;
  case 7:
    writeSabreReg(0x12,0x80);        // Set SPDIF to input #8
    Serial.println(no7);
    break;
  }
}

// Array index into parts of big numbers. Each number consists of 9 custom characters
// in a 3x3 matrix. To print a number, you use the array index corresponding to the number
// times 3. For example to print the number 5, you will print bn1[15], bn1[16] and bn1[17]
// for the first row of the large number, and then bn2[15], bn2[16] and bn2[17] and so on.

//            0      1      2      3      4      5      6      7      8      9    
char bn1[]={B,2,1, 2,1,A, 2,2,1, 2,2,1, 0,A,B, B,2,2, B,2,2, 2,2,B, B,2,1, B,2,1};
char bn2[]={B,A,B, A,B,A ,0,6,5, A,2,1, 5,6,B, 2,2,1, B,6,7, A,0,5, B,6,B, 5,6,B};
char bn3[]={4,3,B, 3,B,3, B,3,3, 4,3,B, A,A,B, 4,3,B, 4,3,B, A,B,A, 4,3,B, A,A,B};


void startDac1(){               // Set registers not requiring display info
  bitSet(reg10,0);              // Set bit zero for reg 10: Mute DACs
  writeSabreReg(0x0A,reg10);    // Mute DACs. Earliest we can mute the DACs to avoid full vol
  setSabreVolume(currAttnu);    // Reg 0 to Reg 7 Set volume registers with startup volume level
  writeSabreReg(0x0D,0x00);     // DAC in-phase
  writeSabreReg(0x13,0x00);     // DACB anti-phase
  writeSabreReg(0x25,0x00);     // Use built in filter for stage 1 and stage 2
  writeSabreReg(0x0E,reg14);    // Reg 14: BuffII input map, trueDiff, normal IIR and Fast rolloff
                                // Reg 14: except BuffII input map setting, the others will be
                                // redefined.
  /*
    The code below may provide some mitigation to the white noise during silence
    #ifdef USE80MHZ
    writeSabreReg(0x10,0x08);     // Reg 16: Turn automute loopback -only to mitigate 352.8KHz noise
    writeSabreReg(0x09,0x10);     // Reg 9: Set automute time 4x less than default (value is in denom.)
    #endif USE80MHZ
  */
  
  #ifdef DUALMONO                // DAC registers default to stereo. Set to MONO L/R for dual MONO
  bitSet(reg17L,0);              // Set for MONO left channel. Right ch variable is already set for MONO
  writeSabreLeftReg(0x11,reg17L);
  writeSabreRightReg(0x11,reg17R);
  #endif DUALMONO

  #ifdef TPAPHASE  
  /* The outputs on each side of each MONO board will be in opposite phase. In order to do this
     the phase of the odd dacs are out of phase with the even dacs. Further, buffalo is configured
     such that (In dual mono mode) the channel on the DAC which is opposite of the selected channel  
     carries the same analog signal but in anti-phase (odd dacs are the left channel;
     even dacs are the right channel)
     See http://hifiduino.wordpress.com/sabre32/ for further explaination
  */
  writeSabreLeftReg(0x0D,0x22);  // MONO LEFT DACx: odd dacs=in-phase; even dacs=anti-phase
  // writeSabreLeftReg(0x13,0x00);  // MONO LEFT DACBx: all dacs anti-phase with respect to DACx
  writeSabreRightReg(0x0D,0x11); // MONO RIGHT DACx: odd dacs=anti-phase; even dacs=in-phase
  // writeSabreRightReg(0x13,0x00); // MONO RIGHT DACBx: all dacs anti-phase with respect to DACx
  #endif TPAPHASE
}

void startDac2(){
  readSettings();
  setAndPrintInput(input);


  Serial.print("Over/ling:");                 

  Serial.print("On");                   // Indicate oversampling is ON (since this is the default)

  Serial.print("-");
  Serial.print(currAttnu/2);    // Print default volume level
  Serial.println("dB");
  bitClear(reg10,0);                 // Clear bit zero of reg 10: unmute DACs
  writeSabreReg(0x0A,reg10);         // Unmute DACs
}

// The following function attempts to "prime" the DPLL by going through all settings of the DPLL
// May help the i2s locking problem???

void primeDpll(){
  bitSet(reg10,0);                   // Set bit zero of reg 10
  writeSabreReg(0x0A,reg10);         // Mute DACs.
  writeSabreReg(0x19,0x02);          // Reg 25: Allow all Best settings
  for(int i=8;i>0;i--){              // Select each DPLL settings from largest to smallest BW
    writeSabreReg(0x19,0x00);        // Reg 25: Allow all DPLL settings at 1X
    writeSabreReg(11, (125+(i*4)));  // Go through all the DPLL settings
    delay(400);

    
    //lcd.setCursor(4,2);              // To show in the screen that something is going on
    Serial.print("<|>");
    writeSabreReg(0x19,0x01);        // Reg 25: Allow all DPLL settings at 128X
    writeSabreReg(11, (161-(i*4)));  // Go through all the DPLL settings
    delay(400);
    
    //lcd.setCursor(4,2);              // To show in the screen that something is going on
    Serial.print(">|<");
  }
  setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO); // Back to original setting for dpll
  bitClear(reg10,0);                 // Clear bit zero of reg 10
  writeSabreReg(0x0A,reg10);         // Unmute DACs
}

 /***************************************************************************************************
 * Timer Code starts here
 ***************************************************************************************************/
int incomingByte = 0;   // for incoming serial data
#define INTERVAL 10             // Arbitrary time interval in minutes
unsigned long minutes=0;        // Minute count 0 to 59
unsigned long totalMinutes=0;   // Total minute count 0 to ...
unsigned long hours=0;          // Hours count 0 to ...
unsigned long lastInterval=0;   // Time in minutes of last interval

void printTime(){               // Prints hours:minutes as xx:xx
  if(hours<10)
    Serial.print("0");
  Serial.print(hours);
  Serial.print(":");
  if(minutes<10)
    Serial.print("0");
  Serial.println(minutes);
}

void keepTime(){                // Keeps track of elapsed time
  if(millis()>((60000)+(60000*minutes)+(3600000*hours))){
    minutes++;
    totalMinutes++;
    if(minutes==60){            // For every 60 minutes...
      minutes=0;                // Reset the minutes and...
      hours++;                  // Increase the hours
    }
  }
}

void printData(){
  Serial.print("Print Data");
  printTime();
}

/******************* START Print Utilities derived from setAndPrint functions *********************/

void printInputFormat(byte value){
  Serial.print("Input Format:");
  switch(value){
  case 0:
    Serial.println("S/PDIF");
    break;
  case 1:
    Serial.println("I2S/DSD");
    break;
  }
}

void printNotch(byte value){
  Serial.print("Notch:");
  switch(value){
  case 0:
    Serial.println("NON");
    break;
  case 1:
    Serial.println("/04");
    break;
  case 2:
    Serial.println("/08");
    break;
  case 3:
    Serial.println("/16");
    break;  
  case 4:
    Serial.println("/32");
    break;
  case 5:
    Serial.println("/64");
    break; 
  }
}

void printQuantizer(byte value){
  Serial.print("Qtz:");
  switch(value){
  case 0:                        // 6-bit true diff
    Serial.println("6bT");
    break;
  case 1:                        // 7-bit pseudo diff
    Serial.println("7bP");
    break;
  case 2:                        // 7-it true diff
    Serial.println("7bT");
    break;
  case 3:                        // 8-bit pseudo diff
    Serial.println("8bP");
    break;  
  case 4:                        // 8-bit true diff
    Serial.println("8bT");
    break;
  case 5:                        // 9-bit pseudo diff
    Serial.println("9bP");
    break; 
  }
}

void printIirFilter(byte value){
  Serial.print("IIR:");
  switch(value){
  case 0:                        // | | | | | |0|0| | IIR Bandwidth: Normal (for PCM)
    Serial.println("PCM");
    break;
  case 1:                        // | | | | | |0|1| | IIR Bandwidth: 50k (for DSD) (D)
    Serial.print("50K");
    break;
  case 2:                        // | | | | | |1|0| | IIR Bandwidth: 60k (for DSD)
    Serial.println("60K");
    break;
  case 3:                        // | | | | | |1|1| | IIR Bandwidth: 70k (for DSD)
    Serial.println("70K");
    break;
  }
}

void printFirFilter(byte value){
  Serial.print("Filter:");
  switch(value){
  case 0:
    Serial.println("Sharp FIR");
    break;
  case 1:
    Serial.println("Slow FIR");
    break;
  }
}

void printBypassOSF(){         // This is just a toggle function
  Serial.print("Over/ling:");    
  if(bypassOSF==true){
    Serial.print("On");  
  }
  else {
    Serial.println("Off");                 
  }
}

void printDPLLMode(byte value){ // Print the DPLL Mode
  Serial.print("DPLL Mode:");
  switch(value){
  case 0:
    Serial.println("x128");
    break;
  case 1:
    Serial.println("x1");
    break;
  case 2:
    Serial.println("NOS");
    break;
  }
}

void printDPLL(byte value){
  Serial.print("DPLL B/W: ");
  switch(value){
  case 0:
    Serial.println("Auto");
    break;
  case 1:
    Serial.println("Lowest");
    break;
  case 2:
    Serial.println("Low");
    break;
  case 3:
    Serial.println("Low-Med");
    break;
  case 4:
    Serial.println("Medium");
    break;
  case 5:
    Serial.println("Med-High");
    break;
  case 6:
    Serial.println("High");
    break;
  case 7:
    Serial.println("Highest");
    break;
  }
}


void printSR(){ 			// Print the sample rate, input and lock (once every "INTERVAL_SAMPLE" time)
    Serial.print("Actual Input Data:");    

    displayMillis = millis(); // Saving last time we display sample rate
    
    Status=readStatus();  // Read status register
    if(Status&B00000100) SPDIFValid=true; // Determine if valid spdif data
    else SPDIFValid=false;                // SR calculation depends on I2S or SPDIf
      
    // Update the sample rate display if there is a lock (otherwise, SR=0)

    if(Status&B00000001){        // There is a lock in a signal
      sr = sampleRate();
      Serial.print(sr, DEC);

      if(Status&B00001000) {      // Determines if DSD

        Serial.print(" DSD ");}
      else {                    // If not DSD then it is I2S or SPDIF
        if(SPDIFValid){           // If valid spdif data, then it is spdif
          Serial.print(" S/PDIF ");}
        else {
          Serial.print(" I2S ");  // Otherwise it is I2S
        }}
    } 
    
    else {                       // There is no lock we print input selection
      Serial.print("No Lock");}  

    StatusS=readSPDIFStatus();  // Read SPDIF status register
    pro_cons = bitRead(StatusS, 0);
    if (pro_cons = 1){
    Serial.println("Professional");}
    else {
    Serial.println("Consumer");}
    
    

  }

void printInput(byte value){

  printInputFormat(settings[input][FORMATVAL]%FORMATCHO);  // print input format value
  printFirFilter(settings[input][FIRVAL]%FIRCHO);          // print FIR filter value
  printIirFilter(settings[input][IIRVAL]%IIRCHO);          // print IIR filter value
  printDPLL(settings[input][DPLLVAL]%DPLLCHO);             // print the DPLL value
  printQuantizer(settings[input][QUANVAL]%QUANCHO);        // print quantizer value
  printNotch(settings[input][NOTCHVAL]%NOTCHCHO);          // print notch delay value
  printDPLLMode(settings[input][PLMVAL]%PLMCHO);           // print dpll mode value
  printSR();

  switch (value){
  case 0:
    Serial.println(no0);
    break;
  case 1:
    Serial.print(no1);
    break;
  case 2:
    Serial.println(no2);
    break;
  case 3:
    Serial.println(no3);
    break;
  case 4:
    Serial.println(no4);
    break;
  case 5:
    Serial.println(no5);
    break;
  case 6:
    Serial.println(no6);
    break;
  case 7:
    Serial.println(no7);
    break;
  }
  
    if(dimmed){                          
        Serial.println("MUTE ON!");
      }
  Serial.print("Volume:");
  Serial.print("-");
  Serial.print(currAttnu/2);    // Print volume level
  Serial.println("dB");
  
}

/******************* END Print Utilities derived from setAndPrint functions *********************/

/************************ MAIN PROGRAM ************************************************************/

void setup() {
  Serial.begin(9600);

  Wire.begin();        // Join the I2C bus as a master
  startDac1();         // First part of starting the DAC
  
  Serial.println("H I F I D U I N O");
  Serial.println("v.B1.0b  STEREO");

  #ifdef DUALMONO
  Serial.println("DUALMONO");
  #endif DUALMONO
  
  #ifdef TPAPHASE
  Serial.println("DUAL-TPA");
  #endif TPAPHASE
  
  Serial.println("(c) HiFiDUINO Jan 06 2012");
  Serial.println("(c) DimDim Mar 11 2012");
  Serial.println("(c) [email protected] Apr 11 2012");

  Serial.println("");
  Serial.println("BuffaloCon 0.1");
  Serial.println("Accepting User Input");
  Serial.println("Press ? key for help");  
  
  delay(1000);

  startDac2();  // prints all the values in the screen

}  // End setup()

// -------------------------------------loop section------------------------------------------


void loop(){
  keepTime();

  if((lastInterval+INTERVAL)==totalMinutes){
    lastInterval=totalMinutes;
    Serial.println("#Interval timer ");
    printData();
  }
  
  // Serial Port Command Controll
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    //say what you got from serial for debugging
    Serial.print("#>BuffaloCon - command received: '");
    Serial.print(char(incomingByte));
    Serial.print("' asci code:");
    Serial.println(incomingByte, DEC);


    
    switch (incomingByte){
    case 32:                                 // Space Bar, prints input info
      printInput(input);
      break;
    case 43:                                 // + key, volume up
      Serial.println("+++");
      if (currAttnu>MINATTNU)                // Check if not already at minimum attenuation
      {
        if(dimmed) {
          rampUp();                          // Disengage dim
          dimmed=false;
        }
        
        currAttnu-=2;                      // Decrease attenuation 1 dB (increase volume 1 db)
        setSabreVolume(currAttnu);         // Write value into registers
     
        Serial.print("-");
        Serial.print(currAttnu/2);    // Print volume level
        Serial.println("dB");
      }      
      break;    
    case 45:                                 // - key, volume down
      Serial.println("---");
      if (currAttnu<MAXATTNU)                // Check if not already at maximum attenuation
      {
        if(dimmed) {
          rampUp();                        // Disengage dim
          dimmed=false;
        }
        
        currAttnu+=2;                      // Increase 1 dB attenuation (decrease volume 1 db)
        setSabreVolume(currAttnu);         // Write value into registers

        Serial.print("-");
        Serial.print(currAttnu/2);    // Print volume level
        Serial.println("dB");
       
      }      
      break;    
      
      
    case 48:  // 0 key. This is the soft mute -dim feature
      Serial.println("MUTE MUTE MUTE");
      if(dimmed){                          // Back to previous volume level 1 db at a time
        rampUp();                          // Disengage dim
        dimmed=false;
      }
      else {
        if(DIM>=currAttnu) {               // only DIM if current attenuation is lower
          setSabreVolume(DIM);             // Dim volume
          
          Serial.print("-");
          Serial.print(currAttnu/2);    // Print default volume level
          Serial.println("dB");

          dimmed=true;
        }
      }
      break;
      
    case 49:  // 1 key. Select source no. 1
      input=0;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 50:  // 2 key. Select source no. 2
      input=1;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 51:  // 3 key. Select source no. 3
      input=2;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 52:  // 4 key. Select source no. 4
      input=3;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 53:  // 5 key. Select source no. 5
      input=4;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 54:  // 6 key. Select source no. 6
      input=5;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 55:  // 7 key. Select source no. 7
      input=6;
      input%=ICHO;
      setAndPrintInput(input);
      break;
    
    case 56:  // 8 key. Select source no. 8
      input=7;
      input%=ICHO;
      setAndPrintInput(input);
      break;

    case 102:  // f key. FIR filter selection
      settings[input][FIRVAL]++;
      setAndPrintFirFilter(settings[input][FIRVAL]%FIRCHO); 
      break;            

    case 105:  // i key. IIR filter selection
      settings[input][IIRVAL]++;
      setAndPrintIirFilter(settings[input][IIRVAL]%IIRCHO);
      break;
    case 113:  // q key. Quantizer selection
      settings[input][QUANVAL]++;
      setAndPrintQuantizer(settings[input][QUANVAL]%QUANCHO);
      break;
    case 100:  // d key. DPLL setting: separate selection for SPDIF and I2S
      settings[input][DPLLVAL]++;
      setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO);
      break;
    case 110:  // n key. Notch selection
      if (digitalRead(4) == digitalRead(2)) settings[input][NOTCHVAL]--;  // CCW
      else settings[input][NOTCHVAL]++;
      setAndPrintNotch(settings[input][NOTCHVAL]%NOTCHCHO);
      break;
    case 112:  // p key. DPLL mode selection
      if (digitalRead(4) == digitalRead(2)) settings[input][PLMVAL]--;  // CCW
      else settings[input][PLMVAL]++;
      setAndPrintDPLLMode(settings[input][PLMVAL]%PLMCHO);
      break;
    case 111:  // o key. OSF Bypass -Since this is a toggle, we just call the function
      setAndPrintBypassOSF();
      break;

    case 63:  // ? key. OSF Bypass -Since this is a toggle, we just call the function
      Serial.println("BuffaloCon Help");
      Serial.println("<key>:<command>, f:FIR, i:IIR, q:Quantizer, d:DPLL, n:Notch, p:DPLLMode, o:OSF");
      Serial.println("keys 1 to 8:select input 1 to 8");
      Serial.println("keys + -:volume up/down");
      Serial.println("key 0:mute");      
      Serial.println("press spacebar to view current input info");
      break;
      
    }  
  }  


  // "Condition" the dpll lock once at startup to see if it helps the I2S locking
  if(!primed){
    Status=readStatus();    // Read status register
    if(Status&B00000001){   // if there is a lock a lock on a signal
      primeDpll();
      primed=true;
    }
  }
/**********************************************************************************
 * No HeartBeat  - this is an interactive service - if need press space bar
 
  // Print the sample rate, input and lock (once every "INTERVAL_SAMPLE" time)
  if((millis() - displayMillis > INTERVAL_SAMPLE*1000)&&!selectMode) {
    displayMillis = millis(); // Saving last time we display sample rate
    
    Status=readStatus();  // Read status register
    if(Status&B00000100) SPDIFValid=true; // Determine if valid spdif data
    else SPDIFValid=false;                // SR calculation depends on I2S or SPDIf
      
    // Update the sample rate display if there is a lock (otherwise, SR=0)

    if(Status&B00000001){        // There is a lock in a signal
      sr = sampleRate();
      Serial.print(sr, DEC);

      if(Status&B00001000) {      // Determines if DSD

        Serial.print("DSD ");}
      else {                    // If not DSD then it is I2S or SPDIF
        if(SPDIFValid){           // If valid spdif data, then it is spdif
          Serial.print("S/PDIF ");}
        else {
          Serial.print("I2S ");  // Otherwise it is I2S
        }}
    } 
    
    else {                       // There is no lock we print input selection
      Serial.print("No Lock");}  

    StatusS=readSPDIFStatus();  // Read SPDIF status register
    pro_cons = bitRead(StatusS, 0);
    if (pro_cons = 1){
    Serial.print("Professional");}
    else {
    Serial.print("Consumer");}
    
    
    // Heatbeat to show that the software is still running...
    if(pulse++%2){
      Serial.println(".");  // Print a "pulse" to indicate the controller is working
    }
    else {
      Serial.println("_");
      
    }
  }
  
 No HeartBit END*/ 
}


Output Capture:
Code:
H I F I D U I N O
v.B1.0b  STEREO
(c) HiFiDUINO Jan 06 2012
(c) DimDim Mar 11 2012
(c) [email protected] Apr 11 2012
Input:S/PDIF
Filter:Slow FIR
IIR:70K
DPLL B/W: Low
Qtz:7bT
Notch:/32
DPLL Mode:x128
Input:Over/ling:On-2dB

BuffaloCon 0.1
Accepting User Input
Press ? key for help
#>
#>BuffaloCon - command received: '1' asci code:49
Input:I2S/DSD
Filter:Slow FIR
IIR:70K
DPLL B/W: Highest
Qtz:8bP
Notch:/16
DPLL Mode:x128
Input:COAX 1
<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<<|>>|<DPLL B/W: Highest
#>BuffaloCon - command received: '?' asci code:63
BuffaloCon Help
<key>:<command>, f:FIR, i:IIR, q:Quantizer, d:DPLL, n:Notch, p:DPLLMode, o:OSF
keys 1 to 8:select input 1 to 8
keys + -:volume up/down
key 0:mute
press spacebar to view current input info
#>BuffaloCon - command received: ' ' asci code:32
Input Format:I2S/DSD
Filter:Slow FIR
IIR:70K
DPLL B/W: Highest
Qtz:8bP
Notch:/16
DPLL Mode:x128
Actual Input Data:44104 I2S Professional
COAX 1
Volume:-2dB
#>BuffaloCon - command received: '+' asci code:43
+++
-1dB
#>BuffaloCon - command received: '+' asci code:43
+++
-0dB
 

tmjuju

Administration Team
Staff member
21 January 2007
21,658
Ένα πρώτο interface σε windows

buffalocon1.png

Βασίζεται στην παραπάνω επικοινωνία μέσω σειριακής με arduino που τελικά με i2c ελέγχει τον πυρήνα του dac.
Δεν είναι και κούκλα το Interface αλλά κάνει τη δουλεία του με mouse interface (αντί του tactile-keyboard-serial-console). Ήταν η πρώτη επαφή μου με Visual Studio 11 Express.

Code:
Public Class Form1
    Dim port_name As String()
    Dim i As Integer
    Dim j As Integer

    Dim send_data As String
    Dim input As Integer = 0
    Dim receive_data As String
    Dim Ctr As Control
    Dim BRx(512) As Byte
    Dim SP As IO.Ports.SerialPort


    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Set up serialport 1

        SerialPort1.DataBits = 8
        SerialPort1.StopBits = IO.Ports.StopBits.One
        SerialPort1.Parity = IO.Ports.Parity.None

        'Set up Combobox comport 1
        cbb_comport.DropDownStyle = ComboBoxStyle.DropDownList
        cbb_baudrate.DropDownStyle = ComboBoxStyle.DropDownList
        cbb_stopbit.DropDownStyle = ComboBoxStyle.DropDownList
        cbb_parity.DropDownStyle = ComboBoxStyle.DropDownList
        cbb_databit.DropDownStyle = ComboBoxStyle.DropDownList
        cbb_flow.DropDownStyle = ComboBoxStyle.DropDownList

        cbb_comport.Sorted = True
        port_name = IO.Ports.SerialPort.GetPortNames()
        For Each comp1 In port_name
            cbb_comport.Items.Add(comp1)
        Next
        cbb_comport.SelectedIndex = IO.Ports.SerialPort.GetPortNames.Length - 1

        'Set up combobox baudrate 1
        cbb_baudrate.Items.Add(2400)
        cbb_baudrate.Items.Add(4800)
        cbb_baudrate.Items.Add(9600)
        cbb_baudrate.Items.Add(14400)
        cbb_baudrate.Items.Add(19200)
        cbb_baudrate.Items.Add(38400)
        cbb_baudrate.Items.Add(56000)
        cbb_baudrate.Items.Add(57600)
        cbb_baudrate.Items.Add(115200)
        cbb_baudrate.Items.Add(128000)
        cbb_baudrate.Items.Add(256000)

        cbb_baudrate.SelectedIndex = 2
        'Set up combobox databit 1

        cbb_databit.Items.Add(8)
        cbb_databit.SelectedIndex = 0

        cbb_stopbit.Items.Add(IO.Ports.StopBits.One)
        cbb_stopbit.SelectedIndex = 0

        For Each s In [Enum].GetNames(GetType(IO.Ports.Parity))
            cbb_parity.Items.Add(s)
        Next s
        cbb_parity.SelectedIndex = 0

        For Each s In [Enum].GetNames(GetType(IO.Ports.Handshake))
            cbb_flow.Items.Add(s)
        Next s

        cbb_flow.SelectedIndex = 0


        btn_DisConnect.Enabled = False

        cbb_parity.Cursor = Cursors.No
        cbb_parity.Enabled = False
        cbb_flow.Cursor = Cursors.No
        cbb_flow.Enabled = False
        cbb_baudrate.Cursor = Cursors.No
        cbb_baudrate.Enabled = False
        cbb_stopbit.Cursor = Cursors.No
        cbb_stopbit.Enabled = False
        cbb_databit.Cursor = Cursors.No
        cbb_databit.Enabled = False

        Me.Text = "BuffaloConWin v0.1"

    End Sub

    Private Sub btn_Connect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Connect.Click


        Me.Text = "Serial Communication Starting..."

        tmr_SerialTimer.Enabled = True
        tmr_SerialTimer.Interval = 500

        Me.SerialPort1.PortName = cbb_comport.SelectedItem
        Me.SerialPort1.BaudRate = cbb_baudrate.SelectedItem
        Me.SerialPort1.StopBits = cbb_stopbit.SelectedItem
        'Me.SerialPort1.Parity = [Enum].GetNames(GetType(IO.Ports.Parity))(cbb_parity.SelectedItem)
        Me.SerialPort1.DataBits = cbb_databit.SelectedItem
        'Me.SerialPort1.Handshake = cbb_flow.SelectedItem


        'Me.SerialPort1.PortName = "COM4"
        'Me.SerialPort1.BaudRate = 9600
        'Me.SerialPort1.StopBits = IO.Ports.StopBits.One
        Me.SerialPort1.Parity = IO.Ports.Parity.None
        'Me.SerialPort1.DataBits = 8
        Me.SerialPort1.Handshake = IO.Ports.Handshake.None

        Try
            'SerialPort1.Close()
            'SerialPort1.Open()
            'delay(10000)
            Me.SerialPort1.Open()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try

        Me.Text = "BuffaloConWin v0.1 - Serial Communication Opened..."

        Me.SerialPort1.DiscardOutBuffer()           'clear output buffer
        Me.SerialPort1.DiscardInBuffer()            'clear input buffer
        Me.SerialPort1.RtsEnable = False
        Me.SerialPort1.DtrEnable = False

        btn_DisConnect.Enabled = True
        btn_Connect.Enabled = False

        '----------------------------------------

        Me.Text = "BuffaloConWin v0.1 - Serial Communication" & "    " & "(Connected)"
        Panel1.BackColor = Color.Lime

        cbb_comport.Cursor = Cursors.No

    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmr_SerialTimer.Tick
        For Me.i = 0 To 511
            BRx(i) = 0
        Next
        receive_data = SerialPort1.BytesToRead
        If receive_data = 0 Then Exit Sub
        If receive_data > 512 Then
            receive_data = 512
        End If
        For Me.j = 1 To receive_data
            BRx(input) = SerialPort1.ReadByte
            txt_receive.Text = txt_receive.Text & Chr(BRx(input))



            If 35 = BRx(input) Then
                txt_LastCommand.Text = ""
            End If
            txt_LastCommand.Text = txt_LastCommand.Text & Chr(BRx(input))


            input = input + 1
        Next
        input = 0
        tmr_SerialTimer.Enabled = False


        For Me.i = 0 To 255
            BRx(i) = 0
        Next
        tmr_SerialTimer.Interval = 500
        tmr_SerialTimer.Enabled = True

    End Sub

    Public Sub delay(ByVal wait As Long)
        Dim i As Long
        For i = 0 To wait
        Next i
    End Sub

    Private Sub btn_DisConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_DisConnect.Click
        SerialPort1.Close()
        tmr_SerialTimer.Stop()
        btn_DisConnect.Enabled = False
        btn_Connect.Enabled = True

        Panel1.BackColor = Color.Transparent

        btn_Connect.Enabled = True
        btn_DisConnect.Enabled = False
        cbb_comport.Enabled = True
        'cbb_baudrate.Enabled = True
        'cbb_databit.Enabled = True
        Me.Text = "BuffaloConWin v0.1 -" & "    " & "(Disconnected)"
    End Sub

    Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click
        txt_receive.Clear()
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click

        If ckb_preClear.Checked Then
            txt_receive.Clear()
        End If

        send_data = 0
        For Me.i = 0 To Len(txtSend.Text) - 1
            send_data = Mid(txtSend.Text, 1 + i, 1)
            Me.SerialPort1.Write(send_data)
            Call delay(90000)
        Next i
    End Sub



    Private Sub btn_VolUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_VolUp.Click
        Me.SerialPort1.Write("+")
        Call delay(90000)
    End Sub

    Private Sub btn_VolDn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_VolDn.Click
        Me.SerialPort1.Write("-")
        Call delay(90000)
    End Sub

    Private Sub btn_FIR_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_FIR.Click
        Me.SerialPort1.Write("f")
        Call delay(90000)
    End Sub

    Private Sub btn_help_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_help.Click
        Me.SerialPort1.Write("?")
        Call delay(90000)
    End Sub

    Private Sub btn_space_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_space.Click
        Me.SerialPort1.Write(" ")
        Call delay(90000)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_IRR.Click
        Me.SerialPort1.Write("i")
        Call delay(90000)
    End Sub

    Private Sub btn_DPLL_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_DPLL.Click
        Me.SerialPort1.Write("d")
        Call delay(90000)
    End Sub

    Private Sub btn_Q_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Q.Click
        Me.SerialPort1.Write("q")
        Call delay(90000)
    End Sub

    Private Sub btn_Notch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Notch.Click
        Me.SerialPort1.Write("n")
        Call delay(90000)
    End Sub

    Private Sub btn_OFS_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_OFS.Click
        Me.SerialPort1.Write("o")
        Call delay(90000)
    End Sub



    Private Sub btn_LEDs_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_LEDs.Click
        If txt_receive.Text.Contains("Filter:Sharp FIR") Then
            lbl_FIR.Text = "Filter:Sharp FIR"
        End If


    End Sub
End Class
 
28 June 2006
2,930
Τάσο τα σέβη μου. Κλίνω ευλαβικά το γόνυ..
Ψιλοάσχετο: Το gui για windows με τι είναι φτιαγμένο? (κάποιο framework, σκληροπυρηνικό win API..)
Το πήγες πολλά βήματα παραπέρα το θέμα. Λόγω υποχρεώσεων στην παρούσα φάση, δεν μπορώ να ασχοληθώ, δυστυχώς. Ζηλεύω πάντως....
 
28 June 2006
2,930
Φυσικά, μπορεί κανείς αν θέλει, να παραμείνει στη hardcore γραμμή του Δημήτρη. Επίσης :grinning-smiley-043^3.
Η διεπαφή μέσω pc πάντως έχει κι αυτή τα δικά της - μεγάλα - πλεονεκτήματα.
 

tmjuju

Administration Team
Staff member
21 January 2007
21,658
Re: Απάντηση: BuffaloCon

Τάσο τα σέβη μου. Κλίνω ευλαβικά το γόνυ..
Ψιλοάσχετο: Το gui για windows με τι είναι φτιαγμένο? (κάποιο framework, σκληροπυρηνικό win API..)
Το πήγες πολλά βήματα παραπέρα το θέμα. Λόγω υποχρεώσεων στην παρούσα φάση, δεν μπορώ να ασχοληθώ, δυστυχώς. Ζηλεύω πάντως....

Με τη δωρεάν έκδοση του Visual Studio 2010 Express της MS http://www.microsoft.com/visualstudio/en-us/products/2010-editions/express είναι φτιαγμένο Κώστα, το gui είναι windows forms application. Έχει γραφικό περιβάλλον να φτιάξεις το gui.
Ήθελα να φτιάξω κάτι που να θυμίζει το ‛control panel’ που δίνουν οι επαγγελματικές κάρτες ήχου.
Το μοναδικό άλλο Interface που σκεφτόμουν είναι ένα Linux-http που να κάθετε καλά σε voyage linux mpd, ή αντίστοιχο light music server.
Γενικά χρήσιμη εμπειρία, και ευχαρίστως να εξετάσουμε και κάποιο άλλο dac, κάπου εδώ με το sabre έχουμε αξιοποιήσει τα γνωστά registers / settings και ασχολούμαστε μόνο με interfaces.
 

tmjuju

Administration Team
Staff member
21 January 2007
21,658
O παραπάνω κώδικας είναι VB (forms όχι cli), αλλά από όσο πρόλαβα να δώ το ίδιο εύκολο είναι και η C#
Αν θες το κάνουμε σαν άσκηση και σε C# :)
Αν κατεβάσεις το Visual Studio Express , κατέβασε το ISO που έχει όλες τις εκδώσεις για εγκατάσταση.
(Δεν έχω δώσει τον αυτόματο κώδικα για interface Που βγάζει το Visual Studio. Γιατί είναι λέει auto generated by MS, copyright MS, και παρατήρησα και στο web ότι οι περισσότεροι δε δίνουν το autogenerated. Δεν είμαι και τόσο ειδικός δηλαδή σε αυτά, μισή μέρα δουλεία είναι το παραπάνω)

Γενικά όχι δε το θεωρώ ωραία δουλεία – κακάσχημο είναι :p
Αλλά αφού είμαι ο μοναδικός που θα το χρησιμοποιήσει δε πειράζει :D
 
28 June 2006
2,930
Είναι παραπάνω από ικανοποιητικό. Έχει τα βασικά controls, πληροφόρηση για τις παραμέτρους, δεν θα το πάμε και σε διαγωνισμό για την ομορφότερη διεπαφή :)