Simulated the CD changer of a Saab to implement a bluetooth connection to the car stereo. Control of playback device (phone) with steering wheel buttons. Needs a RN52 bluetooth transciever and a CAN transiever. So far only audio playback and control via steering wheel buttons implemented. Hands free calling planned.
RN52.cpp
- Committer:
- petter
- Date:
- 2016-01-31
- Revision:
- 14:3f4098e94c29
- Parent:
- 13:968af0520530
- Child:
- 15:82c3cc87bd02
File content as of revision 14:3f4098e94c29:
#include "RN52.h" #include "mbed.h" // RN52 action command definitions #define PLAYPAUSE "AP\r" #define NEXTTRACK "AT+\r" #define PREVTRACK "AT-\r" #define CONNECT "B\r" #define DISCONNECT "@,1\r" #define REBOOT "R,1\r" #define VOLUMEUP "AV+\r" #define MAXVOLUME "SS,0F\r" #define GETSTATUS "Q\r" #define ASSISTANT "P\r" #define CALLER_ID "T\r" #define TRACK_METADATA "AD\r" #define RESPONSE_TIMEOUT 30 //ms Serial serial(p13, p14); // tx, rx DigitalIn event_pin(p20); DigitalOut enable_pin(p5); Timer responsetime; char temp_response[255]; void RN52::init(){ enable(); serial.baud(115200); printf("Serial baudrate set\r\n"); //make sure event pin is pulled low if(event_pin == 0) { serial.printf(GETSTATUS); capture_response(temp_response); } } void RN52::enable(){ enable_pin = 1; } void RN52::disable(){ enable_pin = 0; serial.printf(REBOOT); capture_response(temp_response); } bool RN52::check_event(RN52_RESULT * result){ clear_serial(); if(event_pin == 0) { clear_result(result); get_status(result); switch (result->event) { case RN52_CALLER_ID_EVENT: get_caller_id(result); break; case RN52_TRACK_CHANGE_EVENT: get_track_metadata(result); break; } return 1; } return 0; } bool RN52::connect(){ serial.printf(CONNECT); return capture_response(temp_response); } bool RN52::disconnect(){ serial.printf(DISCONNECT); return capture_response(temp_response); } bool RN52::next_track(){ serial.printf(NEXTTRACK); return capture_response(temp_response); } bool RN52::prev_track(){ serial.printf(PREVTRACK); return capture_response(temp_response); } bool RN52::toggle_play(){ serial.printf(PLAYPAUSE); return capture_response(temp_response); } bool RN52::maxvolume(){ serial.printf(MAXVOLUME); return capture_response(temp_response); } bool RN52::get_status(RN52_RESULT * result){ serial.printf(GETSTATUS); capture_response(result->response); int response_value = strtoul(result->response, NULL, 16); result->media_connected = (response_value & (1 << 10)) >> 10; //byte 0, bit 2 result->phone_connected = (response_value & (1 << 11)) >> 11; //byte 0, bit 3 result->connection = (RN52_CONNECTION)(response_value & 0x0F); //byte 1, bits 0-3 switch (response_value & 0x3000) { case 0x1000: //byte 0, bit 4 result->event = RN52_CALLER_ID_EVENT; break; case 0x2000: //byte 0, bit 5 result->event = RN52_TRACK_CHANGE_EVENT; break; default: result->event = RN52_OTHER_EVENT; break; } return 1; } bool RN52::get_caller_id(RN52_RESULT * result){ serial.printf(CALLER_ID); capture_response(result->response); //parse the response return 1; } bool RN52::get_track_metadata(RN52_RESULT * result){ serial.printf(TRACK_METADATA); if(capture_response(result->response)) {//AOK while(result->response[3] != 'e') { //time(ms) - always the last one capture_response(result->response); switch (result->response[3]) { case 'l': //Title copy_response(result->response, result->title, 6); break; case 'i': //Artist copy_response(result->response, result->artist, 7); break; case 'u': //Album copy_response(result->response, result->album, 6); break; case 'r': //Genre copy_response(result->response, result->genre, 6); break; case 'c': //TrackNumber or TrackCount { char number_string[5]; if(result->response[5] == 'N') { //TrackNumber copy_response(result->response, number_string, 12); result->track_number = strtoul(number_string, NULL, 10); } else { //TrackCount copy_response(result->response, number_string, 11); result->track_count = strtoul(number_string, NULL, 10); } } break; case 'e': //time(ms) - always the last one { char duration_string[10]; copy_response(result->response, duration_string, 9); result->duration = strtoul(duration_string, NULL, 10); } break; } } clear_serial(); } return 1; } bool RN52::capture_response(char * str){ responsetime.reset(); responsetime.start(); char c = ' '; char n = 0; while(c != '\n') { if(serial.readable()) { c = serial.getc(); str[n] = c; n++; } else if(responsetime.read_ms() > RESPONSE_TIMEOUT) { clear_serial(); printf("timeout occured\r\n last response: %s\r\n", str); return 0; } } str[n-2] = '\0'; //terminate string before \r\n return (str[0] == 'A'); } void RN52::clear_serial(){ while(serial.readable()) { serial.getc(); } } void RN52::copy_response(char * source, char * destination, char offset){ int n = 0; while(source[n+offset+1] != '\0') { //remove carraige return in the end destination[n] = source[n+offset]; n++; } destination[n] = '\0'; //end string where carriage was } void RN52::clear_result(RN52_RESULT * result) { result->event = RN52_NO_EVENT; result->media_connected = 0; result->phone_connected = 0; result->connection = RN52_NOT_SET; result->title[0] = '\0'; result->artist[0] = '\0'; result->album[0] = '\0'; result->genre[0] = '\0'; result->duration = 0; result->track_number = 1; result->track_count = 1; result->response[0] = '\0'; }