-
Notifications
You must be signed in to change notification settings - Fork 0
/
DMX.c
125 lines (108 loc) · 4.16 KB
/
DMX.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//
// DMX.c
// HeadMaster
//
// Created by Kevan Ahlquist on 11/8/12.
// Copyright (c) 2013 Tesla Works. MIT license.
//
#include "DMX.h"
#include <xc.h>
// =============================================================================
// Types
// =============================================================================
typedef enum _DMXState {
DMXWaitBreak,
DMXGotBreak,
DMXWaitForStart,
DMXWaitForData,
DMXDone
} DMXState;
// =============================================================================
// Code
// =============================================================================
void DMXSetup(void);
void DMXReceive(DMXDevice *device);
void DMXSetup(void)
{
TRISCbits.TRISC7 = 1; // Allow the EUSART RX to control pin RC7
TRISCbits.TRISC6 = 1; // Allow the EUSART TX to control pin RC6
BAUDCONbits.BRG16 = 1; // Enable EUSART for 16-bit asynchronos operation
TXSTA = 0x04; // Enable transmission and CLEAR high baud rate
RCSTA = 0x90; // Enable serial port and reception
// Set up serial port baud rate of 250 kHz (DMX) with 40 MHz Fosc
SPBRGH = 0;
SPBRG = 39;
}
void DMXReceive(DMXDevice *device)
{
DMXState state = DMXWaitBreak;
int startCounter = 0;
int bufferIndex = 0;
char tmp;
// Cache device characteristics for performance
// Only FSR is available for pointers. We cache these so we can reserve the pointer FSR for using dmxBuffer
char *dmxBuffer = device->buffer;
int startChannel = device->startChannel;
int bufferSize = device->bufferSize;
while (state != DMXDone) {
switch (state) {
case DMXWaitBreak:
// Throw away good data - we aren't ready to start yet!
if (PIR1bits.RCIF) {
tmp = RCREG;
}
// We are waiting for our break signal, which we detect with a framing error
if (RCSTAbits.FERR) {
state = DMXGotBreak;
} else if (RCSTAbits.OERR) {
RCSTAbits.CREN = 0; // Toggling CREN clears OERR flag
RCSTAbits.CREN = 1;
}
break;
case DMXGotBreak:
tmp = RCREG; // Read the receive buffer to clear FERR - just has junk data anyway
state = DMXWaitForStart;
break;
case DMXWaitForStart:
while (!PIR1bits.RCIF) ; // Wait until a byte has been received
if (RCSTAbits.FERR) {
state = DMXGotBreak;
break;
}
tmp = RCREG; // Read the receive buffer
if (tmp != DMX_START_CODE) { // If current byte isn't START code, ignore the frame
state = DMXWaitBreak;
break;
} else {
startCounter = 0; // Initialize counter
bufferIndex = 0;
state = DMXWaitForData;
break;
}
case DMXWaitForData:
// If a new framing error is detected (error or short frame) the rest of the frame
// is ignored and a new synchronization is attempted
if (RCSTAbits.FERR) {
state = DMXWaitBreak;
break;
}
if (PIR1bits.RCIF) { // Wait until a byte is correctly received
if (startCounter < startChannel) {
tmp = RCREG; // Clear RCIF
startCounter++;
} else if (bufferIndex < bufferSize) {
dmxBuffer[bufferIndex] = RCREG;
bufferIndex++;
} else {
state = DMXDone;
}
}
break;
case DMXDone:
return;
default:
// You're in no man's land now
break;
}
}
}