Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Power on BT module only if HU in CD-changer mode #17

Open
BK-Poland opened this issue Sep 3, 2018 · 66 comments
Open

Power on BT module only if HU in CD-changer mode #17

BK-Poland opened this issue Sep 3, 2018 · 66 comments

Comments

@BK-Poland
Copy link

Great job! Thank you! I have only one "little" dream: Is it possible to switch power on the BT module only when I switch to the CD changer in HU? BT turned off when I listen to FM radio.

@archi
Copy link

archi commented Sep 3, 2018

On the hardware side you could add a relay or a suitable NPN transistor to control the power of the module. Software-wise: The protocol allows for this for sure, but @visualapproach would need to add some code to handle that (I didn't look at the code, so no idea how possible that is).

@BK-Poland
Copy link
Author

Hardware for me is no problem. The Arduino output controls the transistor that powers the BT module. The question is: it can be programmed? @visualapproach ? Does Arduino get a message from HU that the CD-changer is on?

@visualapproach
Copy link
Owner

Sure thing, I Will have a look at it and post somerhing soon.

@BK-Poland
Copy link
Author

I will be waiting for a good news. :-)

@visualapproach
Copy link
Owner

visualapproach commented Sep 3, 2018

Code removed and reposted for readability

@visualapproach
Copy link
Owner

check lines 43 and 713-740
That should do it, I think

@BK-Poland
Copy link
Author

I have connected according to: older_stuff/schematics_melbus_hack_v2.
All I need to do is change the PLAY PIN from 12 to 10?
And connect Arduino PIN 5 to base of NPN transistor?

@visualapproach
Copy link
Owner

visualapproach commented Sep 4, 2018

No, you shouldn't have to change PLAY PIN. What you wanna do is to capture POWERON-message and switch on the transistor. If POWEROFF is received, you turn off the transistor. That's all you need to change.

If you use the old code (v7i line 255 onwards), look at the following snippets and adjust according to my suggestion:

         //6, power up. resp ack (0x00), not verified
          case 6:
            byteToSend = 0x00;
            SendByteToMelbus();
            trackInfo[1] = startByte;
            trackInfo[8] = startByte;
            -->   digitalWrite(5, HIGH); //change "5" to whatever pin you have connected to the transistor.
            break;
          //7, power down. ack (0x00), not verified
          case 7:
            byteToSend = 0x00;
            SendByteToMelbus();
            trackInfo[1] = stopByte;
            trackInfo[8] = stopByte;
            -->   digitalWrite(5, LOW); //change "5" to whatever pin you have connected to the transistor
            break;

If you are using the newest code, do the same, but at lines 713 onwards:

        //CDC_PUP
          case 27:
            byteToSend = 0x00;
            SendByteToMelbus();
            trackInfo[1] = startByte;
            trackInfo[8] = startByte;
            -->   digitalWrite(5, HIGH); //change "5" to whatever pin you have connected to the transistor.
            break;

          //CDC_PDN
          case 28:
            byteToSend = 0x00;
            SendByteToMelbus();
            trackInfo[1] = stopByte;
            trackInfo[8] = stopByte;
            -->   digitalWrite(5, LOW); //change "5" to whatever pin you have connected to the transistor
            break;

Ofc remove the arrows. They are just for your attention.

@BK-Poland
Copy link
Author

And in the "void setup ()" section I have to add:
pinMode (5, OUTPUT);
digitalWrite (5, LOW);
???

@visualapproach
Copy link
Owner

Yes. Wish you luck, and let us know if it works.

@archi
Copy link

archi commented Sep 7, 2018

@visualapproach Maybe you can patch this in the repo; I think the feature doesn't do any harm if it goes unused.

@BK-Poland
Copy link
Author

Wait. First, I'll do the tests. Then I will draw a connection diagram. OK? :-)

@visualapproach
Copy link
Owner

Yeah sure. If it works for BK-Poland I'll update the repo

@visualapproach
Copy link
Owner

And thanks all for keeping this project alive!

@archi archi mentioned this issue Sep 9, 2018
@BK-Poland
Copy link
Author

The first test (older stuff code) was quite good. There is only one problem. Output D5 is in a high state also when I listen to the internal CD (HU).
When I switch to FM, BT turns off. Perfect!
When I turn on the CD-Changer, BT turns on. Perfect!
But when I turn on the Internal-HU-CD, BT also turns on. It looks like Internal-HU-CD = CD-Changer.

@visualapproach
Copy link
Owner

Ok I’ll have a look at it.

@BK-Poland
Copy link
Author

And thanks all for keeping this project alive!
Thank you for a great job!


Ok I’ll have a look at it.
Ok, I will wait.

@visualapproach
Copy link
Owner

@BK-Poland I couldn't find anything obvious. What happens when you go from CDC->FM->CD ? Does the D5 go high->low->high?

@BK-Poland
Copy link
Author

What happens when you go from CDC->FM->CD ? Does the D5 go high->low->high?

Yes, exactly.

@BK-Poland
Copy link
Author

There is one more interesting thing. When I switch CDC-> CD, the BT module will restart. So Arduino turns off D5 at 100ms or maybe max 200ms. You can see how the LED in the BT module goes out for a moment.

@visualapproach
Copy link
Owner

Can you hook up a computr via USB and log serial output?

@visualapproach
Copy link
Owner

(Don’t forget to uncomment the transmission logging in Main loop)

@BK-Poland
Copy link
Author

Can you hook up a computr via USB and log serial output?

Sure. But... How can I do this? :-)

@visualapproach
Copy link
Owner

Arduino in car, hooked up to computer via USB. Use arduino IDE to Reprogram arduino with new software (uncomment the logging part by removing the double slashes). Then turn on radio and watch the serial monitor in IDE. Switch between sources and then copy text

@BK-Poland
Copy link
Author

OK. I need 30 minutes. I'll be back... :-D

@BK-Poland
Copy link
Author

I do not know what I'm doing wrong, but the serial monitor does not work. Communication is correct, but nothing is there. Empty serial monitor window.

@visualapproach
Copy link
Owner

Need to sleep now. I get back to you. Check correct port and baudrate 115Kbps (i think)

@BK-Poland
Copy link
Author

Check correct port and baudrate 115Kbps (i think)

They are correct. I need to learn Arduino IDE :-)

@BK-Poland
Copy link
Author

I have a stupid question: Do I have to remove all double slashes from all lines with "Serial.println" and "Serial.print"?

@visualapproach
Copy link
Owner

yeah it's code related. I'll investigate. Could you send me your code by email?

@BK-Poland
Copy link
Author

