Project

General

Profile

Statistics
| Revision:

root / trunk / code / lib / src / libdragonfly / lights.c @ 277

History | View | Annotate | Download (10.5 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26

    
27
/**
28
 * @file ligths.c
29
 * @brief Orbs
30
 *
31
 * Implemenation for the orbs (tri-colored LEDs)
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 * @bug Colors are incorrect, seems to not work with wireless library
35
 **/
36

    
37
/*
38
lights.c
39
Controls orb1 and orb2. Also contains the framework for a software PWM that may be used for servos in the future.
40

41
author: CMU Robotics Club, Colony Project
42

43
Change Log:
44
2.4.07 - Aaron
45
  Revamped orb code so it works.  Need to check interaction with rtc, and tweak some colors.
46

47
2.1.07 - James
48
  Modified sort_buffer() to prune for repeats.  PWM now uses orb_buf_size for the number of orb values in
49
  orb_time_arr[].
50
  Changed sorting algorithm used in sort_buffer() to selection sort (faster). And it works now.
51

52
1.25.07 - KWoo
53
  Deleted old FF+ code to make it cleaner. Commented code. This all works. Note however that if you ever plan to
54
  use the software PWM (which is this) you will need to change the implementation of orb_enable() and orb_disable()
55
  to not shutdown the PWM.
56
*/
57

    
58
#include "lights.h"
59
#include "dragonfly_lib.h"
60
#include <avr/interrupt.h>
61

    
62
#define ORB_RESET 1025
63
#define ORBPORT PORTC
64
#define ORBDDR DDRC
65
#define ORBMASK 0x77
66

    
67
/***** Port and Pin Definitions ****/
68

    
69
//Orb Ports and Registers
70
#define ORB_PORT        PORTC
71
#define ORB_DDR         DDRC
72

    
73
//Orb Pins
74
#define ORB1_RED        0x00
75
#define ORB1_GREEN      0x01
76
#define ORB1_BLUE       0x02
77
#define ORB2_RED        0x04
78
#define ORB2_GREEN      0x05
79
#define ORB2_BLUE       0x06
80

    
81

    
82
#define ORB_COUNT 8 //please dont change this, or bad things might happen
83

    
84
// an orb node
85
struct ORB_NODE {
86
  uint8_t num;
87
  uint16_t angle;
88
};
89

    
90
//the change in an orb
91
struct ORB_CHANGE {
92
  uint16_t port_val;
93
  uint16_t split_time_period;
94
};
95

    
96
// the status of an orb
97
struct ORB_STATUS_STRUCT {
98
  struct ORB_NODE orbs[ORB_COUNT];
99
  uint16_t orb_angles[ORB_COUNT];
100
  struct ORB_CHANGE changes[ORB_COUNT+1];
101
  uint8_t change_count;
102
  uint8_t new_angles;
103
  uint8_t current_orb;
104
} ORB_STATUS;
105

    
106
void orb_sort(void);
107
void orb_setup_pulse(void);
108

    
109
SIGNAL (SIG_OUTPUT_COMPARE3C){
110
  //pull the correct ones down
111
  ORBPORT &= (~ORBMASK)|(ORB_STATUS.changes[ORB_STATUS.current_orb].port_val);
112

    
113
  ++ORB_STATUS.current_orb; //now look at next orb transition
114

    
115
  if (ORB_STATUS.current_orb < ORB_STATUS.change_count) { //if it isnt the end...
116
    //setup timer for next pull down
117
    OCR3C = TCNT3+ORB_STATUS.changes[ORB_STATUS.current_orb].split_time_period;
118
  } else { //we are done with these pulses
119
    orb_setup_pulse();
120
  }
121
}
122

    
123
//sets a channel to a value
124
void orb_set_angle(int orb, int angle) {
125
  uint8_t mysreg;
126

    
127
  orb=orb&0x07; //only have 8
128
  angle=angle&0xff; //only accept 0-255
129
  angle=255-angle; //inverse intensity
130
  angle=angle<<2; //scale up so that we dont run it too often
131
  angle+=3; //0 values dont really work
132

    
133
  if (ORB_STATUS.orb_angles[orb] != angle) { //if the angle has changed
134
    mysreg=SREG;
135
    cli(); //disable interrupts
136
    ORB_STATUS.orb_angles[orb] = angle; //update angle
137
    ORB_STATUS.new_angles = 1;
138
    SREG=mysreg; //put interrupt status back
139
  }
140
}
141

    
142
void orb_sort(void) {
143
  int done = 0, i;
144

    
145
  while (! done) {
146
    done = 1;
147

    
148
    for (i = 0; i < ORB_COUNT - 1; ++i) {  //loop through all
149
      //if they are out of order, swap them
150
      if (ORB_STATUS.orbs[i].angle > ORB_STATUS.orbs[i+1].angle) {
151
        ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
152
        ORB_STATUS.orbs[i+1].angle ^= ORB_STATUS.orbs[i].angle;
153
        ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
154

    
155
        ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
156
        ORB_STATUS.orbs[i+1].num ^= ORB_STATUS.orbs[i].num;
157
        ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
158

    
159
        done = 0;
160
      }
161
    }
162
  }
163
}
164

    
165
//calculate the split times
166
void orb_setup_pulse(void) {
167
  int i;
168
  uint16_t my_port;
169
  uint16_t sum = 0;
170
  uint16_t split_time;
171

    
172
  my_port = 0xff; //all on
173

    
174
  if (ORB_STATUS.new_angles) {
175
    ORB_STATUS.change_count = 0;
176

    
177
    for (i = 0; i < ORB_COUNT; ++i) { //get the new values
178
      ORB_STATUS.orbs[i].angle = ORB_STATUS.orb_angles[ORB_STATUS.orbs[i].num];
179
    }
180

    
181
    orb_sort(); //sort them
182
    ORB_STATUS.new_angles = 0;
183

    
184
    for (i = 0; i < ORB_COUNT; ++i) { //calculate split times
185
      split_time = ORB_STATUS.orbs[i].angle - sum;
186
      my_port &= ~_BV(ORB_STATUS.orbs[i].num);
187

    
188
      for (; i < ORB_COUNT - 1 && ORB_STATUS.orbs[i].angle == ORB_STATUS.orbs[i+1].angle; ++i) {
189
        my_port &= ~_BV(ORB_STATUS.orbs[i+1].num); //look for doups
190
      }
191

    
192
      ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; //which pins are low
193
      ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = split_time;
194

    
195
      ++ORB_STATUS.change_count;
196

    
197
      sum += split_time;
198
    }
199

    
200
    ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port;
201
    ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = ORB_RESET - sum; //get a constant period
202

    
203
    ++ORB_STATUS.change_count;
204
  }
205

    
206
  ORB_STATUS.current_orb = 0;
207

    
208
  ORBPORT |= ORBMASK; //start with all high
209
  OCR3C = TCNT3 + ORB_STATUS.changes[0].split_time_period; //wait for first split
210
}
211

    
212
/**
213
 * @defgroup orbs Orbs
214
 * @brief Functions for controlling the color of the orbs.
215
 *
216
 * Functions for controlling the color and lighting of the orbs.
217
 *
218
 * @{
219
 **/
220

    
221
/**
222
 * Initializes the PWM for Orb control. This must be called before
223
 * the orbs are used for them to function.
224
 **/
225
void orb_init()
226
{
227
  int i;
228
  uint8_t mysreg;
229

    
230
  ORBDDR |= ORBMASK; //all outputs
231

    
232
  mysreg=SREG;
233
  cli(); //turn off interrupts for now
234

    
235
  //init everything
236

    
237
  for (i = 0; i < ORB_COUNT; ++i) {
238
    ORB_STATUS.orbs[i].num = i;
239
    ORB_STATUS.orbs[i].angle = 1023;  //127 is a pretty stupid start angle, but oh well
240
    ORB_STATUS.orb_angles[i] = 1023;
241
  }
242

    
243
  ORB_STATUS.new_angles = 1;
244
  ORB_STATUS.change_count = 0;
245

    
246
  //init timer3
247
  TCCR3A = 0;
248
  TCCR3B = _BV(CS31); //prescale = 8
249
  TCCR3C = 0;
250
  ETIMSK |= _BV(OCIE3C); //turn on oc3c interrupt
251
  OCR3C = TCNT3+ORB_RESET;
252

    
253
  SREG=mysreg;
254
}
255

    
256
/**
257
 * Set both orbs to the color specified. orb_init must
258
 * be called before this function may be used.
259
 *
260
 * @param red_led the red component of the color
261
 * @param green_led the green component of the color
262
 * @param blue_led the blue component of the color
263
 *
264
 * @see orb_init
265
 **/
266
void orb_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
267
  orb1_set(red_led,green_led,blue_led);
268
  orb2_set(red_led,green_led,blue_led);
269
}
270

    
271
/**
272
 * Set orb1 to the color specified. orb_init must
273
 * be called before this function may be used.
274
 *
275
 * @param red_led the red component of the color
276
 * @param green_led the green component of the color
277
 * @param blue_led the blue component of the color
278
 *
279
 * @see orb_init
280
 **/
