-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.c
174 lines (138 loc) · 3.57 KB
/
Program.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
#include "ColourTime.h"
#include "Program.h"
#include <stdbool.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
enum program_addr_space current_addrspace = ADDR_ROM;
// Space to permanently store instructions
#define ROM_SIZE 512
uint8_t rom[ROM_SIZE] EEMEM = {
OP_FADE_RGB, 0xcc, 0x00, 0x00, 0x00, 0x40,
OP_FADE_RGB, 0xee, 0x00, 0x00, 0x00, 0x20,
OP_FADE_RGB, 0xcc, 0x00, 0x00, 0x00, 0x20,
OP_FADE_RGB, 0xdd, 0x00, 0x00, 0x00, 0x40,
OP_FADE_RGB, 0xcc, 0x00, 0x00, 0x00, 0x40,
OP_WAIT, 0x04, 0x00,
OP_GOTO, 0x00, 0x00,
OP_FADE_HSV, 0xff, 0xff, 0xff, 0x20, 0x00,
OP_SET_HSV, 0x00, 0xff, 0xff,
OP_GOTO, 0x00, 0x24
};
unsigned int rom_size = ROM_SIZE;
uint8_t *ram_base;
unsigned int ram_size = 0;
// Begin execution at start of rom
uint8_t *instruction = rom;
void program_init(void) {
program_step();
}
void callback_colour_finished(void) {
program_step();
}
uint8_t read_byte(void) {
if(current_addrspace == ADDR_ROM) {
if(instruction < rom || instruction >= (rom + ROM_SIZE)) {
// TODO: error
return 0x00;
}
return eeprom_read_byte(instruction++);
} else {
// TODO: sanity check
if(instruction < ram_base || instruction >= (ram_base + ram_size)) {
// TODO: error
return 0x00;
}
return *(instruction++);
}
}
void program_execute(uint8_t *program, unsigned int size) {
// Being interrupted here would probably lead to inconsistencies
cli();
ram_base = program;
ram_size = size;
// Set execution to begin of buffer
instruction = ram_base;
current_addrspace = ADDR_RAM;
// Execute to first blocking operation
program_step();
// Re-enable interrupts
sei();
}
void program_step(void) {
struct rgb_colour colour_rgb;
struct hsv_colour colour_hsv;
uint16_t param = 0;
switch((enum program_opcode) read_byte()) {
case OP_HALT:
instruction--;
return;
case OP_SET_RGB:
colour_rgb.red = read_byte();
colour_rgb.green = read_byte();
colour_rgb.blue = read_byte();
set_rgb(colour_rgb);
// immediatly execute next step - since
program_step();
break;
case OP_SET_HSV:
colour_hsv.hue = read_byte();
colour_hsv.saturation = read_byte();
colour_hsv.value = read_byte();
set_hsv(colour_hsv);
// immediatly execute next step - since
program_step();
break;
case OP_FADE_RGB:
colour_rgb.red = read_byte();
colour_rgb.green = read_byte();
colour_rgb.blue = read_byte();
// Duration
param |= (read_byte() << 8) | read_byte();
fade_rgb(colour_rgb, param);
break;
case OP_FADE_HSV:
colour_hsv.hue = read_byte();
colour_hsv.saturation = read_byte();
colour_hsv.value = read_byte();
// Duration
param |= (read_byte() << 8) | read_byte();
fade_hsv(colour_hsv, param);
break;
case OP_WAIT:
// Duration
param |= (read_byte() << 8) | read_byte();
wait(param);
break;
case OP_GOTO_ROM:
// Target offset
param |= (read_byte() << 8) | read_byte();
current_addrspace = ADDR_ROM;
instruction = rom + param;
program_step();
break;
case OP_GOTO:
// Target offset
param |= (read_byte() << 8) | read_byte();
if(current_addrspace == ADDR_ROM) {
instruction = rom + param;
} else {
instruction = ram_base + param;
}
program_step();
break;
case OP_WRITE_ROM:
// read offset at which to store new values
param |= (read_byte() << 8) | read_byte();
uint8_t *write_pos = rom + param;
// Write n bytes
for(param = read_byte(); param > 0; param--) {
if(write_pos < rom || write_pos >= (rom + rom_size))
break;
eeprom_write_byte(write_pos++, read_byte());
}
program_step();
break;
default:
break;
}
}