/*
new:
Press cd1 or cd2 to change bluetooth volume.
Cd change is resetting track number.

By Thomas Landahl, 2017-04-25

*/

#define MELBUS_CLOCKBIT (byte)2 //Pin D2 - CLK
#define MELBUS_DATA (byte)3 //Pin D3 - Data
#define MELBUS_BUSY (byte)4 //Pin D4 - Busy
const byte prevPin = 8;
const byte nextPin = 9;
const byte upPin = 10; //volume up
const byte downPin = 11; //volume down
const byte playPin = 12;

//volatile variables used inside and outside of ISP
volatile byte melbus_ReceivedByte = 0;
volatile byte melbus_Bitposition = 7;
volatile bool byteIsRead = false;

byte byteToSend = 0; //global to avoid unnecessary overhead
unsigned long Connected = 0;

//preset parameters
byte track = 0x01; //Display show HEX value, not DEC. (A-F not "allowed")
byte cd = 0x01; //1-10 is allowed (in HEX. 0A-0F and 1A-1F is not allowed)
byte powerup_ack = 0x00;

//Base adresses.
//const byte MD_ADDR = 0x70; //internal
//const byte CD_ADDR = 0x80; //internal
//const byte TV_ADDR = 0xA8; //might be A9 during main init sequence
//const byte DAB_ADDR = 0xB8;
//const byte SAT_ADDR = 0xC0;
//const byte MDC_ADDR = 0xD8;
//const byte CDC_ADDR = 0xE8;
//const byte RESPONSE = 0x06; //add this to base adress when responding to HU
//const byte MASTER = 0x07; //add this to base adress when requesting/beeing master

//change theese definitions if you wanna emulate another device.
//My HU-650 don't accept anything but a CD-C (so far).
#define RESPONSE_ID 0xEE //ID while responding to init requests (which will use base_id)
#define MASTER_ID 0xEF //ID while requesting/beeing master
#define BASE_ID 0xE8 //ID when getting commands from HU
#define ALT_ID 0xE9 //Alternative ID when getting commands from HU

//This list can't be too long. We only have so much time between the received bytes. (approx 500 us)
const byte commands[][5] = {
{BASE_ID, 0x1E, 0xEF}, //0, Cartridge info request. Respond with 6 bytes (confirmed)
{ALT_ID, 0x1B, 0xE0, 0x01, 0x08}, //1, track info req. resp 9 bytes
{BASE_ID, 0x1B, 0x2D, 0x40, 0x01}, //2, next track.
{BASE_ID, 0x1B, 0x2D, 0x00, 0x01}, //3, prev track
{BASE_ID, 0x1A, 0x50}, //4, change cd
{BASE_ID, 0x1A, 0x50}, //5, not used
{BASE_ID, 0x19, 0x2F}, //6, power up. resp ack (0x00), 0x19 could be 0x49??
{BASE_ID, 0x19, 0x22}, //7, power down. ack (0x00), not verified
{BASE_ID, 0x19, 0x29}, //8, FFW. ack, not verified
{BASE_ID, 0x19, 0x26}, //9, FRW. ack, not verified
{BASE_ID, 0x19, 0x2E}, //10 scan mode. ack, cmd verified!
{BASE_ID, 0x19, 0x52}, //11 random mode. ack, not verified
{0x07, 0x1A, 0xEE}, //12 main init seq. wait for BASE_ID and respond with RESPONSE_ID.
{0x00, 0x00, 0x1C, 0xED}, //13 secondary init req. wait for BASE_ID and respond with RESPONSE_ID.
{0x00, 0x1C, 0xEC} //14 master req broadcast. wait for MASTER_ID and respond with MASTER_ID.
};
//keep track of the length of each command. (The two dimensional array above have fixed width (padded with 0x00))
const byte listLen = 15;
byte cmdLen[listLen] = {3, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3};

//arrays to send to HU when requested

//TRACK INFO
/*According to internet resources, HEX 10 88 01 01 80 03 00 02 22 should be a valid answer.
another source: 0x00, 0x02, 0x00, 0x01, 0x80, 0x01, 0xff, 0x60, 0x60
All comments in HEX

  1. 10, 14, 20, 24, 30, 34, 80, 84, 90, 94 => HU is OK, else error

  2. Status message
    01 = able to select cd by pushing HU-buttons but it resets to 01 after a couple of secs
    00, 10, 20, 40 = HU display: cd load cartridge (decimal numbers here??)
    22 = HU asking for status rapidly
    11 = HU display: CD cartridge empty
    44 = HU display: CD number is blinking
    81 = HU display: cd error

  3. 8 = HU display: random

  4. HU display: CD number (1-10). 0x10 shows "CD ". 0x0A (DEC 10) does not work?
    HU displays each nibble, and only values < A is valid.

  5. Unknown meaning.

  6. TRACK number

  7. Hours not displayed on HU-650

  8. Minutes not displayed on HU-650

  9. Status Power?

*/
byte trackInfo[] = {0x00, 0x02, 0x00, cd, 0x80, track, 0xC7, 0x0A, 0x02}; //9 bytes
byte startByte = 0x08; //on powerup - change trackInfo[1] & [8] to this
byte stopByte = 0x02; //same on powerdown

//CARTRIDGE INFO
//According to internet resources, HEX 00 08 01 4A 0C CC is a valid answer.
//another source: 0x00, 0x0f, 0xff, 0x4a, 0xfc, 0xff
byte cartridgeInfo[] = {0x00, 0xFC, 0xFF, 0x4A, 0xFC, 0xFF}; //6 bytes
// 0xFC = B1111 1100; first six bits for each CD in 6-CD cartridge??

//MASTER MODE INFO
byte masterInfo[] = {0xF8, 0x85, 0xE2, 0x80, 0x03, 0x00, 0x02, 0x02}; //8 bytes

void setup() {
//Disable timer0 interrupt. It's is only bogging down the system. We need speed!
TIMSK0 &= ~_BV(TOIE0);

//All lines are idle HIGH
pinMode(MELBUS_DATA, INPUT_PULLUP);
pinMode(MELBUS_CLOCKBIT, INPUT_PULLUP);
pinMode(MELBUS_BUSY, INPUT_PULLUP);
pinMode(nextPin, OUTPUT);
pinMode(prevPin, OUTPUT);
pinMode(playPin, OUTPUT);
pinMode (5, OUTPUT);
digitalWrite (5, LOW);
digitalWrite(nextPin, LOW);
digitalWrite(prevPin, LOW);
digitalWrite(playPin, LOW);

//LED indicates connected status.
pinMode(13, OUTPUT);
digitalWrite(13, LOW);

//Activate interrupt on clock pin
attachInterrupt(digitalPinToInterrupt(MELBUS_CLOCKBIT), MELBUS_CLOCK_INTERRUPT, RISING);

//Initiate serial communication to debug via serial-usb (arduino)
//For debugging purpose. Better off without it when things work.
//Serial printing take a lot of time!!
Serial.begin(115200);

//Call function that tells HU that we want to register a new device
melbusInitReq();
}