281
void orb1_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
282
  orb_set_angle(0,red_led);
283
  orb_set_angle(1,green_led);
284
  orb_set_angle(2,blue_led);
285
}
286

    
287
/**
288
 * Set orb2 to the color specified. orb_init must
289
 * be called before this function may be used.
290
 *
291
 * @param red_led the red component of the color
292
 * @param green_led the green component of the color
293
 * @param blue_led the blue component of the color
294
 *
295
 * @see orb_init
296
 **/
297
void orb2_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
298
  orb_set_angle(4,red_led);
299
  orb_set_angle(5,green_led);
300
  orb_set_angle(6,blue_led);
301
}
302

    
303
/**
304
 * Set both orbs to the specified color. This function
305
 * is intended to be used with the predefined
306
 * colors. orb_init must be called before this
307
 * function may be used.
308
 *
309
 * @param col the color to set the orbs to
310
 *
311
 * @see orb_init
312
 **/
313
void orb_set_color(int col)
314
{
315
  int red, green, blue;
316

    
317
  red = ((col & 0xE0) >> 5) * 36;
318
  green = ((col & 0x1C) >> 2) * 36;
319
  blue = (col & 0x03) * 85;
320

    
321
  orb_set(red, green, blue);
322
}
323

    
324
/**
325
 * Set orb1 to the specified color. This function
326
 * is intended to be used with the predefined
327
 * colors. orb_init must be called before this
328
 * function may be used.
329
 *
330
 * @param col the color to set the orbs to
331
 *
332
 * @see orb_init
333
 **/
