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.
CDC.cpp@16:7bb8b161e00b, 2016-03-18 (annotated)
- 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?
User | Revision | Line number | New contents of line |
---|---|---|---|
petter | 0:6cf6e566c0da | 1 | // I-Bus information from http://pikkupossu.1g.fi/tomi/projects/i-bus/i-bus.html |
petter | 0:6cf6e566c0da | 2 | // 290h - Steering wheel and SID buttons | Rx |
petter | 0:6cf6e566c0da | 3 | // 328h - SID audio text | Tx |
petter | 0:6cf6e566c0da | 4 | // 32Ch - ACC to SID text |
petter | 0:6cf6e566c0da | 5 | // 32Fh - TWICE to SID text |
petter | 0:6cf6e566c0da | 6 | // 337h - SPA to SID text |
petter | 0:6cf6e566c0da | 7 | // 348h - SID audio text control | Tx |
petter | 0:6cf6e566c0da | 8 | // 34Ch - ACC to SID text control |
petter | 0:6cf6e566c0da | 9 | // 34Fh - TWICE to SID text control |
petter | 0:6cf6e566c0da | 10 | // 357h - SPA to SID text control |
petter | 0:6cf6e566c0da | 11 | // 368h - SID text priority | Tx |
petter | 0:6cf6e566c0da | 12 | // 3C0h - CD Changer control | Rx |
petter | 0:6cf6e566c0da | 13 | // 3C8h - CD Changer information | Tx |
petter | 0:6cf6e566c0da | 14 | // 430h - SID beep request | Tx |
petter | 0:6cf6e566c0da | 15 | // 6A1h - Audio head unit | Rx |
petter | 0:6cf6e566c0da | 16 | // 6A2h - CD changer | Tx |
petter | 0:6cf6e566c0da | 17 | // 320h - Doors, central locking and seat belts | Rx |
petter | 0:6cf6e566c0da | 18 | |
petter | 0:6cf6e566c0da | 19 | /** Includes **/ |
petter | 0:6cf6e566c0da | 20 | #include "CDC.h" |
petter | 0:6cf6e566c0da | 21 | |
petter | 0:6cf6e566c0da | 22 | /** Various constants used for identifying the CDC **/ |
petter | 0:6cf6e566c0da | 23 | #define CDC_APL_ADR 0x11 |
petter | 0:6cf6e566c0da | 24 | #define CDC_SID_FUNCTION_ID 0x19 |
petter | 0:6cf6e566c0da | 25 | |
petter | 0:6cf6e566c0da | 26 | /** TX IDs: **/ |
petter | 0:6cf6e566c0da | 27 | #define GENERAL_STATUS_CDC 0x3C8 |
petter | 0:6cf6e566c0da | 28 | #define DISPLAY_RESOURCE_REQ 0x348 // 'Stolen' from the IHU since the CDC doesn't send this message |
petter | 0:6cf6e566c0da | 29 | #define WRITE_TEXT_ON_DISPLAY 0x328 // 'Stolen' from the IHU since the CDC doesn't send this message |
petter | 0:6cf6e566c0da | 30 | #define NODE_STATUS_TX 0x6A2 |
petter | 0:6cf6e566c0da | 31 | #define SOUND_REQUEST 0x430 |
petter | 0:6cf6e566c0da | 32 | |
petter | 0:6cf6e566c0da | 33 | /** RX IDs: **/ |
petter | 0:6cf6e566c0da | 34 | #define LOCK_STATUS 0x320 |
petter | 0:6cf6e566c0da | 35 | #define IHU_BUTTONS 0x3C0 |
petter | 0:6cf6e566c0da | 36 | #define DISPLAY_RESOURCE_GRANT 0x368 |
petter | 0:6cf6e566c0da | 37 | #define NODE_STATUS_RX 0x6A1 |
petter | 0:6cf6e566c0da | 38 | #define STEERING_WHEEL_BUTTONS 0x290 |
petter | 0:6cf6e566c0da | 39 | |
petter | 0:6cf6e566c0da | 40 | /** Variables: **/ |
petter | 0:6cf6e566c0da | 41 | bool cdc_active = false; // True while our module, the simulated CDC, is active. |
petter | 0:6cf6e566c0da | 42 | bool mute = false; |
petter | 0:6cf6e566c0da | 43 | int toggle_shuffle = 1; |
petter | 6:c454f88524d6 | 44 | int ninefive_cmd[] = {0x32,0x00,0x00,0x16,0x01,0x02,0x00,0x00,-1}; |
petter | 0:6cf6e566c0da | 45 | int beep_cmd[] = {0x80,0x04,0x00,0x00,0x00,0x00,0x00,0x00,-1}; |
petter | 0:6cf6e566c0da | 46 | int cdc_status_cmd[] = {0xE0,0x00,0x01,0x41,0x01,0x00,0x00,0xD0,-1}; |
petter | 11:74844f6ca8cf | 47 | int display_request_cmd[] = {CDC_APL_ADR,0x02,0x05,CDC_SID_FUNCTION_ID,0x00,0x00,0x00,0x00,-1}; |
petter | 0:6cf6e566c0da | 48 | |
petter | 0:6cf6e566c0da | 49 | /** Com: **/ |
petter | 0:6cf6e566c0da | 50 | CAN can(p9, p10); |
petter | 0:6cf6e566c0da | 51 | CANMessage CAN_TxMsg; |
petter | 0:6cf6e566c0da | 52 | CANMessage CAN_RxMsg; |
petter | 11:74844f6ca8cf | 53 | CANMessage CAN_DispMsg[3]; |
petter | 0:6cf6e566c0da | 54 | |
petter | 0:6cf6e566c0da | 55 | /** I/O: **/ |
petter | 0:6cf6e566c0da | 56 | DigitalOut led1(LED1, 0); |
petter | 0:6cf6e566c0da | 57 | DigitalOut led2(LED2, 0); |
petter | 13:968af0520530 | 58 | DigitalOut enable_transceiver(p19); |
petter | 0:6cf6e566c0da | 59 | |
petter | 2:10c60edc8573 | 60 | /** Timers: **/ |
petter | 2:10c60edc8573 | 61 | Timer playback; |
petter | 11:74844f6ca8cf | 62 | Timer sleep_timer; |
petter | 2:10c60edc8573 | 63 | |
petter | 0:6cf6e566c0da | 64 | /****************************************************************************** |
petter | 0:6cf6e566c0da | 65 | * PUBLIC METHODS |
petter | 0:6cf6e566c0da | 66 | ******************************************************************************/ |
petter | 0:6cf6e566c0da | 67 | |
petter | 13:968af0520530 | 68 | /** Enables CAN traciever transmit **/ |
petter | 13:968af0520530 | 69 | void CDC::enable() { |
petter | 16:7bb8b161e00b | 70 | //enable_transceiver = 0; //active |
petter | 16:7bb8b161e00b | 71 | can.monitor(0); |
petter | 14:3f4098e94c29 | 72 | sleep_timer.reset(); |
petter | 14:3f4098e94c29 | 73 | sleep_timer.start(); |
petter | 13:968af0520530 | 74 | } |
petter | 13:968af0520530 | 75 | |
petter | 13:968af0520530 | 76 | /** Disables CAN traciever transmit **/ |
petter | 13:968af0520530 | 77 | void CDC::disable() { |
petter | 16:7bb8b161e00b | 78 | //enable_transceiver = 1; //sleep |
petter | 16:7bb8b161e00b | 79 | can.monitor(1); |
petter | 14:3f4098e94c29 | 80 | sleep_timer.stop(); |
petter | 13:968af0520530 | 81 | } |
petter | 13:968af0520530 | 82 | |
petter | 0:6cf6e566c0da | 83 | /** Initializes CDC **/ |
petter | 0:6cf6e566c0da | 84 | void CDC::init() { |
petter | 13:968af0520530 | 85 | enable(); |
petter | 0:6cf6e566c0da | 86 | can.frequency(47619); |
petter | 0:6cf6e566c0da | 87 | printf("CAN Frequency set\r\n"); |
petter | 0:6cf6e566c0da | 88 | CAN_wrFilter(1, IHU_BUTTONS); |
petter | 0:6cf6e566c0da | 89 | CAN_wrFilter(1, DISPLAY_RESOURCE_GRANT); |
petter | 0:6cf6e566c0da | 90 | CAN_wrFilter(1, NODE_STATUS_RX); |
petter | 0:6cf6e566c0da | 91 | CAN_wrFilter(1, STEERING_WHEEL_BUTTONS); |
petter | 0:6cf6e566c0da | 92 | CAN_wrFilter(1, DISPLAY_RESOURCE_REQ); |
petter | 0:6cf6e566c0da | 93 | printf("CAN Filters set\r\n"); |
petter | 0:6cf6e566c0da | 94 | |
petter | 0:6cf6e566c0da | 95 | CAN_TxMsg.len = 8; |
petter | 11:74844f6ca8cf | 96 | CAN_DispMsg[0].len = 8; |
petter | 11:74844f6ca8cf | 97 | CAN_DispMsg[1].len = 8; |
petter | 11:74844f6ca8cf | 98 | CAN_DispMsg[2].len = 8; |
petter | 11:74844f6ca8cf | 99 | CAN_DispMsg[0].id = WRITE_TEXT_ON_DISPLAY; |
petter | 11:74844f6ca8cf | 100 | CAN_DispMsg[1].id = WRITE_TEXT_ON_DISPLAY; |
petter | 11:74844f6ca8cf | 101 | CAN_DispMsg[2].id = WRITE_TEXT_ON_DISPLAY; |
petter | 11:74844f6ca8cf | 102 | CAN_DispMsg[0].data[0] = 0x42; // order, new |
petter | 11:74844f6ca8cf | 103 | CAN_DispMsg[1].data[0] = 0x01; // order |
petter | 11:74844f6ca8cf | 104 | CAN_DispMsg[2].data[0] = 0x00; // order |
petter | 11:74844f6ca8cf | 105 | CAN_DispMsg[0].data[1] = 0x96; // Address of the SID |
petter | 11:74844f6ca8cf | 106 | CAN_DispMsg[1].data[1] = 0x96; // Address of the SID |
petter | 11:74844f6ca8cf | 107 | CAN_DispMsg[2].data[1] = 0x96; // Address of the SID |
petter | 12:4194c47ca60b | 108 | CAN_DispMsg[0].data[2] = 0x02; // Writing to row 2 |
petter | 12:4194c47ca60b | 109 | CAN_DispMsg[1].data[2] = 0x02; // Writing to row 2 |
petter | 12:4194c47ca60b | 110 | CAN_DispMsg[2].data[2] = 0x02; // Writing to row 2 |
petter | 12:4194c47ca60b | 111 | display("PETTERS BT"); |
petter | 11:74844f6ca8cf | 112 | |
petter | 11:74844f6ca8cf | 113 | sleep_timer.start(); |
petter | 0:6cf6e566c0da | 114 | } |
petter | 0:6cf6e566c0da | 115 | |
petter | 0:6cf6e566c0da | 116 | /** Handles an incoming (RX) frame **/ |
petter | 11:74844f6ca8cf | 117 | IBUS_COMMAND CDC::get_cmd() { |
petter | 14:3f4098e94c29 | 118 | if(can.read(CAN_RxMsg)) { |
petter | 0:6cf6e566c0da | 119 | led2 = !led2; |
petter | 0:6cf6e566c0da | 120 | switch (CAN_RxMsg.id) { |
petter | 0:6cf6e566c0da | 121 | case DISPLAY_RESOURCE_REQ: |
petter | 11:74844f6ca8cf | 122 | sleep_timer.reset(); |
petter | 11:74844f6ca8cf | 123 | send_can_frame(DISPLAY_RESOURCE_REQ, display_request_cmd); |
petter | 2:10c60edc8573 | 124 | update_elapsed_time(); |
petter | 0:6cf6e566c0da | 125 | send_can_frame(GENERAL_STATUS_CDC, cdc_status_cmd); |
petter | 12:4194c47ca60b | 126 | led1 = !led1; |
petter | 16:7bb8b161e00b | 127 | printf("cdc_acttive = %i", cdc_active); |
petter | 11:74844f6ca8cf | 128 | return IBUS_HEAD_UNIT_ON; |
petter | 0:6cf6e566c0da | 129 | case NODE_STATUS_RX: |
petter | 6:c454f88524d6 | 130 | send_can_frame(NODE_STATUS_TX, ninefive_cmd); |
petter | 0:6cf6e566c0da | 131 | break; |
petter | 0:6cf6e566c0da | 132 | case IHU_BUTTONS: |
petter | 0:6cf6e566c0da | 133 | return get_ihu_cmd(); |
petter | 0:6cf6e566c0da | 134 | case STEERING_WHEEL_BUTTONS: |
petter | 0:6cf6e566c0da | 135 | return get_steering_wheel_cmd(); |
petter | 0:6cf6e566c0da | 136 | case DISPLAY_RESOURCE_GRANT: |
petter | 10:8be92db98bf4 | 137 | if (CAN_RxMsg.data[1] == CDC_SID_FUNCTION_ID) { |
petter | 0:6cf6e566c0da | 138 | //We have been granted the right to write text to the second row in the SID |
petter | 11:74844f6ca8cf | 139 | display_request_cmd[2] = 0x04; |
petter | 11:74844f6ca8cf | 140 | display_update(); |
petter | 0:6cf6e566c0da | 141 | } |
petter | 10:8be92db98bf4 | 142 | else { |
petter | 10:8be92db98bf4 | 143 | //Someone else has been granted the display, we need to back down |
petter | 11:74844f6ca8cf | 144 | display_request_cmd[2] = 0x05; //message is considered new |
petter | 0:6cf6e566c0da | 145 | } |
petter | 15:82c3cc87bd02 | 146 | break; |
petter | 0:6cf6e566c0da | 147 | } |
petter | 0:6cf6e566c0da | 148 | return IBUS_OTHER_MESSAGE; |
petter | 11:74844f6ca8cf | 149 | } |
petter | 11:74844f6ca8cf | 150 | if(sleep_timer.read() > 5) { |
petter | 11:74844f6ca8cf | 151 | return IBUS_HEAD_UNIT_OFF; |
petter | 0:6cf6e566c0da | 152 | } |
petter | 0:6cf6e566c0da | 153 | return IBUS_NO_MESSAGE; |
petter | 0:6cf6e566c0da | 154 | } |
petter | 0:6cf6e566c0da | 155 | |
petter | 0:6cf6e566c0da | 156 | /** Handles the IHU_BUTTONS frame that the IHU sends us when it wants to control some feature of the CDC **/ |
petter | 0:6cf6e566c0da | 157 | IBUS_COMMAND CDC::get_ihu_cmd() { |
petter | 0:6cf6e566c0da | 158 | bool event = (CAN_RxMsg.data[0] == 0x80); |
petter | 0:6cf6e566c0da | 159 | if (!event) { |
petter | 0:6cf6e566c0da | 160 | //Ignore the message if it wasn't sent on event |
petter | 0:6cf6e566c0da | 161 | return IBUS_OTHER_MESSAGE; |
petter | 0:6cf6e566c0da | 162 | } |
petter | 0:6cf6e566c0da | 163 | switch (CAN_RxMsg.data[1]) { |
petter | 0:6cf6e566c0da | 164 | case 0x24: // CDC = ON (CD/RDM button has been pressed twice) |
petter | 0:6cf6e566c0da | 165 | cdc_active = true; |
petter | 0:6cf6e566c0da | 166 | return IBUS_CDC_ON; |
petter | 0:6cf6e566c0da | 167 | case 0x14: // CDC = OFF (Back to Radio or Tape mode) |
petter | 0:6cf6e566c0da | 168 | cdc_active = false; |
petter | 0:6cf6e566c0da | 169 | return IBUS_CDC_OFF; |
petter | 0:6cf6e566c0da | 170 | } |
petter | 0:6cf6e566c0da | 171 | if (cdc_active) { |
petter | 0:6cf6e566c0da | 172 | switch (CAN_RxMsg.data[1]) { |
petter | 0:6cf6e566c0da | 173 | case 0x35: // Track up |
petter | 0:6cf6e566c0da | 174 | return IBUS_SKIP_FW; |
petter | 0:6cf6e566c0da | 175 | case 0x36: // Track down |
petter | 0:6cf6e566c0da | 176 | return IBUS_SKIP_BW; |
petter | 0:6cf6e566c0da | 177 | } |
petter | 0:6cf6e566c0da | 178 | } |
petter | 0:6cf6e566c0da | 179 | return IBUS_OTHER_MESSAGE; |
petter | 0:6cf6e566c0da | 180 | } |
petter | 0:6cf6e566c0da | 181 | |
petter | 0:6cf6e566c0da | 182 | /** Handles the STEERING_WHEEL_BUTTONS frame * TODO connect the SID button events to actions **/ |
petter | 0:6cf6e566c0da | 183 | IBUS_COMMAND CDC::get_steering_wheel_cmd() { |
petter | 0:6cf6e566c0da | 184 | |
petter | 0:6cf6e566c0da | 185 | bool event = (CAN_RxMsg.data[0] == 0x80); |
petter | 0:6cf6e566c0da | 186 | if (!event) { |
petter | 0:6cf6e566c0da | 187 | //Ignore the message if it wasn't sent on event |
petter | 0:6cf6e566c0da | 188 | return IBUS_OTHER_MESSAGE; |
petter | 0:6cf6e566c0da | 189 | } |
petter | 0:6cf6e566c0da | 190 | if (!cdc_active) { |
petter | 0:6cf6e566c0da | 191 | return IBUS_OTHER_MESSAGE; |
petter | 0:6cf6e566c0da | 192 | } |
petter | 0:6cf6e566c0da | 193 | switch (CAN_RxMsg.data[4]) { |
petter | 0:6cf6e566c0da | 194 | case 0x04: // NXT button on wheel |
petter | 0:6cf6e566c0da | 195 | return IBUS_NEXT; |
petter | 0:6cf6e566c0da | 196 | case 0x10: // Seek+ button on wheel |
petter | 0:6cf6e566c0da | 197 | return IBUS_SKIP_FW; |
petter | 0:6cf6e566c0da | 198 | case 0x08: // Seek- button on wheel |
petter | 0:6cf6e566c0da | 199 | return IBUS_SKIP_BW; |
petter | 0:6cf6e566c0da | 200 | case 0x40: // Vol+ button on wheel |
petter | 0:6cf6e566c0da | 201 | return IBUS_VOLUME_UP; |
petter | 0:6cf6e566c0da | 202 | case 0x80: // Vol- button on wheel |
petter | 0:6cf6e566c0da | 203 | return IBUS_VOLUME_DOWN; |
petter | 0:6cf6e566c0da | 204 | } |
petter | 0:6cf6e566c0da | 205 | switch (CAN_RxMsg.data[5]) { |
petter | 0:6cf6e566c0da | 206 | case 0x40: // SET button on SID |
petter | 0:6cf6e566c0da | 207 | return IBUS_SET; |
petter | 0:6cf6e566c0da | 208 | case 0x80: // CLEAR button on SID |
petter | 0:6cf6e566c0da | 209 | return IBUS_CLEAR; |
petter | 0:6cf6e566c0da | 210 | } |
petter | 0:6cf6e566c0da | 211 | return IBUS_OTHER_MESSAGE; |
petter | 0:6cf6e566c0da | 212 | } |
petter | 0:6cf6e566c0da | 213 | |
petter | 0:6cf6e566c0da | 214 | |
petter | 0:6cf6e566c0da | 215 | |
petter | 0:6cf6e566c0da | 216 | /** Writes the provided text on the SID. NOTE the character set used by the SID is slightly nonstandard. "Normal" characters should work fine. **/ |
petter | 11:74844f6ca8cf | 217 | void CDC::display(char text[]) { |
petter | 0:6cf6e566c0da | 218 | if (!text) { |
petter | 0:6cf6e566c0da | 219 | return; |
petter | 0:6cf6e566c0da | 220 | } |
petter | 0:6cf6e566c0da | 221 | |
petter | 0:6cf6e566c0da | 222 | //Notify the SID that we want to display a message |
petter | 11:74844f6ca8cf | 223 | send_can_frame(DISPLAY_RESOURCE_REQ, display_request_cmd); |
petter | 0:6cf6e566c0da | 224 | |
petter | 0:6cf6e566c0da | 225 | // Copy the provided string and make sure we have a new array of the correct length: |
petter | 0:6cf6e566c0da | 226 | char display_text[15]; |
petter | 0:6cf6e566c0da | 227 | int i, n; |
petter | 0:6cf6e566c0da | 228 | n = strlen(text); |
petter | 0:6cf6e566c0da | 229 | if(n > 15) { |
petter | 0:6cf6e566c0da | 230 | n = 15; |
petter | 0:6cf6e566c0da | 231 | } |
petter | 0:6cf6e566c0da | 232 | for (i = 0; i < n; i++) { |
petter | 0:6cf6e566c0da | 233 | display_text[i] = text[i]; |
petter | 0:6cf6e566c0da | 234 | } |
petter | 9:9a4c81493a3d | 235 | for (i = n; i < 15; i++) { |
petter | 0:6cf6e566c0da | 236 | display_text[i] = 0; |
petter | 0:6cf6e566c0da | 237 | } |
petter | 0:6cf6e566c0da | 238 | |
petter | 11:74844f6ca8cf | 239 | CAN_DispMsg[0].data[2] = 0x82; // Sent on basetime, writing to row 2, message changed |
petter | 11:74844f6ca8cf | 240 | CAN_DispMsg[0].data[3] = display_text[0]; |
petter | 11:74844f6ca8cf | 241 | CAN_DispMsg[0].data[4] = display_text[1]; |
petter | 11:74844f6ca8cf | 242 | CAN_DispMsg[0].data[5] = display_text[2]; |
petter | 11:74844f6ca8cf | 243 | CAN_DispMsg[0].data[6] = display_text[3]; |
petter | 11:74844f6ca8cf | 244 | CAN_DispMsg[0].data[7] = display_text[4]; |
petter | 0:6cf6e566c0da | 245 | |
petter | 11:74844f6ca8cf | 246 | CAN_DispMsg[1].data[3] = display_text[5]; |
petter | 11:74844f6ca8cf | 247 | CAN_DispMsg[1].data[4] = display_text[6]; |
petter | 11:74844f6ca8cf | 248 | CAN_DispMsg[1].data[5] = display_text[7]; |
petter | 11:74844f6ca8cf | 249 | CAN_DispMsg[1].data[6] = display_text[8]; |
petter | 11:74844f6ca8cf | 250 | CAN_DispMsg[1].data[7] = display_text[9]; |
petter | 0:6cf6e566c0da | 251 | |
petter | 11:74844f6ca8cf | 252 | CAN_DispMsg[2].data[3] = display_text[10]; |
petter | 11:74844f6ca8cf | 253 | CAN_DispMsg[2].data[4] = display_text[11]; |
petter | 11:74844f6ca8cf | 254 | CAN_DispMsg[2].data[5] = display_text[12]; |
petter | 11:74844f6ca8cf | 255 | CAN_DispMsg[2].data[6] = display_text[13]; |
petter | 11:74844f6ca8cf | 256 | CAN_DispMsg[2].data[7] = display_text[14]; |
petter | 0:6cf6e566c0da | 257 | } |
petter | 0:6cf6e566c0da | 258 | |
petter | 0:6cf6e566c0da | 259 | /** Writes the provided text on the SID. NOTE the character set used by the SID is slightly nonstandard. "Normal" characters should work fine. **/ |
petter | 11:74844f6ca8cf | 260 | void CDC::display_update() { |
petter | 11:74844f6ca8cf | 261 | can.write(CAN_DispMsg[0]); |
petter | 11:74844f6ca8cf | 262 | can.write(CAN_DispMsg[1]); |
petter | 11:74844f6ca8cf | 263 | can.write(CAN_DispMsg[2]); |
petter | 11:74844f6ca8cf | 264 | CAN_DispMsg[0].data[2] = 0x02; // Message not changed next transmission unless display() is called |
petter | 0:6cf6e566c0da | 265 | } |
petter | 0:6cf6e566c0da | 266 | |
petter | 2:10c60edc8573 | 267 | /** Sets the elapsed time in the cdc_status message **/ |
petter | 2:10c60edc8573 | 268 | void CDC::update_elapsed_time() { |
petter | 2:10c60edc8573 | 269 | cdc_status_cmd[5] = (char)(((int)playback.read())/60); |
petter | 2:10c60edc8573 | 270 | cdc_status_cmd[6] = (char)(((int)playback.read())%60); |
petter | 2:10c60edc8573 | 271 | } |
petter | 2:10c60edc8573 | 272 | |
petter | 2:10c60edc8573 | 273 | /** Resets the elapsed time in the cdc_status message **/ |
petter | 2:10c60edc8573 | 274 | void CDC::reset_elapsed_time() { |
petter | 2:10c60edc8573 | 275 | playback.reset(); |
petter | 2:10c60edc8573 | 276 | } |
petter | 2:10c60edc8573 | 277 | |
petter | 2:10c60edc8573 | 278 | /** Stops the elapsed time in the cdc_status message **/ |
petter | 2:10c60edc8573 | 279 | void CDC::stop_elapsed_time() { |
petter | 2:10c60edc8573 | 280 | playback.stop(); |
petter | 2:10c60edc8573 | 281 | } |
petter | 2:10c60edc8573 | 282 | |
petter | 2:10c60edc8573 | 283 | /** Starts the elapsed time in the cdc_status message **/ |
petter | 2:10c60edc8573 | 284 | void CDC::start_elapsed_time() { |
petter | 2:10c60edc8573 | 285 | playback.start(); |
petter | 0:6cf6e566c0da | 286 | } |
petter | 0:6cf6e566c0da | 287 | |
petter | 6:c454f88524d6 | 288 | /** Sets the current track number as playing **/ |
petter | 6:c454f88524d6 | 289 | void CDC::set_track(char track_number) { |
petter | 6:c454f88524d6 | 290 | cdc_status_cmd[4] = track_number; |
petter | 6:c454f88524d6 | 291 | } |
petter | 6:c454f88524d6 | 292 | |
petter | 0:6cf6e566c0da | 293 | |
petter | 0:6cf6e566c0da | 294 | /** Formats and puts a frame on CAN bus **/ |
petter | 0:6cf6e566c0da | 295 | void CDC::send_can_frame(int message_id, int *msg) { |
petter | 0:6cf6e566c0da | 296 | CAN_TxMsg.id = message_id; |
petter | 0:6cf6e566c0da | 297 | int i = 0; |
petter | 0:6cf6e566c0da | 298 | while (msg[i] != -1) { |
petter | 0:6cf6e566c0da | 299 | CAN_TxMsg.data[i] = msg[i]; |
petter | 0:6cf6e566c0da | 300 | i++; |
petter | 0:6cf6e566c0da | 301 | } |
petter | 0:6cf6e566c0da | 302 | can.write(CAN_TxMsg); |
petter | 0:6cf6e566c0da | 303 | } |
petter | 0:6cf6e566c0da | 304 | |
petter | 0:6cf6e566c0da | 305 | /** DEBUG: Prints the CAN TX frame to serial output **/ |
petter | 0:6cf6e566c0da | 306 | void CDC::print_can_frame(CANMessage *msg){ |
petter | 0:6cf6e566c0da | 307 | printf("CAN message %X:", msg->id); |
petter | 0:6cf6e566c0da | 308 | for (int i = 0; i < msg->len; i++) { |
petter | 0:6cf6e566c0da | 309 | printf(" %X", msg->data[i]); |
petter | 0:6cf6e566c0da | 310 | } |
petter | 0:6cf6e566c0da | 311 | printf("\r\n"); |
petter | 0:6cf6e566c0da | 312 | } |
petter | 0:6cf6e566c0da | 313 | |
petter | 0:6cf6e566c0da | 314 | /*---------------------------------------------------------------------------- |
petter | 0:6cf6e566c0da | 315 | setup acceptance filter. CAN controller (1..2) |
petter | 0:6cf6e566c0da | 316 | *----------------------------------------------------------------------------*/ |
petter | 0:6cf6e566c0da | 317 | void CDC::CAN_wrFilter(uint32_t ctrl, uint32_t id) { |
petter | 0:6cf6e566c0da | 318 | static int CAN_std_cnt = 0; |
petter | 0:6cf6e566c0da | 319 | static int CAN_ext_cnt = 0; |
petter | 0:6cf6e566c0da | 320 | uint32_t buf0, buf1; |
petter | 0:6cf6e566c0da | 321 | int cnt1, cnt2, bound1; |
petter | 0:6cf6e566c0da | 322 | |
petter | 0:6cf6e566c0da | 323 | /* Acceptance Filter Memory full */ |
petter | 0:6cf6e566c0da | 324 | if ((((CAN_std_cnt + 1) >> 1) + CAN_ext_cnt) >= 512) |
petter | 0:6cf6e566c0da | 325 | return; /* error: objects full */ |
petter | 0:6cf6e566c0da | 326 | |
petter | 0:6cf6e566c0da | 327 | /* Setup Acceptance Filter Configuration |
petter | 0:6cf6e566c0da | 328 | Acceptance Filter Mode Register = Off */ |
petter | 0:6cf6e566c0da | 329 | LPC_CANAF->AFMR = 0x00000001; |
petter | 0:6cf6e566c0da | 330 | |
petter | 0:6cf6e566c0da | 331 | id |= (ctrl-1) << 13; /* Add controller number */ |
petter | 0:6cf6e566c0da | 332 | id &= 0x0000F7FF; /* Mask out 16-bits of ID */ |
petter | 0:6cf6e566c0da | 333 | |
petter | 0:6cf6e566c0da | 334 | /* Move all remaining extended mask entries one place up |
petter | 0:6cf6e566c0da | 335 | if new entry will increase standard ID filters list */ |
petter | 0:6cf6e566c0da | 336 | if ((CAN_std_cnt & 0x0001) == 0 && CAN_ext_cnt != 0) { |
petter | 0:6cf6e566c0da | 337 | cnt1 = (CAN_std_cnt >> 1); |
petter | 0:6cf6e566c0da | 338 | bound1 = CAN_ext_cnt; |
petter | 0:6cf6e566c0da | 339 | buf0 = LPC_CANAF_RAM->mask[cnt1]; |
petter | 0:6cf6e566c0da | 340 | while (bound1--) { |
petter | 0:6cf6e566c0da | 341 | cnt1++; |
petter | 0:6cf6e566c0da | 342 | buf1 = LPC_CANAF_RAM->mask[cnt1]; |
petter | 0:6cf6e566c0da | 343 | LPC_CANAF_RAM->mask[cnt1] = buf0; |
petter | 0:6cf6e566c0da | 344 | buf0 = buf1; |
petter | 0:6cf6e566c0da | 345 | } |
petter | 0:6cf6e566c0da | 346 | } |
petter | 0:6cf6e566c0da | 347 | |
petter | 0:6cf6e566c0da | 348 | if (CAN_std_cnt == 0) { /* For entering first ID */ |
petter | 0:6cf6e566c0da | 349 | LPC_CANAF_RAM->mask[0] = 0x0000FFFF | (id << 16); |
petter | 0:6cf6e566c0da | 350 | } else if (CAN_std_cnt == 1) { /* For entering second ID */ |
petter | 0:6cf6e566c0da | 351 | if ((LPC_CANAF_RAM->mask[0] >> 16) > id) |
petter | 0:6cf6e566c0da | 352 | LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] >> 16) | (id << 16); |
petter | 0:6cf6e566c0da | 353 | else |
petter | 0:6cf6e566c0da | 354 | LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] & 0xFFFF0000) | id; |
petter | 0:6cf6e566c0da | 355 | } else { |
petter | 0:6cf6e566c0da | 356 | /* Find where to insert new ID */ |
petter | 0:6cf6e566c0da | 357 | cnt1 = 0; |
petter | 0:6cf6e566c0da | 358 | cnt2 = CAN_std_cnt; |
petter | 0:6cf6e566c0da | 359 | bound1 = (CAN_std_cnt - 1) >> 1; |
petter | 0:6cf6e566c0da | 360 | while (cnt1 <= bound1) { /* Loop through standard existing IDs */ |
petter | 0:6cf6e566c0da | 361 | if ((LPC_CANAF_RAM->mask[cnt1] >> 16) > id) { |
petter | 0:6cf6e566c0da | 362 | cnt2 = cnt1 * 2; |
petter | 0:6cf6e566c0da | 363 | break; |
petter | 0:6cf6e566c0da | 364 | } |
petter | 0:6cf6e566c0da | 365 | if ((LPC_CANAF_RAM->mask[cnt1] & 0x0000FFFF) > id) { |
petter | 0:6cf6e566c0da | 366 | cnt2 = cnt1 * 2 + 1; |
petter | 0:6cf6e566c0da | 367 | break; |
petter | 0:6cf6e566c0da | 368 | } |
petter | 0:6cf6e566c0da | 369 | cnt1++; /* cnt1 = U32 where to insert new ID */ |
petter | 0:6cf6e566c0da | 370 | } /* cnt2 = U16 where to insert new ID */ |
petter | 0:6cf6e566c0da | 371 | |
petter | 0:6cf6e566c0da | 372 | if (cnt1 > bound1) { /* Adding ID as last entry */ |
petter | 0:6cf6e566c0da | 373 | if ((CAN_std_cnt & 0x0001) == 0) /* Even number of IDs exists */ |
petter | 0:6cf6e566c0da | 374 | LPC_CANAF_RAM->mask[cnt1] = 0x0000FFFF | (id << 16); |
petter | 0:6cf6e566c0da | 375 | else /* Odd number of IDs exists */ |
petter | 0:6cf6e566c0da | 376 | LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | id; |
petter | 0:6cf6e566c0da | 377 | } else { |
petter | 0:6cf6e566c0da | 378 | buf0 = LPC_CANAF_RAM->mask[cnt1]; /* Remember current entry */ |
petter | 0:6cf6e566c0da | 379 | if ((cnt2 & 0x0001) == 0) /* Insert new mask to even address */ |
petter | 0:6cf6e566c0da | 380 | buf1 = (id << 16) | (buf0 >> 16); |
petter | 0:6cf6e566c0da | 381 | else /* Insert new mask to odd address */ |
petter | 0:6cf6e566c0da | 382 | buf1 = (buf0 & 0xFFFF0000) | id; |
petter | 0:6cf6e566c0da | 383 | |
petter | 0:6cf6e566c0da | 384 | LPC_CANAF_RAM->mask[cnt1] = buf1; /* Insert mask */ |
petter | 0:6cf6e566c0da | 385 | |
petter | 0:6cf6e566c0da | 386 | bound1 = CAN_std_cnt >> 1; |
petter | 0:6cf6e566c0da | 387 | /* Move all remaining standard mask entries one place up */ |
petter | 0:6cf6e566c0da | 388 | while (cnt1 < bound1) { |
petter | 0:6cf6e566c0da | 389 | cnt1++; |
petter | 0:6cf6e566c0da | 390 | buf1 = LPC_CANAF_RAM->mask[cnt1]; |
petter | 0:6cf6e566c0da | 391 | LPC_CANAF_RAM->mask[cnt1] = (buf1 >> 16) | (buf0 << 16); |
petter | 0:6cf6e566c0da | 392 | buf0 = buf1; |
petter | 0:6cf6e566c0da | 393 | } |
petter | 0:6cf6e566c0da | 394 | |
petter | 0:6cf6e566c0da | 395 | if ((CAN_std_cnt & 0x0001) == 0) /* Even number of IDs exists */ |
petter | 0:6cf6e566c0da | 396 | LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | (0x0000FFFF); |
petter | 0:6cf6e566c0da | 397 | } |
petter | 0:6cf6e566c0da | 398 | } |
petter | 0:6cf6e566c0da | 399 | CAN_std_cnt++; |
petter | 0:6cf6e566c0da | 400 | |
petter | 0:6cf6e566c0da | 401 | /* Calculate std ID start address (buf0) and ext ID start address (buf1) */ |
petter | 0:6cf6e566c0da | 402 | buf0 = ((CAN_std_cnt + 1) >> 1) << 2; |
petter | 0:6cf6e566c0da | 403 | buf1 = buf0 + (CAN_ext_cnt << 2); |
petter | 0:6cf6e566c0da | 404 | |
petter | 0:6cf6e566c0da | 405 | /* Setup acceptance filter pointers */ |
petter | 0:6cf6e566c0da | 406 | LPC_CANAF->SFF_sa = 0; |
petter | 0:6cf6e566c0da | 407 | LPC_CANAF->SFF_GRP_sa = buf0; |
petter | 0:6cf6e566c0da | 408 | LPC_CANAF->EFF_sa = buf0; |
petter | 0:6cf6e566c0da | 409 | LPC_CANAF->EFF_GRP_sa = buf1; |
petter | 0:6cf6e566c0da | 410 | LPC_CANAF->ENDofTable = buf1; |
petter | 0:6cf6e566c0da | 411 | |
petter | 0:6cf6e566c0da | 412 | LPC_CANAF->AFMR = 0x00000000; /* Use acceptance filter */ |
petter | 0:6cf6e566c0da | 413 | } |