//Main loop
void loop() {
static byte byteCounter = 0; //keep track of how many bytes is sent in current command
static byte lastByte = 0; //used to copy volatile byte to register variable. See below
static byte matching[listLen]; //Keep track of every matching byte in the commands array
//static byte msgCount = 0; //inc every time busy line goes idle.
//static byte masterCount = 0;
byte melbus_log[99]; //main init sequence is 61 bytes long...
bool flag = false;
bool BUSY = PIND & (1 << MELBUS_BUSY);

Connected++;
//check BUSY line active (active low)
while (!BUSY) {
//Transmission handling here...
//debug
//PORTB |= 1 << 5;
if (byteIsRead) {
//debug
//PORTB &= ~(1 << 5);
byteIsRead = false;
lastByte = melbus_ReceivedByte; //copy volatile byte to register variable
//Well, since HU is talking to us we might call it a conversation.
Connected = 0;
melbus_log[byteCounter] = lastByte;
//Loop though every command in the array and check for matches. (No, don't go looking for matches now)
for (byte cmd = 0; cmd < listLen; cmd++) {
//check if this byte is matching
if (lastByte == commands[cmd][byteCounter]) {
matching[cmd]++;
//check if a complete command is received, and take appropriate action
if (matching[cmd] == cmdLen[cmd]) {
switch (cmd) {
//0, Cartridge info request. Respond with 6 bytes
case 0:
SendCartridgeInfo();
break;
//1, track info req. resp 9 bytes
case 1:
SendTrackInfo();
//Serial.println(" trk info sent");
break;
//2, next track.
case 2:
track++;
fixTrack();
trackInfo[5] = track;
nextTrack();
break;
//3, prev track
case 3:
track--;
fixTrack();
trackInfo[5] = track;
prevTrack();
break;
//4, change cd
case 4:
//wait for next byte to get CD number
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
switch (melbus_ReceivedByte) {
case 0x81:
cd = 1;
volumeDown(); //internal to BT-module, not BT source
track = 1;
break;
case 0x82:
cd = 2;
volumeUp(); //internal to BT-module, not BT source
track = 1;
break;
case 0x83:
cd = 3;
track = 1;
break;
case 0x84:
cd = 4;
track = 1;
break;
case 0x85:
cd = 5;
track = 1;
break;
case 0x86:
cd = 6;
track = 1;
break;
case 0x41:
cd++;
track = 1;
break;
case 0x01:
cd--;
track = 1;
break;
default:
track = 1;
break;
}
}
}
trackInfo[3] = cd;
trackInfo[5] = track;
break;
//5, not used
case 5:
break;
//6, power up. resp ack (0x00), not verified
case 6:
byteToSend = 0x00;
SendByteToMelbus();
trackInfo[1] = startByte;
trackInfo[8] = startByte;
digitalWrite(5, HIGH);
Serial.println("D5 ON");
break;
//7, power down. ack (0x00), not verified
case 7:
byteToSend = 0x00;
SendByteToMelbus();
trackInfo[1] = stopByte;
trackInfo[8] = stopByte;
digitalWrite(5, LOW);
Serial.println("D5 OFF");
break;
//8, FFW. ack, not verified
case 8:
byteToSend = 0x00;
SendByteToMelbus();
break;
//9, FRW. ack, not verified
case 9:
byteToSend = 0x00;
SendByteToMelbus();
break;
//10 scan mode.
//Used as a PLAY button here
case 10:
byteToSend = 0x00;
SendByteToMelbus();
play();
//trackInfo[0]++; //debug
break;
//11 random mode.
//Used as a PLAY button here
case 11:
byteToSend = 0x00;
SendByteToMelbus();
play();
break;
//12 main init seq. wait for BASE_ID and respond with RESPONSE_ID.
case 12:
//wait for base_id and respond with response_id
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
//debug get whole message
//byteCounter++;
//melbus_log[byteCounter] = melbus_ReceivedByte;
//end debug
if (melbus_ReceivedByte == BASE_ID) {
byteToSend = RESPONSE_ID;
SendByteToMelbus();
break;
}
}
}
break;
//13 secondary init req. wait for BASE_ID and respond with RESPONSE_ID.
case 13:
//wait for base_id and respond response_id
//digitalWrite(13, HIGH);
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
//debug get whole message
//byteCounter++;
//melbus_log[byteCounter] = melbus_ReceivedByte;
//end debug
if (melbus_ReceivedByte == BASE_ID) {
byteToSend = RESPONSE_ID;
SendByteToMelbus();
break;
}
}
}
break;
//14 master req broadcast. wait for MASTER_ID and respond with MASTER_ID. (not used in this sketch)
case 14:
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
if (melbus_ReceivedByte == MASTER_ID) {
byteToSend = MASTER_ID;
SendByteToMelbus();
//do stuff here to send message to HU, like
masterSend();
break;
}
}
}
break;
// //15
// case 15:
// byteToSend = 0x00;
// SendByteToMelbus();
// break;
// //16
// case 16:
// byteToSend = 0x00;
// SendByteToMelbus();
// break;
// //17
// case 17:
// byteToSend = 0x00;
// SendByteToMelbus();
// break;
}
break; //bail for loop. (Not meaningful to search more commands if one is already found)
} //end if command found
} //end if lastbyte matches
} //end for cmd loop
byteCounter++;
} //end if byteisread
//Update status of BUSY line, so we don't end up in an infinite while-loop.
BUSY = PIND & (1 << MELBUS_BUSY);
if (BUSY) {
flag = true; //used to execute some code only once between transmissions
}
}

//Do other stuff here if you want. MELBUS lines are free now. BUSY = IDLE (HIGH)
//Don't take too much time though, since BUSY might go active anytime, and then we'd better be ready to receive.
//Printing transmission log (incoming, before responses)
if (flag) {
for (byte b = 0; b < byteCounter; b++) {
Serial.print(melbus_log[b], HEX);
Serial.print(" ");
}
Serial.println();
}

//Reset stuff
byteCounter = 0;
melbus_Bitposition = 7;
for (byte i = 0; i < listLen; i++) {
matching[i] = 0;
}
if (Connected > 2000000) {
melbusInitReq();
Connected = 0;
}

