Advertisement
Guest User

Untitled

a guest
Mar 13th, 2020
427
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.85 KB | None | 0 0
  1. #include <SPI.h>
  2. #include <Wire.h>
  3. #include <EEPROM.h>
  4.  
  5. const byte
  6.   STB = 6,
  7.   MUTE = 5,
  8.   TDA = 68;
  9.  
  10. byte
  11.   headunitSourceIndex = 0, // 0,1,2
  12.   headunitMasterVolume = 0, // 0 to 63
  13.   headunitFrontLeft = 0,
  14.   headunitFrontRight = 0,
  15.   headunitRearLeft = 0,
  16.   headunitRearRight = 0;
  17.  
  18. int
  19.   headunitBass = 0,
  20.   headunitTreble = 0;
  21.  
  22. volatile unsigned long
  23.   lastChangeTimestamp = 0,
  24.   lastConfigTimestamp = 0;
  25.  
  26. bool muteSequenceFound = false;
  27.  
  28. static byte pml009State[17] = {
  29.   0x0B, 0x58, 0x58, 0x00,
  30.   0x00, 0x00, 0xB0, 0x00,
  31.   0x00, 0x10, 0x00, 0x40,
  32.   0x40, 0xC0, 0x86, 0xC0,
  33.   0x86
  34. };
  35.  
  36. // 0 to 63 with a 1.25 db step,
  37. // rounded to nearest integer for PML009A
  38. const byte tda7303Decibels[64] = {
  39.   0,1,3,4,5,6,8,9,10,11,13,14,15,
  40.   16,18,19,20,21,23,24,25,26,28,29,
  41.   30,31,33,34,35,36,38,39,40,41,43,
  42.   44,45,46,48,49,50,51,53,54,55,56,
  43.   58,59,60,61,63,64,65,66,68,69,70,
  44.   71,73,74,75,76,78,79
  45. };
  46.  
  47. // Loudness: low (PML009A loudness [15-0] against TDA7303 main volume index [0-63], reversed)
  48. const byte loudnessMode4[64] = {
  49.   13,13,13,13,13,13,13,13,13,13,
  50.   13,13,13,13,13,13,13,13,13,13,
  51.   13,13,13,13,13,13,13,13,12,12,
  52.   12,12,12,11,11,11,11,10,10,10,
  53.   10,9,8,8,7,6,6,5,5,4,3,3,2,2,2,
  54.   1,1,1,0,0,0,0,0,0
  55. };
  56.  
  57. // Loudness: mid
  58. const byte loudnessMode11[64] = {
  59.   13,13,13,13,13,13,13,13,13,13,
  60.   13,13,13,13,13,13,13,13,13,13,
  61.   13,13,13,13,13,13,13,13,13,13,
  62.   13,13,13,13,13,13,13,13,13,13,
  63.   13,12,11,11,10,9,9,8,8,7,6,6,5,
  64.   4,4,3,3,2,1,1,0,0,0,0
  65. };
  66.  
  67. // Loudness: high
  68. const byte loudnessMode15[64] = {
  69.   15,15,15,15,15,15,15,15,15,15,
  70.   15,15,15,15,15,15,15,15,15,15,
  71.   15,15,15,15,15,15,15,15,15,15,
  72.   15,14,14,14,14,14,14,14,14,14,
  73.   14,13,12,12,11,10,10,9,9,8,7,7,
  74.   6,5,5,4,4,3,2,2,1,0,0,0
  75. };
  76.  
  77. void setup() {
  78.   // save config
  79.   if (EEPROM.read(0) == 2) {
  80.     for (int i = 3; i <= 9; i++) {
  81.       pml009State[i] = EEPROM.read(i);
  82.     }
  83.   }
  84.  
  85.   Serial.begin(115200);
  86.   pinMode(STB, OUTPUT);
  87.   pinMode(MUTE, OUTPUT);
  88.   SPI.begin();
  89.  
  90.   Wire.begin(TDA);
  91.   Wire.onReceive(tda7303Cmd);
  92. }
  93.  
  94. int inputPos = 0;
  95. unsigned long inputTimer = 0;
  96.  
  97. void loop() {
  98.   if (lastChangeTimestamp > 0 && millis() - lastChangeTimestamp > 30) {
  99.     digitalWrite(MUTE, LOW);
  100.    
  101.     pml009State[0] = headunitSourceIndex | 0b10000; // source and gain adjustment
  102.  
  103.     // TDA7303 has a wide range main volume control from 0 to -80db (1.25 db steps),
  104.     // per-channel attenuators and automatic loudness control (on/off),
  105.     // whereas PML009A has a narrower primary adjustment from 0 to -31db (1 db steps),
  106.     // deeper per-channel attenuators (-63 to 0 db w/ mute, 1 db steps) and
  107.     // manual loudness control (-15 to 0 db att 1 db steps w/ mode switches).
  108.     //
  109.     // The following code maps TDA7303 to PML009A state using lookups
  110.     // defined above (obtained by sniffing DEH-P4500R commands to PML009A and
  111.     // recalculated to match nearest matching decibel target value).
  112.    
  113.     byte dbTarget = tda7303Decibels[headunitMasterVolume];
  114.  
  115.     byte loudness = 0;
  116.    
  117.     switch(pml009State[6] >> 4) {
  118.       case 4:
  119.         loudness = loudnessMode4[63 - headunitMasterVolume];
  120.         break;
  121.       case 11:
  122.         loudness = loudnessMode11[63 - headunitMasterVolume];
  123.         break;
  124.       case 15:
  125.         loudness = loudnessMode15[63 - headunitMasterVolume];
  126.         break;
  127.     }
  128.  
  129.     // increase gain against volume drop in the loudness contour
  130.     dbTarget -= loudness;
  131.  
  132.     // set loudness gain/att bits
  133.     pml009State[6] = (pml009State[6] & 0b11110000) | loudness;
  134.  
  135.     // apply balance/fader
  136.     byte fl = max(0, dbTarget + headunitFrontLeft);
  137.     byte fr = max(0, dbTarget + headunitFrontRight);
  138.     byte rl = max(0, dbTarget + headunitRearLeft);
  139.     byte rr = max(0, dbTarget + headunitRearRight);
  140.  
  141.     // split dbTarget into primary and secondary controls
  142.     byte primaryLeft = min(31, min(fl, rl));
  143.     byte primaryRight = min(31, min(fr, rr));
  144.     pml009State[01] = primaryLeft | 0b01000000;
  145.     pml009State[02] = primaryRight | 0b01000000;
  146.     pml009State[11] = min(63, fl - primaryLeft) | 0b01000000;
  147.     pml009State[12] = min(63, fr - primaryRight) | 0b01000000;
  148.     pml009State[13] = min(63, rl - primaryLeft) | 0b11000000;
  149.     pml009State[15] = min(63, rr - primaryRight) | 0b11000000;
  150.  
  151.     auto commonSecLeft = min(fl, rl) - primaryLeft;
  152.     auto commonSecRight = min(fr, rr) - primaryRight;
  153.     pml009State[14] = min(63, commonSecLeft + 7 - headunitBass * 2 + max(0, min(headunitBass, headunitBass - commonSecLeft / 2))) | 0b10000000;
  154.     pml009State[16] = min(63, commonSecRight + 7 - headunitBass * 2 + max(0, min(headunitBass, headunitBass - commonSecRight / 2))) | 0b10000000;
  155.     // the purpose of the above binary constants is unknown
  156.  
  157.     SPI.beginTransaction(SPISettings(100000, LSBFIRST, SPI_MODE3));
  158.     digitalWrite(STB, HIGH);
  159.     for (int i = 0; i < 17; i++) {
  160.      SPI.transfer(pml009State[i]);
  161.     }
  162.     digitalWrite(STB, LOW);
  163.     SPI.endTransaction();
  164.     Serial.write(0xFF); // sync
  165.     Serial.write(pml009State + 3, 7);
  166.     lastChangeTimestamp = 0;
  167.   }
  168.  
  169.   while(Serial.available()) {
  170.     if (millis() - inputTimer < 100 && inputPos > 0) {
  171.       pml009State[inputPos++] = Serial.read();
  172.       if (inputPos > 9) {
  173.         inputPos = 0;
  174.         inputTimer = 0;
  175.         lastChangeTimestamp = millis();
  176.         lastConfigTimestamp = millis();
  177.       }
  178.     }
  179.     else if (Serial.read() == 0xFF) { // sync
  180.       inputPos = 3;
  181.       inputTimer = millis();
  182.     }
  183.   }
  184.  
  185.   if ((muteSequenceFound && lastConfigTimestamp > 0) || millis() - lastConfigTimestamp > 30000) {
  186.     muteSequenceFound = false;
  187.     lastConfigTimestamp = 0;
  188.    
  189.     // save config
  190.     EEPROM.update(0, 2);
  191.     for (int i = 3; i <= 9; i++) {
  192.       EEPROM.update(i, pml009State[i]);
  193.     }
  194.   }
  195. }
  196.  
  197. void tda7303Cmd(int byteCount) {
  198.   while(1 < Wire.available());
  199.   byte cmd = Wire.read();
  200.  
  201.   // mute sequence detection.
  202.   // we're looking for these four bytes close to each other
  203.   if (cmd == 0x9F || cmd == 0xBF || cmd == 0xDf || cmd == 0xFF) {
  204.     muteSequenceFound = true;
  205.   }
  206.  
  207.   if (cmd <= B00111111) {
  208.     headunitMasterVolume = cmd;
  209.   }
  210.   else if (cmd <= B01011111) {
  211.     headunitSourceIndex = cmd & 0b11;
  212.     digitalWrite(MUTE, HIGH);
  213.   }
  214.   else if (cmd <= B01101111) {
  215.     headunitBass = (cmd & 0b1000 ? +1 : -1) * (7 - cmd & 0b111);
  216.   }
  217.   else if (cmd <= B01111111) {
  218.     headunitTreble = (cmd & 0b1000 ? +1 : -1) * (7 - cmd & 0b111);
  219.   }
  220.   else if (cmd <= B10011111) {
  221.     headunitFrontLeft = cmd & 0b11111;
  222.   }
  223.   else if (cmd <= B10111111) {
  224.     headunitFrontRight = cmd & 0b11111;
  225.   }
  226.   else if (cmd <= B11011111) {
  227.     headunitRearLeft = cmd & 0b11111;
  228.   }
  229.   else if (cmd <= B11111111) {
  230.     headunitRearRight = cmd & 0b11111;
  231.   }
  232.  
  233.   lastChangeTimestamp = millis();
  234.  
  235.   //char buf[5] = { 0, 0, 0, 0, 0 };
  236.   //sprintf(buf, " %x", cmd);
  237.   //Serial.println(buf);
  238. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement