1 /******************************************************************************* 2 * Types and defines 3 ******************************************************************************/ 4 5 //#define VALIDATE_PERFORMANCE_ON_MAX_DMX_BUS_LOAD 6 7 #define MAN_ID ((32*32*('N'-'@')) + (32*('X'-'@')) + ('P'-'@')) 8 9 #define DEVICE_MODEL_ID1 0x00 /* MSB */ 10 #define DEVICE_MODEL_ID0 0x01 /* LSB */ 11 12 #define SW_VERSION_ID3 0x01 /* MSB */ 13 #define SW_VERSION_ID2 0x00 14 #define SW_VERSION_ID1 0x00 15 #define SW_VERSION_ID0 0x03 /* LSB */ 16 #define FIRMWARE_VERSION "V1.0.0.3" 17 18 #define DMX512_FOOTPRINT 4 /* nr of slots this device uses */ 19 20 #define SC_NULL 0x00 /* NULL Start Code Packet */ 21 #define SC_TEXT 0x17 /* Start Code ASCII Text Packet */ 22 #define SC_RDM 0xCC /* Start Code RDM Packet */ 23 24 #define SC_SUB_MESSAGE 0x01 25 26 // RDM command classes (Slot 20) 27 #define DISCOVERY_COMMAND 0x10 28 #define DISCOVERY_COMMAND_RESPONSE 0x11 29 #define GET_COMMAND 0x20 30 #define GET_COMMAND_RESPONSE 0x21 31 #define SET_COMMAND 0x30 32 #define SET_COMMAND_RESPONSE 0x31 33 34 #define RESPONSE_TYPE_ACK 0x00 35 #define RESPONSE_TYPE_ACK_TIMER 0x01 36 #define RESPONSE_TYPE_NACK_REASON 0x02 37 #define RESPONSE_TYPE_ACK_OVERFLOW 0x03 38 39 #define DISC_UNIQUE_BRANCH 0x0001 40 #define DISC_MUTE 0x0002 41 #define DISC_UN_MUTE 0x0003 42 #define DEVICE_INFO 0x0060 43 #define SOFTWARE_VERSION_LABEL 0x00C0 44 #define DMX_START_ADDRESS 0x00F0 45 #define IDENTIFY_DEVICE 0x1000 46 47 /******************************************************************************* 48 * global variables 49 ******************************************************************************/ 50 51 static uint16_t my_dmx_start_address; 52 53 #ifdef SUPPORT_RDM_OVER_DMX512 54 static uint32_t my_unique_id; 55 static long long my_uid; 56 static uint16_t break_time; 57 static uint16_t mab_time; 58 static uint8_t rdm_message_count; 59 static uint8_t rdm_response_msg[64]; 60 static uint8_t identify_state; // off=0, on=1 61 #endif 62 63 /******************************************************************************* 64 * local functions 65 ******************************************************************************/ 66 67 static uint16_t get_my_slot_nrs(void) 68 { 69 return ((bsp_read_dip_switches() * 32) + 29); 70 } 71 72 static inline void init_globals(void) 73 { 74 my_dmx_start_address = get_my_slot_nrs(); 75 #ifdef SUPPORT_RDM_OVER_DMX512 76 my_unique_id = bsp_get_id(); // this is not garanteed to be unique !! 77 my_uid = ((MAN_ID >> 8) & 0xFF); 78 my_uid <<= 8; 79 my_uid |= ((MAN_ID >> 0) & 0xFF); 80 my_uid <<= 8; 81 my_uid |= ((my_unique_id >> 24) & 0xFF); 82 my_uid <<= 8; 83 my_uid |= ((my_unique_id >> 16) & 0xFF); 84 my_uid <<= 8; 85 my_uid |= ((my_unique_id >> 8) & 0xFF); 86 my_uid <<= 8; 87 my_uid |= ((my_unique_id >> 0) & 0xFF); 88 break_time = 176; /* 176 usec */ 89 mab_time = 12; /* 12 usec */ 90 rdm_message_count = 0; 91 identify_state = 0; 92 #endif 93 } 94 95 #ifdef SUPPORT_RDM_OVER_DMX512 96 static uint16_t calc_crc(uint8_t *data, uint8_t len) 97 { 98 uint16_t crc = 0; 99 uint16_t i; 100 101 for (i=0; i < len; i++) 102 { 103 crc += *data++; 104 } 105 return crc; 106 } 107 108 static inline void send_disc_response(uint8_t *rdm_msg) 109 { 110 bsp_delay_usec(100); 111 rdm_response_msg[0] = 0xFE; 112 rdm_response_msg[1] = 0xFE; 113 rdm_response_msg[2] = 0xFE; 114 rdm_response_msg[3] = 0xFE; 115 rdm_response_msg[4] = 0xFE; 116 rdm_response_msg[5] = 0xFE; 117 rdm_response_msg[6] = 0xFE; 118 rdm_response_msg[7] = 0xAA; 119 rdm_response_msg[8] = ((MAN_ID >> 8) & 0xFF) | 0xAA; 120 rdm_response_msg[9] = ((MAN_ID >> 8) & 0xFF) | 0x55; 121 rdm_response_msg[10] = ((MAN_ID >> 0) & 0xFF) | 0xAA; 122 rdm_response_msg[11] = ((MAN_ID >> 0) & 0xFF) | 0x55; 123 rdm_response_msg[12] = ((my_unique_id >> 24) & 0xFF) | 0xAA; 124 rdm_response_msg[13] = ((my_unique_id >> 24) & 0xFF) | 0x55; 125 rdm_response_msg[14] = ((my_unique_id >> 16) & 0xFF) | 0xAA; 126 rdm_response_msg[15] = ((my_unique_id >> 16) & 0xFF) | 0x55; 127 rdm_response_msg[16] = ((my_unique_id >> 8) & 0xFF) | 0xAA; 128 rdm_response_msg[17] = ((my_unique_id >> 8) & 0xFF) | 0x55; 129 rdm_response_msg[18] = ((my_unique_id >> 0) & 0xFF) | 0xAA; 130 rdm_response_msg[19] = ((my_unique_id >> 0) & 0xFF) | 0x55; 131 uint16_t crc = calc_crc(&rdm_response_msg[8], 12); 132 rdm_response_msg[20] = ((crc >> 8) & 0xFF) | 0xAA; 133 rdm_response_msg[21] = ((crc >> 8) & 0xFF) | 0x55; 134 rdm_response_msg[22] = ((crc >> 0) & 0xFF) | 0xAA; 135 rdm_response_msg[23] = ((crc >> 0) & 0xFF) | 0x55; 136 bsp_xmit_to_dmx_bus(); 137 Uart_XmitDmxSlotValues(rdm_response_msg, 24, 0/*NO BREAK*/, 4, true); 138 bsp_recv_from_dmx_bus(); 139 } 140 141 static void send_rdm_msg(uint8_t *rdm_msg, uint8_t command_class, uint8_t data_len) 142 { 143 uint8_t count = 24 + data_len; 144 145 // Remark: Parameter Data must be filled by the caller of this function 146 bsp_delay_usec(150); 147 rdm_response_msg[0] = SC_RDM; 148 rdm_response_msg[1] = SC_SUB_MESSAGE; 149 rdm_response_msg[2] = count; 150 rdm_response_msg[3] = rdm_msg[9]; // copy destination from received msg 151 rdm_response_msg[4] = rdm_msg[10]; 152 rdm_response_msg[5] = rdm_msg[11]; 153 rdm_response_msg[6] = rdm_msg[12]; 154 rdm_response_msg[7] = rdm_msg[13]; 155 rdm_response_msg[8] = rdm_msg[14]; 156 rdm_response_msg[9] = ((MAN_ID >> 8) & 0xFF); 157 rdm_response_msg[10] = ((MAN_ID >> 0) & 0xFF); 158 rdm_response_msg[11] = ((my_unique_id >> 24) & 0xFF); 159 rdm_response_msg[12] = ((my_unique_id >> 16) & 0xFF); 160 rdm_response_msg[13] = ((my_unique_id >> 8) & 0xFF); 161 rdm_response_msg[14] = ((my_unique_id >> 0) & 0xFF); 162 rdm_response_msg[15] = rdm_msg[15]; // pass back Transaction Number 163 rdm_response_msg[16] = RESPONSE_TYPE_ACK; 164 rdm_response_msg[17] = rdm_message_count; 165 rdm_response_msg[18] = 0; // Sub-Device MSB 166 rdm_response_msg[19] = 0; // Sub-Device LSB 167 rdm_response_msg[20] = command_class; 168 rdm_response_msg[21] = rdm_msg[21]; // copy PID from received msg 169 rdm_response_msg[22] = rdm_msg[22]; 170 rdm_response_msg[23] = data_len; 171 uint16_t crc = calc_crc(rdm_response_msg, count); 172 rdm_response_msg[count+0] = (crc >> 8) & 0xFF; 173 rdm_response_msg[count+1] = (crc >> 0) & 0xFF; 174 bsp_xmit_to_dmx_bus(); 175 Uart_XmitDmxSlotValues(rdm_response_msg, (count + 2), 176 break_time, mab_time, true); 177 bsp_recv_from_dmx_bus(); 178 } 179 180 static inline void send_disc_mute_response(uint8_t *rdm_msg) 181 { 182 // no binding uid, only the control field 183 rdm_response_msg[24] = 0; 184 rdm_response_msg[25] = 0; 185 send_rdm_msg(rdm_msg, DISCOVERY_COMMAND_RESPONSE, 2); 186 } 187 188 static inline void send_disc_un_mute_response(uint8_t *rdm_msg) 189 { 190 send_disc_mute_response(rdm_msg); 191 } 192 193 static inline void send_get_device_info_response(uint8_t *rdm_msg) 194 { 195 rdm_response_msg[24] = 0x01; // RDM Protocol Version MSB 196 rdm_response_msg[25] = 0x00; // RDM Protocol Version LSB 197 rdm_response_msg[26] = DEVICE_MODEL_ID1; 198 rdm_response_msg[27] = DEVICE_MODEL_ID0; 199 rdm_response_msg[28] = 0x01; // Product Category MSB 200 rdm_response_msg[29] = 0x01; // Product Category LSB 201 rdm_response_msg[30] = SW_VERSION_ID3; 202 rdm_response_msg[31] = SW_VERSION_ID2; 203 rdm_response_msg[32] = SW_VERSION_ID1; 204 rdm_response_msg[33] = SW_VERSION_ID0; 205 rdm_response_msg[34] = 0x00; // DMX512 Footprint MSB 206 rdm_response_msg[35] = DMX512_FOOTPRINT; 207 rdm_response_msg[36] = 0x01; // DMX512 Personality MSB 208 rdm_response_msg[37] = 0x01; // DMX512 Personality LSB 209 rdm_response_msg[38] = (my_dmx_start_address >> 8) & 0xFF; // DMX512 Start Address MSB 210 rdm_response_msg[39] = (my_dmx_start_address >> 0) & 0xFF; // DMX512 Start Address LSB 211 rdm_response_msg[40] = 0x00; // Sub-Device Count MSB 212 rdm_response_msg[41] = 0x00; // Sub-Device Count LSB 213 rdm_response_msg[42] = 0x00; // Sensor Count 214 send_rdm_msg(rdm_msg, GET_COMMAND_RESPONSE, 19); 215 } 216 217 static inline void send_get_software_version_response(uint8_t *rdm_msg) 218 { 219 rdm_response_msg[24] = 'N'; 220 rdm_response_msg[25] = 'X'; 221 rdm_response_msg[26] = 'P'; 222 rdm_response_msg[27] = ' '; 223 rdm_response_msg[28] = 'L'; 224 rdm_response_msg[29] = 'P'; 225 rdm_response_msg[30] = 'C'; 226 rdm_response_msg[31] = '1'; 227 rdm_response_msg[32] = '1'; 228 rdm_response_msg[33] = '1'; 229 rdm_response_msg[34] = '4'; 230 rdm_response_msg[35] = ' '; 231 rdm_response_msg[36] = 'D'; 232 rdm_response_msg[37] = 'M'; 233 rdm_response_msg[38] = 'X'; 234 rdm_response_msg[39] = '5'; 235 rdm_response_msg[40] = '1'; 236 rdm_response_msg[41] = '2'; 237 rdm_response_msg[42] = ' '; 238 rdm_response_msg[43] = 's'; 239 rdm_response_msg[44] = 'l'; 240 rdm_response_msg[45] = 'a'; 241 rdm_response_msg[46] = 'v'; 242 rdm_response_msg[47] = 'e'; 243 send_rdm_msg(rdm_msg, GET_COMMAND_RESPONSE, 24); 244 } 245 246 static inline void send_get_dmx_start_address_response(uint8_t *rdm_msg) 247 { 248 rdm_response_msg[24] = (my_dmx_start_address >> 8) & 0xFF; 249 rdm_response_msg[25] = (my_dmx_start_address >> 0) & 0xFF; 250 send_rdm_msg(rdm_msg, GET_COMMAND_RESPONSE, 2); 251 } 252 253 static inline void send_get_identify_device_response(uint8_t *rdm_msg, uint8_t state) 254 { 255 rdm_response_msg[24] = state; 256 send_rdm_msg(rdm_msg, GET_COMMAND_RESPONSE, 1); 257 } 258 259 static inline void send_set_dmx_start_address_response(uint8_t *rdm_msg) 260 { 261 send_rdm_msg(rdm_msg, SET_COMMAND_RESPONSE, 0); 262 } 263 264 static inline void send_set_identify_device_response(uint8_t * rdm_msg) 265 { 266 send_rdm_msg(rdm_msg, SET_COMMAND_RESPONSE, 0); 267 } 268 269 static inline bool check_broadcast(uint8_t * msg) 270 { 271 if ((msg[5] == 0xFF) && (msg[6] == 0xFF) && 272 (msg[7] == 0xFF) && (msg[8] == 0xFF)) 273 { 274 if (((msg[3] == 0xFF) && (msg[4] == 0xFF)) || 275 ((msg[3] == ((MAN_ID >> 8) & 0xFF)) && 276 (msg[4] == ((MAN_ID >> 0) & 0xFF)))) 277 { 278 return true; 279 } 280 } 281 return false; 282 } 283 284 static inline bool check_own_uid(uint8_t * msg) 285 { 286 if ((msg[3] == ((MAN_ID >> 8) & 0xFF)) && 287 (msg[4] == ((MAN_ID >> 0) & 0xFF)) && 288 (msg[5] == ((my_unique_id >> 24) & 0xFF)) && 289 (msg[6] == ((my_unique_id >> 16) & 0xFF)) && 290 (msg[7] == ((my_unique_id >> 8) & 0xFF)) && 291 (msg[8] == ((my_unique_id >> 0) & 0xFF))) 292 { 293 return true; 294 } 295 return false; 296 } 297 298 static inline void handle_rdm_msg(uint8_t *rdm_msg) 299 { 300 static bool rdm_muted = false; 301 302 /* check sub start code in RDM Packet and minimum lenght */ 303 if ((rdm_msg[1] == SC_SUB_MESSAGE) && (rdm_msg[2] >= 24)) 304 { 305 uint8_t len = rdm_msg[2]; 306 uint16_t crc = ((uint16_t)rdm_msg[len+0] << 8) | rdm_msg[len+1]; 307 308 if (calc_crc(rdm_msg, len) != crc) return; 309 310 bool broadcast = check_broadcast(rdm_msg); 311 bool own_uid = check_own_uid(rdm_msg); 312 313 if (!broadcast && !own_uid) return; 314 315 uint16_t pid = ((uint16_t)rdm_msg[21] << 8) | rdm_msg[22]; 316 317 /* check command class (CC) */ 318 switch (rdm_msg[20]) 319 { 320 case DISCOVERY_COMMAND: 321 /* check parameter ID (PID) */ 322 if ((pid == DISC_UNIQUE_BRANCH) && (len == 36)) 323 { 324 if (!rdm_muted) 325 { 326 long long lower_bound_uid; 327 long long upper_bound_uid; 328 329 lower_bound_uid = rdm_msg[24]; 330 lower_bound_uid <<= 8; 331 lower_bound_uid |= rdm_msg[25]; 332 lower_bound_uid <<= 8; 333 lower_bound_uid |= rdm_msg[26]; 334 lower_bound_uid <<= 8; 335 lower_bound_uid |= rdm_msg[27]; 336 lower_bound_uid <<= 8; 337 lower_bound_uid |= rdm_msg[28]; 338 lower_bound_uid <<= 8; 339 lower_bound_uid |= rdm_msg[29]; 340 341 upper_bound_uid = rdm_msg[30]; 342 upper_bound_uid <<= 8; 343 upper_bound_uid |= rdm_msg[31]; 344 upper_bound_uid <<= 8; 345 upper_bound_uid |= rdm_msg[32]; 346 upper_bound_uid <<= 8; 347 upper_bound_uid |= rdm_msg[33]; 348 upper_bound_uid <<= 8; 349 upper_bound_uid |= rdm_msg[34]; 350 upper_bound_uid <<= 8; 351 upper_bound_uid |= rdm_msg[35]; 352 353 if ((my_uid >= lower_bound_uid) && (my_uid <= upper_bound_uid)) 354 { 355 send_disc_response(rdm_msg); 356 } 357 } 358 } 359 else if ((pid == DISC_MUTE) && (len == 24)) 360 { 361 rdm_muted = true; 362 if (own_uid) send_disc_mute_response(rdm_msg); 363 } 364 else if ((pid == DISC_UN_MUTE) && (len == 24)) 365 { 366 rdm_muted = false; 367 if (own_uid) send_disc_un_mute_response(rdm_msg); 368 } 369 break; 370 case GET_COMMAND: 371 if (own_uid) 372 { 373 if ((pid == DEVICE_INFO) && (len == 24)) 374 { 375 send_get_device_info_response(rdm_msg); 376 } 377 else if ((pid == SOFTWARE_VERSION_LABEL) && (len == 24)) 378 { 379 send_get_software_version_response(rdm_msg); 380 } 381 else if ((pid == DMX_START_ADDRESS) && (len == 24)) 382 { 383 send_get_dmx_start_address_response(rdm_msg); 384 } 385 else if ((pid == IDENTIFY_DEVICE) && (len == 24)) 386 { 387 send_get_identify_device_response(rdm_msg, identify_state); 388 } 389 } 390 break; 391 case SET_COMMAND: 392 if ((pid == DMX_START_ADDRESS) && (len == 26)) 393 { 394 my_dmx_start_address = ((uint16_t)rdm_msg[24] << 8) | rdm_msg[25]; 395 if (own_uid) send_set_dmx_start_address_response(rdm_msg); 396 } 397 else if ((pid == IDENTIFY_DEVICE) && (len == 25)) 398 { 399 identify_state = rdm_msg[24]; 400 if (identify_state) 401 { 402 dim_leds(255,255,255,255); 403 #ifdef SUPPORT_I2C_BUS 404 lcd_update("You found me :-)"); 405 #endif 406 } 407 else 408 { 409 dim_leds(0,0,0,0); 410 #ifdef SUPPORT_I2C_BUS 411 lcd_update(""); 412 #endif 413 } 414 if (own_uid) send_set_identify_device_response(rdm_msg); 415 } 416 break; 417 default: 418 break; 419 } 420 } 421 } 422 #endif 423 424 /******************************************************************************* 425 * global functions 426 ******************************************************************************/ 427 428 int main (void) 429 { 430 bool communication_lost = false; 431 bool not_addressed = false; 432 uint16_t dmx_len; 433 uint8_t *pslot_values; 434 uint8_t busyled_state = 0; 435 436 SystemInit(); 437 bsp_init(); 438 439 bsp_control_led(0,0); /* on startup turn on traffic led to check proper working */ 440 init_globals(); 441 #ifdef SUPPORT_MANUAL_CONTROL 442 init_manual_ctrl(); 443 #endif 444 #ifdef SUPPORT_I2C_BUS 445 lcd_update("NXP LPC1114 DMX512 slave"); /* startup msg on LCD */ 446 #endif 447 Uart_LoopBackTest(true); 448 while(1) 449 { 450 // blocking read for 1000 milli seconds 451 dmx_len = Uart_RecvDmxSlotValues(&pslot_values, true, 1000); 452 if (dmx_len > 0) 453 { 454 if (communication_lost || not_addressed) 455 { 456 communication_lost = false; 457 not_addressed = false; 458 #ifdef SUPPORT_I2C_BUS 459 if (pslot_values[0] != SC_TEXT) lcd_update(""); 460 #endif 461 } 462 #ifndef VALIDATE_PERFORMANCE_ON_MAX_DMX_BUS_LOAD 463 busyled_state ^= 1; 464 bsp_control_led(0, busyled_state); 465 #endif 466 /* Check the start code */ 467 if (pslot_values[0] == SC_NULL) 468 { 469 #ifndef SUPPORT_RDM_OVER_DMX512 470 my_dmx_start_address = get_my_slot_nrs(); 471 #endif 472 if (dmx_len > my_dmx_start_address + 0) 473 { 474 uint8_t mySlotValues[DMX512_FOOTPRINT] = {0,0,0,0}; 475 mySlotValues[0] = pslot_values[my_dmx_start_address + 0]; 476 if (dmx_len > my_dmx_start_address + 1) 477 mySlotValues[1] = pslot_values[my_dmx_start_address + 1]; 478 if (dmx_len > my_dmx_start_address + 2) 479 mySlotValues[2] = pslot_values[my_dmx_start_address + 2]; 480 if (dmx_len > my_dmx_start_address + 3) 481 mySlotValues[3] = pslot_values[my_dmx_start_address + 3]; 482 dim_leds(mySlotValues[0], mySlotValues[1], 483 mySlotValues[2], mySlotValues[3]); 484 #ifdef VALIDATE_PERFORMANCE_ON_MAX_DMX_BUS_LOAD 485 bsp_control_led(0, ~mySlotValues[3]); 486 #endif 487 } 488 else 489 { 490 not_addressed = true; 491 dim_leds(0,0,0,0); 492 #ifdef SUPPORT_I2C_BUS 493 lcd_update("Not addressed byDMX512 master"); 494 #endif 495 } 496 } 497 #ifdef SUPPORT_I2C_BUS 498 else if (pslot_values[0] == SC_TEXT) 499 { /* minimal length of msg must be 4 bytes(=slots) */ 500 if (dmx_len >= 4) 501 { 502 lcd_update((char *)(pslot_values+3)); 503 } 504 } 505 #endif 506 #ifdef SUPPORT_RDM_OVER_DMX512 507 else if (pslot_values[0] == SC_RDM) 508 { 509 handle_rdm_msg(pslot_values); 510 } 511 #endif 512 } 513 else 514 { /* nothing received in 1 second, switch off the leds */ 515 communication_lost = true; 516 #ifdef SUPPORT_RDM_OVER_DMX512 517 if (!identify_state) 518 #endif 519 { 520 dim_leds(0,0,0,0); 521 #ifdef SUPPORT_I2C_BUS 522 lcd_update("No packets from DMX512 master"); 523 #endif 524 } 525 } 526 #ifdef SUPPORT_MANUAL_CONTROL 527 check_manual_ctrl(); 528 #endif 529 WDT_Feed(); 530 } 531 } 532 533 void dim_leds(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4) 534 { 535 Timer_PWM_Set_Duty_Cycle(CT16B0, CTMAT0, value1); 536 Timer_PWM_Set_Duty_Cycle(CT16B0, CTMAT1, value2); 537 Timer_PWM_Set_Duty_Cycle(CT16B1, CTMAT0, value3); 538 Timer_PWM_Set_Duty_Cycle(CT16B1, CTMAT1, value4); 539 } 540 541 void get_version_string(char *pstr) 542 { 543 #ifdef SUPPORT_MANUAL_CONTROL 544 strcpy(pstr, FIRMWARE_VERSION); 545 #endif 546 } 547 548 549 /* EOF */ 550 551