//Incoming serial data is supposed to look like this:
//index, databyte: "3, 5"
//No error checking here since we're just hacking
// if (Serial.available() > 0) {
// int index = Serial.parseInt();
// trackInfo[index] = (byte) Serial.parseInt();
// Serial.readStringUntil('\n');
// for (byte b = 0; b < 9; b++) {
// Serial.print(trackInfo[b], HEX);
// Serial.print("-");
// }
// Serial.println();
// }

// I haven't seen any advantages from sending messages to HU.
//Therefore this section is disabled.
// if (flag) {
// if(some timed interval etc)
// reqMaster();
// }

flag = false; //don't print during next loop. Wait for new message to arrive first.
}

//Notify HU that we want to trigger the first initiate procedure to add a new device (CD-CHGR) by pulling BUSY line low for 1s
void melbusInitReq() {
//Serial.println("conn");
//Disable interrupt on INT0 quicker than: detachInterrupt(MELBUS_CLOCKBIT_INT);
EIMSK &= ~(1 << INT0);

// Wait until Busy-line goes high (not busy) before we pull BUSY low to request init
while (digitalRead(MELBUS_BUSY) == LOW) {}
delayMicroseconds(20);

pinMode(MELBUS_BUSY, OUTPUT);
digitalWrite(MELBUS_BUSY, LOW);
//timer0 is off so we have to do a trick here
for (unsigned int i = 0; i < 12000; i++) delayMicroseconds(100);

digitalWrite(MELBUS_BUSY, HIGH);
pinMode(MELBUS_BUSY, INPUT_PULLUP);
//Enable interrupt on INT0, quicker than: attachInterrupt(MELBUS_CLOCKBIT_INT, MELBUS_CLOCK_INTERRUPT, RISING);
EIMSK |= (1 << INT0);
}

//This is a function that sends a byte to the HU - (not using interrupts)
//SET byteToSend variable before calling this!!
void SendByteToMelbus() {
//Disable interrupt on INT0 quicker than: detachInterrupt(MELBUS_CLOCKBIT_INT);
EIMSK &= ~(1 << INT0);

//Convert datapin to output
//pinMode(MELBUS_DATA, OUTPUT); //To slow, use DDRD instead:
DDRD |= (1 << MELBUS_DATA);

//For each bit in the byte
for (int i = 7; i >= 0; i--)
{
while (PIND & (1 << MELBUS_CLOCKBIT)) {} //wait for low clock
//If bit [i] is "1" - make datapin high
if (byteToSend & (1 << i)) {
PORTD |= (1 << MELBUS_DATA);
}
//if bit [i] is "0" - make datapin low
else {
PORTD &= ~(1 << MELBUS_DATA);
}
while (!(PIND & (1 << MELBUS_CLOCKBIT))) {} //wait for high clock
}

//Reset datapin to high and return it to an input
//pinMode(MELBUS_DATA, INPUT_PULLUP);
PORTD |= 1 << MELBUS_DATA;
DDRD &= ~(1 << MELBUS_DATA);

//Enable interrupt on INT0, quicker than: attachInterrupt(MELBUS_CLOCKBIT_INT, MELBUS_CLOCK_INTERRUPT, RISING);
EIMSK |= (1 << INT0);
}

//Global external interrupt that triggers when clock pin goes high after it has been low for a short time => time to read datapin
void MELBUS_CLOCK_INTERRUPT() {
//Read status of Datapin and set status of current bit in recv_byte
//if (digitalRead(MELBUS_DATA) == HIGH) {
if ((PIND & (1 << MELBUS_DATA))) {
melbus_ReceivedByte |= (1 << melbus_Bitposition); //set bit nr [melbus_Bitposition] to "1"
}
else {
melbus_ReceivedByte &= ~(1 << melbus_Bitposition); //set bit nr [melbus_Bitposition] to "0"
}

//if all the bits in the byte are read:
if (melbus_Bitposition == 0) {
//set bool to true to evaluate the bytes in main loop
byteIsRead = true;

//Reset bitcount to first bit in byte
melbus_Bitposition = 7;

}
else {
//set bitnumber to address of next bit in byte
melbus_Bitposition--;
}
}

void SendTrackInfo() {
noInterrupts();
for (byte i = 0; i < 9; i++) {
byteToSend = trackInfo[i];
SendByteToMelbus();
}
interrupts();
}

void SendCartridgeInfo() {
noInterrupts();
for (byte i = 0; i < 6; i++) {
byteToSend = cartridgeInfo[i];
SendByteToMelbus();
}
interrupts();
}

void reqMaster() {
DDRD |= (1 << MELBUS_DATA); //output
PORTD &= ~(1 << MELBUS_DATA);//low
delayMicroseconds(700);
delayMicroseconds(700);
delayMicroseconds(800);
PORTD |= (1 << MELBUS_DATA);//high
DDRD &= ~(1 << MELBUS_DATA); //back to input
}

void masterSend() {
noInterrupts();
for (byte i = 0; i < 8; i++) {
byteToSend = masterInfo[i];
SendByteToMelbus();
}
interrupts();
}

void fixTrack() {
//cut out A-F in each nibble, and skip "00"
byte hn = track >> 4;
byte ln = track & 0xF;
if (ln == 0xA) {
ln = 0;
hn += 1;
}
if (ln == 0xF) {
ln = 9;
}
if (hn == 0xA) {
hn = 0;
ln = 1;
}
if ((hn == 0) && (ln == 0)) {
ln = 0x9;
hn = 0x9;
}
track = (hn << 4) + ln;
}

