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