334
void orb1_set_color(int col)
335
{
336
  int red, green, blue;
337

    
338
  red = ((col & 0xE0) >> 5) * 36;
339
  green = ((col & 0x1C) >> 2) * 36;
340
  blue = (col & 0x03) * 85;
341

    
342
  orb1_set(red, green, blue);
343
}
344

    
345
/**
346
 * Set orb2 to the specified color. This function
347
 * is intended to be used with the predefined
348
 * colors. orb_init must be called before this
349
 * function may be used.
350
 *
351
 * @param col the color to set the orbs to
352
 *
353
 * @see orb_init
354
 **/
355
void orb2_set_color(int col)
356
{
357
  int red, green, blue;
358

    
359
  red = ((col & 0xE0) >> 5) * 36;
360
  green = ((col & 0x1C) >> 2) * 36;
361
  blue = (col & 0x03) * 85;
362

    
363
  orb2_set(red, green, blue);
364
}
365

    
366
//DOES THIS WORK?
367
// Disables the timer1 interrupt, disabling the Orb's color fading capabilities
368
// You can still turn the red, green, and blue leds on and off with set_orb_dio
369
/* If we use the PWM for anything else besides the ORB, this implementation needs to be done better */
370
/**
371
 * Disables the orb color fading capabilities
372
 * by disabling the timer1 interrupt.
373
 *
374
 * @see orb_init
375
 **/
376
void orb_disable()
377
{
378
  TCCR3B &= 0;    //Turn off everything
379
  ORB_PORT |= _BV(ORB1_RED);
380
  ORB_PORT |= _BV(ORB1_GREEN);
381
  ORB_PORT |= _BV(ORB1_BLUE);
382
  ORB_PORT |= _BV(ORB2_RED);
383
  ORB_PORT |= _BV(ORB2_GREEN);
384
  ORB_PORT |= _BV(ORB2_BLUE);
385
}
386

    
387
//DOES THIS WORK?
388
// Enables the timer1 interrupt, enabling the Orb's color fading capabilities
389
/**
390
 * Enables the orb's color fading capabilities.
391
 *
392
 * @see orb_init
393
 **/
394
void orb_enable()
395
{
396
//  TCCR0 |= _BV(COM01) | _BV(COM00)  | _BV(WGM00) | _BV(CS01); //Toggle OC Pin on match, FAST PWM Mode, clock/8
397
  TCCR3B =_BV(CS31);
398
}
399

    
400
/** @} **/ //end group