//Simulate button presses on the BT module. 200 ms works good. Less is not more in this case...
void nextTrack() {
digitalWrite(nextPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(nextPin, LOW);
}

void prevTrack() {
digitalWrite(prevPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(prevPin, LOW);
}

void play() {
digitalWrite(playPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(playPin, LOW);
}

void volumeDown() {
digitalWrite(downPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(downPin, LOW);

}

void volumeUp() {
digitalWrite(upPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(upPin, LOW);

}

//Happy listening, hacker!

@visualapproach
Copy link
Owner

change line 182 to

if ((matching[cmd] == cmdLen[cmd]) && (byteCounter+1 == commands[cmd][0])) {

and try again.
(It's friday night so my mental skills are degraded now ;-) but I have good hope this works)

@BK-Poland
Copy link
Author

Something is wrong. Now HU does not detect the CDC. So...
It's Friday night. Time for play ;-) We'll be back to the topic after the weekend.

@visualapproach
Copy link
Owner

if ((matching[cmd] == cmdLen[cmd]) && (byteCounter+1 ==cmdLen[cmd] )) {

@BK-Poland
Copy link
Author

It works! Perfectly! A big beer for you. Thank you!

@BK-Poland
Copy link
Author

OK. Time to sharezone my hardware. I use the MOSFET IRL540N (logic level). I use gate resistor 1Mohm. Its simple to make a new function :-)

@visualapproach
Copy link
Owner

Awesome! Cheers

@BK-Poland
Copy link
Author

Do you need me to draw my wiring diagram? If I can help, please write. You can publish my idea in the official code.

@visualapproach
Copy link
Owner

Please do! I’ll update the code also. May I ask why you are using the old code? Legacy or doesn’t the newer code work in your application? Just curious.

@BK-Poland
Copy link
Author

Why do I use the old code? It's simpler and it's enough for me. It's easier for me to analyze it. It meets all my requirements. BT works in my old Volvo. Thank you very much for that! When I was doing my BT-Volvo-Car according to your instructions and with your code it was still an old code. Maybe I will try a new code in the future. In what program do you draw your electrical diagrams?

@visualapproach
Copy link
Owner

Ok, I understand. If you are happy then no need to switch code :-)
I've used Eagle. Supposedly you can import your PCBs into Fusion360 wich is an advantage. But it is a rather complicated program for what I do. I have also peeked at easyEDA, an online PCB editor.

@BK-Poland
Copy link
Author

I remember that I had to draw a diagram. I'm working on one more improvement. I am waiting for a shipment (with some electronics parts) from China. A month or two. Please be patient. :-)

@visualapproach
Copy link
Owner

No worries. I will update the code also. Some day :-)

@BK-Poland
Copy link
Author

BK-Poland commented Oct 8, 2018

I have a problem with the hardware layer. Sometimes the BT module turns itself on. Sometimes Arduino goes crazy and I have CD Error on the HU display. Even, he sometimes switches the songs himself. It seems to me that disconnecting GND of the BT module is not a good solution. If I do a properly working layout, I will show the diagram. Please be patient. :-D

@BK-Poland
Copy link
Author

I found the fault. The Arduino Nano stabilizer on the PCB was damaged. The damage was revealed only after a few minutes of work. But sometimes only after an hour. I used a step-down converter and Arduino has 5V power supply.

I have one more request for help: Is it possible to do so that Arduino does not turn off BT when shooting the starter?

@BK-Poland
Copy link
Author

I will write in words how this code could work in "case 7":
After receiving the OFF signal from HU, wait 5 seconds. If the ON signal comes in at this time, do not do anything. If after 5 seconds there is no ON signal then DigitalWrite (5, OFF).

@visualapproach
Copy link
Owner

It would be possible with a local powersupply that lasts for the duration of you shooting the starter. Like a battery or capacitor.

@BK-Poland
Copy link
Author

Yes I know. I've already done direct battery power. Arduino and BT have power supply always.
When I listen music in parking, for example Spotify and when I start the engine, it disconnects the phone and BT, and then I have to wait until the phone connects to BT and then I need to press PLAY. I would like to avoid it. Will you help me? :-)

@visualapproach
Copy link
Owner

Try this:

//Main loop
void loop() {
static long unsigned int mytimer = 0; //add this line
static bool mytimer_enabled = false; //add this line
...

          //6, power up. resp ack (0x00), not verified
          case 6:
            byteToSend = 0x00;
            SendByteToMelbus();
            trackInfo[1] = startByte;
            trackInfo[8] = startByte;
            digitalWrite(5, HIGH);
            Serial.println("D5 ON");
            mytimer_enabled = false;
            mytimer = 0;
            break;
          //7, power down. ack (0x00), not verified
          case 7:
            byteToSend = 0x00;
            SendByteToMelbus();
            trackInfo[1] = stopByte;
            trackInfo[8] = stopByte;
            mytimer_enabled = true;
            break;

...

if (mytimer_enabled) {
mytimer++;
if (mytimer == 500000) { //edit this value to get timing right. No idea how big it needs to be.
shutoffBT();
mytimer = 0;
mytimer_enabled = false;
}
}
}
//end of loop()

//add this function:
void shutoffBT() {
digitalWrite(5, LOW);
Serial.println("D5 OFF");
}

@visualapproach
Copy link
Owner

any success?

@BK-Poland
Copy link
Author

BK-Poland commented Feb 26, 2019

I am sorry that I have not written for so long. I had a lot of work and not enough free time.

Unfortunately it does not work. Normally turns BT on and off without delay.
Where should I insert "if (mytimer_enabled) ...."?
Are you sure that 5 seconds is 500000? If in milliseconds it should probably be 5000?
Currently I have this code:

@BK-Poland
Copy link
Author

/*
new:
Press cd1 or cd2 to change bluetooth volume.
Cd change is resetting track number.

By Thomas Landahl, 2017-04-25

*/

#define MELBUS_CLOCKBIT (byte)2 //Pin D2 - CLK
#define MELBUS_DATA (byte)3 //Pin D3 - Data
#define MELBUS_BUSY (byte)4 //Pin D4 - Busy
const byte prevPin = 9;
const byte nextPin = 8;
const byte upPin = 10; //volume up
const byte downPin = 11; //volume down
const byte playPin = 12;

//volatile variables used inside and outside of ISP
volatile byte melbus_ReceivedByte = 0;
volatile byte melbus_Bitposition = 7;
volatile bool byteIsRead = false;

byte byteToSend = 0; //global to avoid unnecessary overhead
unsigned long Connected = 0;

//preset parameters
byte track = 0x01; //Display show HEX value, not DEC. (A-F not "allowed")
byte cd = 0x01; //1-10 is allowed (in HEX. 0A-0F and 1A-1F is not allowed)
byte powerup_ack = 0x00;

//Base adresses.
//const byte MD_ADDR = 0x70; //internal
//const byte CD_ADDR = 0x80; //internal
//const byte TV_ADDR = 0xA8; //might be A9 during main init sequence
//const byte DAB_ADDR = 0xB8;
//const byte SAT_ADDR = 0xC0;
//const byte MDC_ADDR = 0xD8;
//const byte CDC_ADDR = 0xE8;
//const byte RESPONSE = 0x06; //add this to base adress when responding to HU
//const byte MASTER = 0x07; //add this to base adress when requesting/beeing master

//change theese definitions if you wanna emulate another device.
//My HU-650 don't accept anything but a CD-C (so far).
#define RESPONSE_ID 0xEE //ID while responding to init requests (which will use base_id)
#define MASTER_ID 0xEF //ID while requesting/beeing master
#define BASE_ID 0xE8 //ID when getting commands from HU
#define ALT_ID 0xE9 //Alternative ID when getting commands from HU

//This list can't be too long. We only have so much time between the received bytes. (approx 500 us)
const byte commands[][5] = {
{BASE_ID, 0x1E, 0xEF}, //0, Cartridge info request. Respond with 6 bytes (confirmed)
{ALT_ID, 0x1B, 0xE0, 0x01, 0x08}, //1, track info req. resp 9 bytes
{BASE_ID, 0x1B, 0x2D, 0x40, 0x01}, //2, next track.
{BASE_ID, 0x1B, 0x2D, 0x00, 0x01}, //3, prev track
{BASE_ID, 0x1A, 0x50}, //4, change cd
{BASE_ID, 0x1A, 0x50}, //5, not used
{BASE_ID, 0x19, 0x2F}, //6, power up. resp ack (0x00), 0x19 could be 0x49??
{BASE_ID, 0x19, 0x22}, //7, power down. ack (0x00), not verified
{BASE_ID, 0x19, 0x29}, //8, FFW. ack, not verified
{BASE_ID, 0x19, 0x26}, //9, FRW. ack, not verified
{BASE_ID, 0x19, 0x2E}, //10 scan mode. ack, cmd verified!
{BASE_ID, 0x19, 0x52}, //11 random mode. ack, not verified
{0x07, 0x1A, 0xEE}, //12 main init seq. wait for BASE_ID and respond with RESPONSE_ID.
{0x00, 0x00, 0x1C, 0xED}, //13 secondary init req. wait for BASE_ID and respond with RESPONSE_ID.
{0x00, 0x1C, 0xEC} //14 master req broadcast. wait for MASTER_ID and respond with MASTER_ID.
};
//keep track of the length of each command. (The two dimensional array above have fixed width (padded with 0x00))
const byte listLen = 15;
byte cmdLen[listLen] = {3, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3};

//arrays to send to HU when requested

//TRACK INFO
/*According to internet resources, HEX 10 88 01 01 80 03 00 02 22 should be a valid answer.
another source: 0x00, 0x02, 0x00, 0x01, 0x80, 0x01, 0xff, 0x60, 0x60
All comments in HEX

  1. 10, 14, 20, 24, 30, 34, 80, 84, 90, 94 => HU is OK, else error

  2. Status message
    01 = able to select cd by pushing HU-buttons but it resets to 01 after a couple of secs
    00, 10, 20, 40 = HU display: cd load cartridge (decimal numbers here??)
    22 = HU asking for status rapidly
    11 = HU display: CD cartridge empty
    44 = HU display: CD number is blinking
    81 = HU display: cd error

  3. 8 = HU display: random

  4. HU display: CD number (1-10). 0x10 shows "CD ". 0x0A (DEC 10) does not work?
    HU displays each nibble, and only values < A is valid.

  5. Unknown meaning.

  6. TRACK number

  7. Hours not displayed on HU-650

  8. Minutes not displayed on HU-650

  9. Status Power?

*/
byte trackInfo[] = {0x00, 0x02, 0x00, cd, 0x80, track, 0xC7, 0x0A, 0x02}; //9 bytes
byte startByte = 0x08; //on powerup - change trackInfo[1] & [8] to this
byte stopByte = 0x02; //same on powerdown

//CARTRIDGE INFO
//According to internet resources, HEX 00 08 01 4A 0C CC is a valid answer.
//another source: 0x00, 0x0f, 0xff, 0x4a, 0xfc, 0xff
byte cartridgeInfo[] = {0x00, 0xFC, 0xFF, 0x4A, 0xFC, 0xFF}; //6 bytes
// 0xFC = B1111 1100; first six bits for each CD in 6-CD cartridge??

//MASTER MODE INFO
byte masterInfo[] = {0xF8, 0x85, 0xE2, 0x80, 0x03, 0x00, 0x02, 0x02}; //8 bytes

void setup() {
//Disable timer0 interrupt. It's is only bogging down the system. We need speed!
TIMSK0 &= ~_BV(TOIE0);

//All lines are idle HIGH
pinMode(MELBUS_DATA, INPUT_PULLUP);
pinMode(MELBUS_CLOCKBIT, INPUT_PULLUP);
pinMode(MELBUS_BUSY, INPUT_PULLUP);
pinMode(nextPin, OUTPUT);
pinMode(prevPin, OUTPUT);
pinMode(playPin, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(6, HIGH);
digitalWrite(nextPin, LOW);
digitalWrite(prevPin, LOW);
digitalWrite(playPin, LOW);

//LED indicates connected status.
pinMode(13, OUTPUT);
digitalWrite(13, LOW);

//Activate interrupt on clock pin
attachInterrupt(digitalPinToInterrupt(MELBUS_CLOCKBIT), MELBUS_CLOCK_INTERRUPT, RISING);

//Initiate serial communication to debug via serial-usb (arduino)
//For debugging purpose. Better off without it when things work.
//Serial printing take a lot of time!!
//Serial.begin(115200);

//Call function that tells HU that we want to register a new device
melbusInitReq();
}

//Main loop
void loop() {
static byte byteCounter = 0; //keep track of how many bytes is sent in current command
static byte lastByte = 0; //used to copy volatile byte to register variable. See below
static byte matching[listLen]; //Keep track of every matching byte in the commands array
static long unsigned int mytimer = 0; //add this line
static bool mytimer_enabled = false; //add this line
//static byte msgCount = 0; //inc every time busy line goes idle.
//static byte masterCount = 0;
byte melbus_log[99]; //main init sequence is 61 bytes long...
bool flag = false;
bool BUSY = PIND & (1 << MELBUS_BUSY);

Connected++;
//check BUSY line active (active low)
while (!BUSY) {
//Transmission handling here...
//debug
//PORTB |= 1 << 5;
if (byteIsRead) {
//debug
//PORTB &= ~(1 << 5);
byteIsRead = false;
lastByte = melbus_ReceivedByte; //copy volatile byte to register variable
//Well, since HU is talking to us we might call it a conversation.
Connected = 0;
melbus_log[byteCounter] = lastByte;
//Loop though every command in the array and check for matches. (No, don't go looking for matches now)
for (byte cmd = 0; cmd < listLen; cmd++) {
//check if this byte is matching
if (lastByte == commands[cmd][byteCounter]) {
matching[cmd]++;
//check if a complete command is received, and take appropriate action
if ((matching[cmd] == cmdLen[cmd]) && (byteCounter+1 ==cmdLen[cmd] )) {
switch (cmd) {
//0, Cartridge info request. Respond with 6 bytes
case 0:
SendCartridgeInfo();
break;
//1, track info req. resp 9 bytes
case 1:
SendTrackInfo();
//Serial.println(" trk info sent");
break;
//2, next track.
case 2:
track++;
fixTrack();
trackInfo[5] = track;
nextTrack();
break;
//3, prev track
case 3:
track--;
fixTrack();
trackInfo[5] = track;
prevTrack();
break;
//4, change cd
case 4:
//wait for next byte to get CD number
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
switch (melbus_ReceivedByte) {
case 0x81:
cd = 1;
volumeDown(); //internal to BT-module, not BT source
track = 1;
break;
case 0x82:
cd = 2;
volumeUp(); //internal to BT-module, not BT source
track = 1;
break;
case 0x83:
cd = 3;
track = 1;
break;
case 0x84:
cd = 4;
track = 1;
break;
case 0x85:
cd = 5;
track = 1;
break;
case 0x86:
cd = 6;
track = 1;
break;
case 0x41:
cd++;
track = 1;
break;
case 0x01:
cd--;
track = 1;
break;
default:
track = 1;
break;
}
}
}
trackInfo[3] = cd;
trackInfo[5] = track;
break;
//5, not used
case 5:
break;
//6, power up. resp ack (0x00), not verified
case 6:
byteToSend = 0x00;
SendByteToMelbus();
trackInfo[1] = startByte;
trackInfo[8] = startByte;
digitalWrite(6, LOW);
//Serial.println("D6 ON");
mytimer_enabled = false;
mytimer = 0;
break;
//7, power down. ack (0x00), not verified
case 7:
byteToSend = 0x00;
SendByteToMelbus();
trackInfo[1] = stopByte;
trackInfo[8] = stopByte;
digitalWrite(6, HIGH);
//Serial.println("D6 OFF");
mytimer_enabled = true;
break;
//8, FFW. ack, not verified
case 8:
byteToSend = 0x00;
SendByteToMelbus();
break;
//9, FRW. ack, not verified
case 9:
byteToSend = 0x00;
SendByteToMelbus();
break;
//10 scan mode.
//Used as a PLAY button here
case 10:
byteToSend = 0x00;
SendByteToMelbus();
play();
//trackInfo[0]++; //debug
break;
//11 random mode.
//Used as a PLAY button here
case 11:
byteToSend = 0x00;
SendByteToMelbus();
play();
break;
//12 main init seq. wait for BASE_ID and respond with RESPONSE_ID.
case 12:
//wait for base_id and respond with response_id
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
//debug get whole message
//byteCounter++;
//melbus_log[byteCounter] = melbus_ReceivedByte;
//end debug
if (melbus_ReceivedByte == BASE_ID) {
byteToSend = RESPONSE_ID;
SendByteToMelbus();
break;
}
}
}
break;
//13 secondary init req. wait for BASE_ID and respond with RESPONSE_ID.
case 13:
//wait for base_id and respond response_id
//digitalWrite(13, HIGH);
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
//debug get whole message
//byteCounter++;
//melbus_log[byteCounter] = melbus_ReceivedByte;
//end debug
if (melbus_ReceivedByte == BASE_ID) {
byteToSend = RESPONSE_ID;
SendByteToMelbus();
break;
}
}
}
break;
//14 master req broadcast. wait for MASTER_ID and respond with MASTER_ID. (not used in this sketch)
case 14:
while (!(PIND & (1 << MELBUS_BUSY))) {
if (byteIsRead) {
byteIsRead = false;
if (melbus_ReceivedByte == MASTER_ID) {
byteToSend = MASTER_ID;
SendByteToMelbus();
//do stuff here to send message to HU, like
masterSend();
break;
}
}
}
break;
// //15
// case 15:
// byteToSend = 0x00;
// SendByteToMelbus();
// break;
// //16
// case 16:
// byteToSend = 0x00;
// SendByteToMelbus();
// break;
// //17
// case 17:
// byteToSend = 0x00;
// SendByteToMelbus();
// break;
}
break; //bail for loop. (Not meaningful to search more commands if one is already found)
} //end if command found
} //end if lastbyte matches
} //end for cmd loop
byteCounter++;
} //end if byteisread
//Update status of BUSY line, so we don't end up in an infinite while-loop.
BUSY = PIND & (1 << MELBUS_BUSY);
if (BUSY) {
flag = true; //used to execute some code only once between transmissions
}
}

