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.

Dependencies:   mbed

Committer:
petter
Date:
Fri Mar 18 20:58:36 2016 +0000
Revision:
16:7bb8b161e00b
Parent:
15:82c3cc87bd02
Added can.monitor in a trial to get the sleep mode working

Who changed what in which revision?

UserRevisionLine numberNew contents of line
petter 0:6cf6e566c0da 1 #include "RN52.h"
petter 0:6cf6e566c0da 2 #include "mbed.h"
petter 0:6cf6e566c0da 3
petter 0:6cf6e566c0da 4 // RN52 action command definitions
petter 0:6cf6e566c0da 5 #define PLAYPAUSE "AP\r"
petter 0:6cf6e566c0da 6 #define NEXTTRACK "AT+\r"
petter 0:6cf6e566c0da 7 #define PREVTRACK "AT-\r"
petter 0:6cf6e566c0da 8 #define CONNECT "B\r"
petter 0:6cf6e566c0da 9 #define DISCONNECT "@,1\r"
petter 0:6cf6e566c0da 10 #define REBOOT "R,1\r"
petter 0:6cf6e566c0da 11 #define VOLUMEUP "AV+\r"
petter 0:6cf6e566c0da 12 #define MAXVOLUME "SS,0F\r"
petter 0:6cf6e566c0da 13 #define GETSTATUS "Q\r"
petter 0:6cf6e566c0da 14 #define ASSISTANT "P\r"
petter 0:6cf6e566c0da 15 #define CALLER_ID "T\r"
petter 0:6cf6e566c0da 16 #define TRACK_METADATA "AD\r"
petter 0:6cf6e566c0da 17
petter 15:82c3cc87bd02 18 #define RESPONSE_TIMEOUT 20 //ms
petter 16:7bb8b161e00b 19 #define METADATA_RESPONSE_TIMEOUT 100 //ms
petter 0:6cf6e566c0da 20
petter 0:6cf6e566c0da 21 Serial serial(p13, p14); // tx, rx
petter 0:6cf6e566c0da 22 DigitalIn event_pin(p20);
petter 13:968af0520530 23 DigitalOut enable_pin(p5);
petter 11:74844f6ca8cf 24 Timer responsetime;
petter 16:7bb8b161e00b 25 Timer metadata_responsetime;
petter 16:7bb8b161e00b 26
petter 14:3f4098e94c29 27 char temp_response[255];
petter 11:74844f6ca8cf 28
petter 0:6cf6e566c0da 29
petter 0:6cf6e566c0da 30 void RN52::init(){
petter 0:6cf6e566c0da 31 serial.baud(115200);
petter 0:6cf6e566c0da 32 printf("Serial baudrate set\r\n");
petter 15:82c3cc87bd02 33 enable();
petter 0:6cf6e566c0da 34 }
petter 0:6cf6e566c0da 35
petter 13:968af0520530 36 void RN52::enable(){
petter 13:968af0520530 37 enable_pin = 1;
petter 13:968af0520530 38 }
petter 13:968af0520530 39
petter 13:968af0520530 40 void RN52::disable(){
petter 13:968af0520530 41 enable_pin = 0;
petter 14:3f4098e94c29 42 serial.printf(REBOOT);
petter 14:3f4098e94c29 43 capture_response(temp_response);
petter 13:968af0520530 44 }
petter 13:968af0520530 45
petter 5:8e468fef2754 46 bool RN52::check_event(RN52_RESULT * result){
petter 6:c454f88524d6 47 clear_serial();
petter 15:82c3cc87bd02 48 if((enable_pin == 1) && (event_pin == 0)) {
petter 7:2df2c6e8c0df 49 clear_result(result);
petter 8:beb6c399490a 50 get_status(result);
petter 5:8e468fef2754 51 switch (result->event) {
petter 4:3041a571b7a7 52 case RN52_CALLER_ID_EVENT:
petter 8:beb6c399490a 53 get_caller_id(result);
petter 4:3041a571b7a7 54 break;
petter 4:3041a571b7a7 55 case RN52_TRACK_CHANGE_EVENT:
petter 8:beb6c399490a 56 get_track_metadata(result);
petter 4:3041a571b7a7 57 break;
petter 16:7bb8b161e00b 58 case RN52_OTHER_EVENT:
petter 16:7bb8b161e00b 59 if(result->connection == RN52_AUDIO_STREAMING) {
petter 16:7bb8b161e00b 60 get_track_metadata(result);
petter 16:7bb8b161e00b 61 }
petter 16:7bb8b161e00b 62 break;
petter 4:3041a571b7a7 63 }
petter 4:3041a571b7a7 64 return 1;
petter 0:6cf6e566c0da 65 }
petter 0:6cf6e566c0da 66 return 0;
petter 0:6cf6e566c0da 67 }
petter 0:6cf6e566c0da 68
petter 5:8e468fef2754 69 bool RN52::connect(){
petter 5:8e468fef2754 70 serial.printf(CONNECT);
petter 14:3f4098e94c29 71 return capture_response(temp_response);
petter 5:8e468fef2754 72 }
petter 0:6cf6e566c0da 73
petter 5:8e468fef2754 74 bool RN52::disconnect(){
petter 5:8e468fef2754 75 serial.printf(DISCONNECT);
petter 14:3f4098e94c29 76 return capture_response(temp_response);
petter 5:8e468fef2754 77 }
petter 5:8e468fef2754 78
petter 5:8e468fef2754 79 bool RN52::next_track(){
petter 5:8e468fef2754 80 serial.printf(NEXTTRACK);
petter 14:3f4098e94c29 81 return capture_response(temp_response);
petter 5:8e468fef2754 82 }
petter 5:8e468fef2754 83
petter 5:8e468fef2754 84 bool RN52::prev_track(){
petter 5:8e468fef2754 85 serial.printf(PREVTRACK);
petter 14:3f4098e94c29 86 return capture_response(temp_response);
petter 5:8e468fef2754 87 }
petter 5:8e468fef2754 88
petter 5:8e468fef2754 89 bool RN52::toggle_play(){
petter 5:8e468fef2754 90 serial.printf(PLAYPAUSE);
petter 14:3f4098e94c29 91 return capture_response(temp_response);
petter 5:8e468fef2754 92 }
petter 5:8e468fef2754 93
petter 5:8e468fef2754 94 bool RN52::maxvolume(){
petter 6:c454f88524d6 95 serial.printf(MAXVOLUME);
petter 14:3f4098e94c29 96 return capture_response(temp_response);
petter 0:6cf6e566c0da 97 }
petter 0:6cf6e566c0da 98
petter 8:beb6c399490a 99 bool RN52::get_status(RN52_RESULT * result){
petter 8:beb6c399490a 100 serial.printf(GETSTATUS);
petter 8:beb6c399490a 101 capture_response(result->response);
petter 8:beb6c399490a 102 int response_value = strtoul(result->response, NULL, 16);
petter 8:beb6c399490a 103 result->media_connected = (response_value & (1 << 10)) >> 10; //byte 0, bit 2
petter 8:beb6c399490a 104 result->phone_connected = (response_value & (1 << 11)) >> 11; //byte 0, bit 3
petter 8:beb6c399490a 105 result->connection = (RN52_CONNECTION)(response_value & 0x0F); //byte 1, bits 0-3
petter 8:beb6c399490a 106 switch (response_value & 0x3000) {
petter 8:beb6c399490a 107 case 0x1000: //byte 0, bit 4
petter 8:beb6c399490a 108 result->event = RN52_CALLER_ID_EVENT;
petter 0:6cf6e566c0da 109 break;
petter 8:beb6c399490a 110 case 0x2000: //byte 0, bit 5
petter 8:beb6c399490a 111 result->event = RN52_TRACK_CHANGE_EVENT;
petter 8:beb6c399490a 112 break;
petter 8:beb6c399490a 113 default:
petter 8:beb6c399490a 114 result->event = RN52_OTHER_EVENT;
petter 0:6cf6e566c0da 115 break;
petter 8:beb6c399490a 116 }
petter 8:beb6c399490a 117 return 1;
petter 8:beb6c399490a 118 }
petter 8:beb6c399490a 119
petter 8:beb6c399490a 120 bool RN52::get_caller_id(RN52_RESULT * result){
petter 8:beb6c399490a 121 serial.printf(CALLER_ID);
petter 8:beb6c399490a 122 capture_response(result->response);
petter 8:beb6c399490a 123 //parse the response
petter 8:beb6c399490a 124 return 1;
petter 8:beb6c399490a 125 }
petter 8:beb6c399490a 126 bool RN52::get_track_metadata(RN52_RESULT * result){
petter 15:82c3cc87bd02 127 clear_serial();
petter 16:7bb8b161e00b 128 metadata_responsetime.start();
petter 16:7bb8b161e00b 129 metadata_responsetime.reset();
petter 8:beb6c399490a 130 serial.printf(TRACK_METADATA);
petter 16:7bb8b161e00b 131 capture_response(result->response);//AOK
petter 16:7bb8b161e00b 132 while(result->response[4] != '(') { //time(ms) - always the last one
petter 16:7bb8b161e00b 133 capture_response(result->response);
petter 16:7bb8b161e00b 134 switch (result->response[3]) {
petter 16:7bb8b161e00b 135 case 'l': //Title
petter 16:7bb8b161e00b 136 copy_response(result->response, result->title, 6);
petter 16:7bb8b161e00b 137 break;
petter 16:7bb8b161e00b 138 case 'i': //Artist
petter 16:7bb8b161e00b 139 copy_response(result->response, result->artist, 7);
petter 16:7bb8b161e00b 140 break;
petter 16:7bb8b161e00b 141 case 'u': //Album
petter 16:7bb8b161e00b 142 copy_response(result->response, result->album, 6);
petter 16:7bb8b161e00b 143 break;
petter 16:7bb8b161e00b 144 case 'r': //Genre
petter 16:7bb8b161e00b 145 copy_response(result->response, result->genre, 6);
petter 16:7bb8b161e00b 146 break;
petter 16:7bb8b161e00b 147 case 'c': //TrackNumber or TrackCount
petter 16:7bb8b161e00b 148 {
petter 16:7bb8b161e00b 149 char number_string[5];
petter 16:7bb8b161e00b 150 if(result->response[5] == 'N') { //TrackNumber
petter 16:7bb8b161e00b 151 copy_response(result->response, number_string, 12);
petter 16:7bb8b161e00b 152 result->track_number = strtoul(number_string, NULL, 10);
petter 6:c454f88524d6 153 }
petter 16:7bb8b161e00b 154 else { //TrackCount
petter 16:7bb8b161e00b 155 copy_response(result->response, number_string, 11);
petter 16:7bb8b161e00b 156 result->track_count = strtoul(number_string, NULL, 10);
petter 8:beb6c399490a 157 }
petter 16:7bb8b161e00b 158 }
petter 16:7bb8b161e00b 159 break;
petter 16:7bb8b161e00b 160 case 'e':
petter 16:7bb8b161e00b 161 {
petter 16:7bb8b161e00b 162 char duration_string[10];
petter 16:7bb8b161e00b 163 copy_response(result->response, duration_string, 9);
petter 16:7bb8b161e00b 164 result->duration = strtoul(duration_string, NULL, 10);
petter 16:7bb8b161e00b 165 }
petter 16:7bb8b161e00b 166 break;
petter 8:beb6c399490a 167 }
petter 16:7bb8b161e00b 168 if(metadata_responsetime.read_ms() > METADATA_RESPONSE_TIMEOUT) {
petter 16:7bb8b161e00b 169 clear_serial();
petter 16:7bb8b161e00b 170 return 0;
petter 16:7bb8b161e00b 171 }
petter 0:6cf6e566c0da 172 }
petter 16:7bb8b161e00b 173 clear_serial();
petter 0:6cf6e566c0da 174 return 1;
petter 0:6cf6e566c0da 175 }
petter 0:6cf6e566c0da 176
petter 5:8e468fef2754 177 bool RN52::capture_response(char * str){
petter 11:74844f6ca8cf 178 responsetime.reset();
petter 11:74844f6ca8cf 179 responsetime.start();
petter 0:6cf6e566c0da 180 char c = ' ';
petter 0:6cf6e566c0da 181 char n = 0;
petter 0:6cf6e566c0da 182 while(c != '\n') {
petter 0:6cf6e566c0da 183 if(serial.readable()) {
petter 0:6cf6e566c0da 184 c = serial.getc();
petter 0:6cf6e566c0da 185 str[n] = c;
petter 0:6cf6e566c0da 186 n++;
petter 0:6cf6e566c0da 187 }
petter 11:74844f6ca8cf 188 else if(responsetime.read_ms() > RESPONSE_TIMEOUT) {
petter 11:74844f6ca8cf 189 clear_serial();
petter 11:74844f6ca8cf 190 return 0;
petter 11:74844f6ca8cf 191 }
petter 0:6cf6e566c0da 192 }
petter 7:2df2c6e8c0df 193 str[n-2] = '\0'; //terminate string before \r\n
petter 15:82c3cc87bd02 194 //return (str[0] == 'A');
petter 15:82c3cc87bd02 195 return 1;
petter 6:c454f88524d6 196 }
petter 6:c454f88524d6 197
petter 6:c454f88524d6 198 void RN52::clear_serial(){
petter 6:c454f88524d6 199 while(serial.readable()) {
petter 6:c454f88524d6 200 serial.getc();
petter 6:c454f88524d6 201 }
petter 7:2df2c6e8c0df 202 }
petter 7:2df2c6e8c0df 203
petter 7:2df2c6e8c0df 204 void RN52::copy_response(char * source, char * destination, char offset){
petter 7:2df2c6e8c0df 205 int n = 0;
petter 7:2df2c6e8c0df 206 while(source[n+offset+1] != '\0') { //remove carraige return in the end
petter 7:2df2c6e8c0df 207 destination[n] = source[n+offset];
petter 7:2df2c6e8c0df 208 n++;
petter 7:2df2c6e8c0df 209 }
petter 7:2df2c6e8c0df 210 destination[n] = '\0'; //end string where carriage was
petter 7:2df2c6e8c0df 211 }
petter 7:2df2c6e8c0df 212
petter 7:2df2c6e8c0df 213 void RN52::clear_result(RN52_RESULT * result) {
petter 7:2df2c6e8c0df 214 result->event = RN52_NO_EVENT;
petter 7:2df2c6e8c0df 215 result->media_connected = 0;
petter 7:2df2c6e8c0df 216 result->phone_connected = 0;
petter 8:beb6c399490a 217 result->connection = RN52_NOT_SET;
petter 7:2df2c6e8c0df 218 result->title[0] = '\0';
petter 7:2df2c6e8c0df 219 result->artist[0] = '\0';
petter 7:2df2c6e8c0df 220 result->album[0] = '\0';
petter 7:2df2c6e8c0df 221 result->genre[0] = '\0';
petter 7:2df2c6e8c0df 222 result->duration = 0;
petter 9:9a4c81493a3d 223 result->track_number = 1;
petter 9:9a4c81493a3d 224 result->track_count = 1;
petter 7:2df2c6e8c0df 225 result->response[0] = '\0';
petter 15:82c3cc87bd02 226 }
petter 15:82c3cc87bd02 227
petter 15:82c3cc87bd02 228 void RN52::config(char * name) {
petter 15:82c3cc87bd02 229 bool en = enable_pin;
petter 15:82c3cc87bd02 230 enable_pin = 1;
petter 15:82c3cc87bd02 231 wait(0.5); //make sure booted up, not sure if needed
petter 15:82c3cc87bd02 232 serial.printf("S%%,18E7\r"); //extended features
petter 16:7bb8b161e00b 233 serial.printf("SC,200420\r"); //device type
petter 15:82c3cc87bd02 234 serial.printf("SN,%s\r", name); //name
petter 15:82c3cc87bd02 235 serial.printf(REBOOT);
petter 15:82c3cc87bd02 236 clear_serial();
petter 15:82c3cc87bd02 237 enable_pin = en; //restore status
petter 0:6cf6e566c0da 238 }