-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
executable file
·412 lines (362 loc) · 13 KB
/
main.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
//************************************************************************************
//
// This source is Copyright (c) 2011 by Computer Inspirations. All rights reserved.
// You are permitted to modify and use this code for personal use only.
//
//************************************************************************************
/**
* \file main.c
* \details This module implements the top-level RGBW user interface and responds to
* pushbutton presses and/or the RS-485 command interface while also cycling
* through the currently-defined sequences. Depending on the state of the
* \em STARTSEQADD location in internal EEPROM, either a set of macros will
* be executed from internal EEPROM that point to the actual sequences in
* external EEPROM or a contiguous run of sequences in external EEPROM will
* be executed directly.
* Pushbuttons can be used to define the macros (see below) or put the
* RGBW hardware into a sleep mode (holding PB2 for 5 secs). By default,
* all the sequences in external EEPROM will be sequentially executed.
* \author Michael Griebling
* \date 10 Nov 2011
*/
//************************************************************************************
#include <xc.h>
// PIC16F1829 Configuration Bit Settings
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
#include "Types.h"
#include "SBUS.h"
#include "PWM.h"
#include "Pushbuttons.h"
#include "Sequences.h"
#include "NightSense.h"
#include "MemoryMap.h"
#include "Macros.h"
#include "EEPROM.h"
#include <stdlib.h>
// Temporarily define FLASHCOPY to initialize the external EEPROM with the contents
// of the Sequences.inc file. Two blue flashes indicate the programming is done.
// Once the EEPROM is programmed, comment out the FLASHCOPY define to restore normal
// program functions. This kludge is necessary because both the program and sequences
// can't fit into Flash at the same time.
//#define FLASHCOPY
#ifdef FLASHCOPY
#include "Sequences.inc"
#endif
#define FW_VERSION (2)
// Initial internal EEPROM default contents
// Default data definitions for internal EEPROM:
// state = Night mode on,
// offDelayTime = 5 mins,
// onDelayTime = 5 mins,
// duration = 360 mins = 6 hrs
// start Sequence = 0
// last Sequence = 61
// device Address = FF
// macro area blank (no macros to play)
__EEPROM_DATA(0x01, 0x05, 0x05, 0x01, 0x68, 0x00, 0x00, 0x00); // Internal state variables - 16 bytes
__EEPROM_DATA(61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
__EEPROM_DATA(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); // EEPROM macro sequences - 200 bytes
unsigned int activeSequence; // active sequence to play
unsigned int maxAddress, minAddress; // sequence start and end address
BOOL override; // override outputs via SBUS
BOOL playMacros; // play EEPROM macros if TRUE
// Wait for Sequence to finish playing while also scanning the pushbuttons and
// handling any external commands
BOOL Scan (void) {
unsigned int i;
do {
PushButtons_Scan(); // update pushbutton status
for (i=0; i<10; i++) {
SBUS_Process_Command(); // handle protocol commands
__delay_ms(1);
}
if (PushButtons_Active(BUTTON1|BUTTON2)) return TRUE;
// if (PushButtons_Active(BUTTON2)) return TRUE;
} while (PWM_Busy());
return FALSE;
}
void ShowNumber (unsigned int version) {
while (version > 0) {
PWM_Ramp (0, 0, 255, 0, 0, 5); // Flash blue
Scan();
PWM_Ramp (0, 0, 0, 0, 0, 20); // Off
Scan();
version--;
}
// Channel test sequence
PWM_Ramp (255, 0, 0, 0, 0, 5); // Flash red
Scan();
PWM_Ramp (0, 0, 0, 255, 0, 5); // Flash white
Scan();
PWM_Ramp (0, 255, 0, 0, 0, 5); // Flash green
Scan();
PWM_Ramp (0, 0, 255, 0, 0, 5); // Flash blue
Scan();
PWM_Ramp (0, 0, 0, 0, 0, 5); // Off
Scan();
}
void ConfirmCommand (void) {
PWM_Set (0, 0, 255, 0); // Blue flash
__delay_ms(500);
PWM_Set (0, 0, 0, 0);
__delay_ms(250);
}
void Error (void) {
PWM_Set (255, 0, 0, 0); // Red flash
__delay_ms(2000);
PWM_Set (0, 0, 0, 0);
__delay_ms(250);
}
// Play the 'sequence' numbered FLASH or EEPROM sequence.
void PlaySequence (unsigned int sequence) {
BOOL ok;
if (Seq_Find(sequence) != FIND_OK) {
Error(); Scan(); return;
}
do {
PWM_Ramp (Seq_GetPWM(0), Seq_GetPWM(1), Seq_GetPWM(2), Seq_GetPWM(3), Seq_GetFade(), Seq_GetHold());
if (Scan()) {
PWM_Set(0, 0, 0, 0);
return; // handle push buttons
}
ok = Seq_Next(NOREPEAT);
} while ((Seq_GetActive() == sequence) && ok);
}
#ifndef FLASHCOPY
static void InitMode (void) {
unsigned int total;
// Validate the start/total sequence values
activeSequence = ReadWord(STARTSEQADD);
playMacros = FALSE;
if (activeSequence == PLAYMACROS) {
// play back internal EEPROM macros
playMacros = TRUE;
activeSequence = 0;
total = Macros_Count();
} else {
// determine EEPROM maximum
total = Seq_Count();
minAddress = ReadWord(TOTALSEQADD);
if (minAddress < total) total = minAddress;
if (Seq_Find(activeSequence) != FIND_OK || (minAddress == 0)) {
activeSequence = 0;
}
}
minAddress = activeSequence;
maxAddress = activeSequence+total-1;
}
void DefineEEMacros (void) {
unsigned int sequence = 0;
unsigned int prevStart;
PWM_Set (0, 0, 0, 0);
Seq_Find(sequence);
prevStart = ReadWord(STARTSEQADD);
if (prevStart == PLAYMACROS) prevStart = 0;
do {
PlaySequence(sequence);
if (PushButtons_Pressed(BUTTON1)) {
// advance to next sequence
PWM_Set (0, 0, 0, 0);
PushButtons_Clear(BUTTON1);
sequence++;
if (sequence >= Seq_Count()) sequence = 0;
Seq_Find(sequence);
}
if (PushButtons_Pressed(BUTTON2)) {
// add sequence to EEPROM
PWM_Set (0, 0, 0, 0);
PushButtons_Clear(BUTTON2);
if (Macros_Add(sequence)) {
ConfirmCommand();
} else Error();
}
} while (!PushButtons_Held(BUTTON2));
PushButtons_Clear(BUTTON2);
if (Macros_Count() != 0) {
WriteWord(STARTSEQADD, PLAYMACROS); // enable macro playback
} else {
// restore previous playback mode
WriteWord(STARTSEQADD, prevStart); // enable normal playback
}
ConfirmCommand();
ConfirmCommand();
InitMode();
}
static void DoSleep (void) {
while (PWM_Busy()); // wait for PWM to complete
PWM_Set(0, 0, 0, 0);
__delay_ms(50);
TRISBbits.TRISB4 = 1; // change SDA to input temporarily
TRISBbits.TRISB6 = 1; // change SCL to input temporarily
TRISAbits.TRISA0 = 1; // temporarily make JTAG pins inputs
TRISAbits.TRISA1 = 1;
WPUAbits.WPUA0 = 1; // enable pull-ups
WPUAbits.WPUA1 = 1;
IOCANbits.IOCAN0 = 1; // enable interrupt on negative edge on pin A0
TRISBbits.TRISB5 = 1; // Set as pulled up digital inputs
WPUBbits.WPUB5 = 1;
TMR4IE = 0; // Disable Timer4 interrupts
TMR6IE = 0; // Disable Timer6 interrupts
FVRCON = 0; // Disable voltage reference
IOCIE = 1; // Enable I/O interrupts
//*************************************************************************************
SLEEP(); // processor goes into sleep mode and clears watchdog
//*************************************************************************************
NOP();
IOCIE = 0;
SBUS_Init();
PWM_Init();
PushButtons_Init();
NightSense_Init();
ConfirmCommand();
}
#else
extern unsigned char MAGIC[];
void CopyFlashToEEPROM (void) {
unsigned char compare;
unsigned int i;
// Copies the contents of FLASH in Sequences[] to EEPROM
if (EEPROM_Present()) {
// Write Sequences data to external EEPROM
EEPROM_Write(0x0000, (unsigned char *)Sequences, sizeof(Sequences));
// Verify the external EEPROM contents
for (i=0; i<sizeof(Sequences); i++) {
compare = EEPROM_ReadChar(i);
if (compare != Sequences[i]) {
Error();
return; // abort
}
}
EEPROM_Write(EEPROM_GetSize()-2, MAGIC, 2); // initialize EEPROM magic number
// Set up internal EEPROM start address and sequence length
WriteWord(STARTSEQADD, 0x0000); // enable normal playback
WriteWord(TOTALSEQADD, Seq_Count()); // identify how many sequences are defined
ConfirmCommand();
} else {
Error();
}
}
#endif
main() {
// Select the internal 4MHz oscillator
OSCCONbits.IRCF = 0b1101; // 4MHz clock select
OSCCONbits.SCS = 0b11; // Internal oscillator
OSCCONbits.SPLLEN = 0; // x4 PLL disabled
SBUS_Init();
EEPROM_Init();
Macros_Init();
PWM_Init();
PushButtons_Init();
NightSense_Init();
Seq_Init(); // Start out at the first sequence
// opMode = LIGHTING_MODE;
override = FALSE;
// Play FLASH/EEPROM sequences or macros from internal EEPROM, changes operating modes, or define EEPROM macros
#ifndef FLASHCOPY
InitMode();
#else
CopyFlashToEEPROM();
#endif
// Display the firmware version number
ShowNumber(FW_VERSION);
for (;;) {
// if (NightSense_IsNight()) {
// if (opMode == HALLOWEEN_MODE) {
// amp = rand() % 120 + 135;
// delay = rand() % 100;
// mode = rand() % 1000;
// if (mode == 64) {
// delay += 2000;
// PWM_Set (0, 0, 0, 0); // Black
// for (i=0; i<delay; i++) __delay_ms(1);
// } else if (mode == 78) {
// delay += 500;
// PWM_Set (255, 255, 255, 0); // White
// for (i=0; i<delay; i++) __delay_ms(1);
// PWM_Set (0, 0, 0, 0); // Black
// for (i=0; i<delay/2; i++) __delay_ms(1);
// PWM_Set (255, 255, 255, 0); // White
// for (i=0; i<delay/4; i++) __delay_ms(1);
// PWM_Set (0, 0, 0, 0); // Black
// for (i=0; i<delay/2; i++) __delay_ms(1);
// PWM_Set (255, 255, 255, 0); // White
// for (i=0; i<delay/8; i++) __delay_ms(1);
// PWM_Set (0, 0, 0, 0); // Black
// for (i=0; i<delay; i++) __delay_ms(1);
// } else {
// PWM_Set (0, (255*amp)/256, 0, 0); // Green flame
// for (i=0; i<delay; i++) __delay_ms(1);
// }
// } else if (opMode == CHRISTMAS_MODE) {
// PWM_Ramp(255, 0, 0, 0, 0, 254); // Red - 10 secs
// Scan ();
// PWM_Ramp(0, 255, 0, 0, 254, 254); // Green - Fade/Hold
// Scan ();
// PWM_Ramp(0, 0, 255, 0, 254, 254); // Blue - Fade/Hold
// Scan ();
// PWM_Ramp(255, 0, 0, 0, 254, 254); // Red - Fade/Hold
// Scan ();
// } else {
// // normal lighting mode
// PWM_Set (255, 255, 255, 255); // White
// }
//
// // check for mode changes
// PushButtons_Scan(); // update pushbutton status
// __delay_ms(10);
// if (PushButtons_Pressed(BUTTON2)) {
// // Change operating modes
// PushButtons_Clear(BUTTON2);
// ConfirmCommand();
// opMode++;
// if (opMode > LIGHTING_MODE) opMode = 0;
// }
// } else {
// PWM_Ramp (0, 0, 0, 0, 1, 0);
// }
if (NightSense_IsNight()) {
if (!override) {
if (playMacros) PlaySequence(Macros_Read(activeSequence));
else PlaySequence(activeSequence);
if (activeSequence < maxAddress) activeSequence++;
else activeSequence = minAddress;
} else {
Scan();
}
} else {
if (!override) PWM_Ramp (0, 0, 0, 0, 1, 0);
Scan();
}
#ifndef FLASHCOPY
// handle pushbuttons
if (PushButtons_Pressed(BUTTON2)) {
// Change operating modes
PushButtons_Clear(BUTTON2);
ConfirmCommand();
DefineEEMacros();
}
if (PushButtons_Held(BUTTON2)) {
PushButtons_Clear(BUTTON2);
DoSleep();
}
#endif
}
}