if (mytimer_enabled) {
mytimer++;
if (mytimer == 500000) { //edit this value to get timing right. No idea how big it needs to be.
shutoffBT();
mytimer = 0;
mytimer_enabled = false;
}
}

//Do other stuff here if you want. MELBUS lines are free now. BUSY = IDLE (HIGH)
//Don't take too much time though, since BUSY might go active anytime, and then we'd better be ready to receive.
//Printing transmission log (incoming, before responses)
// if (flag) {
// for (byte b = 0; b < byteCounter; b++) {
// Serial.print(melbus_log[b], HEX);
// Serial.print(" ");
// }
// Serial.println();
// }

//Reset stuff
byteCounter = 0;
melbus_Bitposition = 7;
for (byte i = 0; i < listLen; i++) {
matching[i] = 0;
}
if (Connected > 2000000) {
melbusInitReq();
Connected = 0;
}

//Incoming serial data is supposed to look like this:
//index, databyte: "3, 5"
//No error checking here since we're just hacking
// if (Serial.available() > 0) {
// int index = Serial.parseInt();
// trackInfo[index] = (byte) Serial.parseInt();
// Serial.readStringUntil('\n');
// for (byte b = 0; b < 9; b++) {
// Serial.print(trackInfo[b], HEX);
// Serial.print("-");
// }
// Serial.println();
// }

// I haven't seen any advantages from sending messages to HU.
//Therefore this section is disabled.
// if (flag) {
// if(some timed interval etc)
// reqMaster();
// }

flag = false; //don't print during next loop. Wait for new message to arrive first.
}

//Notify HU that we want to trigger the first initiate procedure to add a new device (CD-CHGR) by pulling BUSY line low for 1s
void melbusInitReq() {
//Serial.println("conn");
//Disable interrupt on INT0 quicker than: detachInterrupt(MELBUS_CLOCKBIT_INT);
EIMSK &= ~(1 << INT0);

// Wait until Busy-line goes high (not busy) before we pull BUSY low to request init
while (digitalRead(MELBUS_BUSY) == LOW) {}
delayMicroseconds(20);

pinMode(MELBUS_BUSY, OUTPUT);
digitalWrite(MELBUS_BUSY, LOW);
//timer0 is off so we have to do a trick here
for (unsigned int i = 0; i < 12000; i++) delayMicroseconds(100);

digitalWrite(MELBUS_BUSY, HIGH);
pinMode(MELBUS_BUSY, INPUT_PULLUP);
//Enable interrupt on INT0, quicker than: attachInterrupt(MELBUS_CLOCKBIT_INT, MELBUS_CLOCK_INTERRUPT, RISING);
EIMSK |= (1 << INT0);
}

//This is a function that sends a byte to the HU - (not using interrupts)
//SET byteToSend variable before calling this!!
void SendByteToMelbus() {
//Disable interrupt on INT0 quicker than: detachInterrupt(MELBUS_CLOCKBIT_INT);
EIMSK &= ~(1 << INT0);

//Convert datapin to output
//pinMode(MELBUS_DATA, OUTPUT); //To slow, use DDRD instead:
DDRD |= (1 << MELBUS_DATA);

//For each bit in the byte
for (int i = 7; i >= 0; i--)
{
while (PIND & (1 << MELBUS_CLOCKBIT)) {} //wait for low clock
//If bit [i] is "1" - make datapin high
if (byteToSend & (1 << i)) {
PORTD |= (1 << MELBUS_DATA);
}
//if bit [i] is "0" - make datapin low
else {
PORTD &= ~(1 << MELBUS_DATA);
}
while (!(PIND & (1 << MELBUS_CLOCKBIT))) {} //wait for high clock
}

//Reset datapin to high and return it to an input
//pinMode(MELBUS_DATA, INPUT_PULLUP);
PORTD |= 1 << MELBUS_DATA;
DDRD &= ~(1 << MELBUS_DATA);

//Enable interrupt on INT0, quicker than: attachInterrupt(MELBUS_CLOCKBIT_INT, MELBUS_CLOCK_INTERRUPT, RISING);
EIMSK |= (1 << INT0);
}

//Global external interrupt that triggers when clock pin goes high after it has been low for a short time => time to read datapin
void MELBUS_CLOCK_INTERRUPT() {
//Read status of Datapin and set status of current bit in recv_byte
//if (digitalRead(MELBUS_DATA) == HIGH) {
if ((PIND & (1 << MELBUS_DATA))) {
melbus_ReceivedByte |= (1 << melbus_Bitposition); //set bit nr [melbus_Bitposition] to "1"
}
else {
melbus_ReceivedByte &= ~(1 << melbus_Bitposition); //set bit nr [melbus_Bitposition] to "0"
}

//if all the bits in the byte are read:
if (melbus_Bitposition == 0) {
//set bool to true to evaluate the bytes in main loop
byteIsRead = true;

//Reset bitcount to first bit in byte
melbus_Bitposition = 7;

}
else {
//set bitnumber to address of next bit in byte
melbus_Bitposition--;
}
}

void SendTrackInfo() {
noInterrupts();
for (byte i = 0; i < 9; i++) {
byteToSend = trackInfo[i];
SendByteToMelbus();
}
interrupts();
}

void SendCartridgeInfo() {
noInterrupts();
for (byte i = 0; i < 6; i++) {
byteToSend = cartridgeInfo[i];
SendByteToMelbus();
}
interrupts();
}

void reqMaster() {
DDRD |= (1 << MELBUS_DATA); //output
PORTD &= ~(1 << MELBUS_DATA);//low
delayMicroseconds(700);
delayMicroseconds(700);
delayMicroseconds(800);
PORTD |= (1 << MELBUS_DATA);//high
DDRD &= ~(1 << MELBUS_DATA); //back to input
}

void masterSend() {
noInterrupts();
for (byte i = 0; i < 8; i++) {
byteToSend = masterInfo[i];
SendByteToMelbus();
}
interrupts();
}

void fixTrack() {
//cut out A-F in each nibble, and skip "00"
byte hn = track >> 4;
byte ln = track & 0xF;
if (ln == 0xA) {
ln = 0;
hn += 1;
}
if (ln == 0xF) {
ln = 9;
}
if (hn == 0xA) {
hn = 0;
ln = 1;
}
if ((hn == 0) && (ln == 0)) {
ln = 0x9;
hn = 0x9;
}
track = (hn << 4) + ln;
}

//Simulate button presses on the BT module. 200 ms works good. Less is not more in this case...
void nextTrack() {
digitalWrite(nextPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(nextPin, LOW);
}

void prevTrack() {
digitalWrite(prevPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(prevPin, LOW);
}

void play() {
digitalWrite(playPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(playPin, LOW);
}

void volumeDown() {
digitalWrite(downPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(downPin, LOW);

}

void volumeUp() {
digitalWrite(upPin, HIGH);
for (byte i = 0; i < 200; i++)
delayMicroseconds(1000);
digitalWrite(upPin, LOW);

}

void shutoffBT() {
digitalWrite(5, LOW);
Serial.println("D5 OFF");
}
//Happy listening, hacker!

@visualapproach
Copy link
Owner

This line: static long unsigned int mytimer = 0;
should be static unsigned long mytimer = 0;
(my bad)
You have mixed D5 and D6, and HIGH/LOW logic. Assuming D6 is controlling your mosfet, and I will write ON/OFF instead of HIGH/LOW. Depending on your circuit you need to replace with the proper one.
Case 6: change D6 to ON (HIGH or LOW)
Case 7: remove the line "digitalWrite(6...". You wanna wait before doing that.
Lastly: in the shutoffBT() - D6 instead of D5 and HIGH/LOW should be OFF

Are you sure that 5 seconds is 500000? If in milliseconds it should probably be 5000?

I'm sure it is not 5 s. It's not a timer per se, it's a counter. It would be alot easier to time things if timers where on, but they might interfere with communication. As I commented in the code, you need to adjust the value yourself. If it takes 20 s to count to 500000 then you try 125000.

@BK-Poland
Copy link
Author

It works! Exactly as I wanted. Thank you! :-)
I changed D5 to D6 because I probably damaged D5. I also changed the high / low logic, because now I control the relay module. No MOSFET.
Thank you very much!

@visualapproach
Copy link
Owner

You’re welcome

@BK-Poland
Copy link
Author

What kind of program did you use to draw the scheme of your project?

@visualapproach
Copy link
Owner

Eagle

@hagurel
Copy link

hagurel commented Mar 15, 2019

hepinizi tebrik ederim

@visualapproach
Copy link
Owner

Tack ska du ha

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants