Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp
- Committer:
- juliogerchman
- Date:
- 2013-09-21
- Revision:
- 8:77fd54b4864c
- Parent:
- 6:62c9a5483a84
- Parent:
- 7:e3b6f5741d9d
- Child:
- 9:c3d4c7059979
- Child:
- 10:01eb82c2a01b
File content as of revision 8:77fd54b4864c:
#include <queue>
#include <algorithm>
#include "mbed.h"
DigitalOut myled(LED1);
DigitalOut led2(LED2);
Serial pc(USBTX, USBRX);
SPI spi(p5, p6, p20); // mosi, miso, sclk
DigitalOut latch(p16);
DigitalOut strobe(p17);
Ticker g_ticker;
#define LENGTH 160
uint8_t strip[160];
#define BLACK 0x80
#define BLUE (BLACK | 0x10)
#define RED (BLACK | 0x04)
#define GREEN (BLACK | 0x01)
#define YELLOW (RED | GREEN)
#define CYAN (GREEN | BLUE)
#define MAGENTA (RED | BLUE)
#define WHITE (RED | GREEN | BLUE)
#define FAST 0x40
uint8_t fade_result[] =
{0, 2, 3, 1};
uint8_t google_colors[] = {BLUE, RED, YELLOW, BLUE, GREEN, RED};
uint8_t getbit(uint8_t from, uint8_t to)
{
return fade_result[((from&1) << 1) | (to & 1)];
}
uint8_t getcolor(uint8_t from, uint8_t to)
{
uint8_t result = 0x80;
result |= getbit(from >> 0, to >> 0) << 0;
result |= getbit(from >> 2, to >> 2) << 2;
result |= getbit(from >> 4, to >> 4) << 4;
return result;
}
void write_strip(uint8_t* data, int len)
{
latch = 0;
for (int i = len - 1; i >= 0; i--) {
spi.write(data[i]);
}
latch = 1;
wait_us(2);
latch = 0;
}
class Schedulable
{
public:
int time_;
virtual void Run() = 0;
bool operator<(const Schedulable& o) const {
return time_ < o.time_;
}
};
struct comp {
bool operator()(const Schedulable* a, const Schedulable* b) {
return *b < *a;
}
};
priority_queue<Schedulable*, vector<Schedulable*>, comp> task_list;
void Schedule(Schedulable* action)
{
task_list.push(action);
}
int global_tick = 0;
bool strip_changed;
void tick_cb()
{
++global_tick;
strobe = !strobe;
}
class RepeatedFadeInOut : public Schedulable
{
public:
RepeatedFadeInOut(int start_time, int led, uint8_t a, uint8_t b, bool fast)
: led_(led), a_(a), b_(b), fast_(fast) {
time_ = start_time;
Schedule(this);
}
virtual void Run() {
strip[led_] = getcolor(a_, b_);
if (fast_) {
strip[led_] |= FAST;
time_ += 128;
} else {
time_ += 256;
}
strip_changed = true;
swap(a_,b_);
Schedule(this);
}
private:
int led_;
uint8_t a_,b_;
bool fast_;
};
class WalkingFadeInOut : public Schedulable
{
public:
WalkingFadeInOut(int start_time, int led, int stride, uint8_t a, uint8_t b, bool fast)
: led_(led - stride), stride_(stride), a_(a), b_(b), fast_(fast), step_(true) {
time_ = start_time;
Schedule(this);
}
virtual void Run() {
if (step_) {
step_ = false;
if (led_ >= 0) strip[led_] = a_;
led_ += stride_;
led_ %= LENGTH;
} else {
step_ = true;
}
strip[led_] = getcolor(a_, b_);
if (fast_) {
strip[led_] |= FAST;
time_ += 128;
} else {
time_ += 256;
}
strip_changed = true;
swap(a_,b_);
Schedule(this);
}
private:
int led_, stride_;
uint8_t a_,b_;
bool fast_, step_;
};
class RegionWalkingFadeInOut : public Schedulable
{
public:
RegionWalkingFadeInOut(int start_time, int led, int stride, int start_led, int length, uint8_t a, uint8_t b, bool fast, bool repeat, bool drop, Schedulable* next)
: led_(led - stride), stride_(stride), start_led_(start_led), length_(length), a_(a), b_(b), fast_(fast), step_(true), repeat_(repeat), drop_(drop), next_(next) {
time_ = start_time;
Schedule(this);
}
virtual void Run() {
if (step_) {
step_ = false;
if (led_ >= 0) strip[led_ + start_led_] = a_;
led_ += stride_;
if (repeat_) {
led_ %= length_;
} else {
if (led_ >= length_) {
/*if (next_ && led_ == (length_ + stride_)) {
next_->time_ = global_tick + 1;
Schedule(next_);
}*/
delete this;
return;
}
}
} else {
if (led_ == (length_ - 1) && drop_ && !repeat_) {
if (next_) {
next_->time_ = global_tick + 257;
Schedule(next_);
}
delete this;
return;
}
step_ = true;
}
strip[led_ + start_led_] = getcolor(a_, b_);
if (fast_) {
strip[led_ + start_led_] |= FAST;
time_ += 128;
} else {
time_ += 256;
}
strip_changed = true;
swap(a_,b_);
Schedule(this);
}
private:
int led_, stride_;
int start_led_, length_;
uint8_t a_,b_;
bool fast_, step_;
bool repeat_, drop_;
Schedulable* next_;
};
class WaitAndSetDone : public Schedulable {
public:
WaitAndSetDone(int start_time, bool* done)
: done_(done) {
time_ = start_time;
Schedule(this);
}
virtual void Run() {
strip_changed = true;
if (done_) *done_ = true;
delete this;
}
private:
bool* done_;
};
class FadeFillRegion : public Schedulable {
public:
FadeFillRegion(int start_time, int start_led, int length, uint8_t from_color, uint8_t to_color, bool fast, bool* done)
: start_led_(start_led), length_(length), from_color_(from_color), to_color_(to_color), fast_(fast), done_(done) {
time_ = start_time;
Schedule(this);
}
virtual void Run() {
for (int i = start_led_; i < start_led_ + length_; ++i) {
strip[i] = getcolor(from_color_, to_color_) | (fast_ ? FAST : 0);
}
strip_changed = true;
new WaitAndSetDone(global_tick + (fast_ ? 256 : 512), done_);
delete this;
}
private:
int start_led_, length_;
uint8_t from_color_, to_color_;
bool fast_;
bool* done_;
};
/* Keep dropping water drops in a bucket, until it fills up. */
class DropBucketFill : public Schedulable
{
public:
DropBucketFill(int start_time, int start_led, int length, int drop_size, uint8_t from_color, uint8_t to_color, int fade_out_pause, uint8_t fade_out_color, bool* done)
: start_led_(start_led), length_(length), original_length_(length), drop_size_(drop_size), from_color_(from_color), to_color_(to_color), fade_out_pause_(fade_out_pause), fade_out_color_(fade_out_color), done_(done) {
time_ = start_time;
Schedule(this);
}
virtual void Run() {
// The bucket starts with a drop at its end.
//strip[start_led_ + length_] = to_color_;
//strip[start_led_ + length_] = RED;
if (length_ > 0) {
// There's still space in the bucket. Drop a new drop.
for (int i = 0; i < min(drop_size_, length_); ++i) {
Schedulable* next_drop = this;
new RegionWalkingFadeInOut(time_ + (256 * i / drop_size_), i, drop_size_, start_led_, length_, from_color_, to_color_, true, false, true, next_drop);
}
length_--;
} else if (length_ == 0) {
// There's no more space in the bucket. Bail out.
new FadeFillRegion(global_tick + fade_out_pause_, start_led_, original_length_, to_color_, fade_out_color_, false, done_);
delete this;
return;
}
}
private:
int start_led_, length_, original_length_;
int drop_size_;
uint8_t from_color_, to_color_;
int fade_out_pause_;
uint8_t fade_out_color_;
bool* done_;
};
Schedulable* g_watchdog;
class ProgramSupervisor
{
public:
ProgramSupervisor() {
next_program_ = 0;
}
// The program should be alive forever. Programs do not delete themselves upon completion. Every scheduling of a program happens with global time set to zero.
void RegisterProgram(Schedulable* program) {
programs_.push_back(program);
}
// This should be called by the program executor when it is completed.
// It is desired to leave all LEDs black after program completion.
void CurrentProgramDone() {
next_program_++;
next_program_ %= programs_.size();
ScheduleProgram();
}
void ScheduleProgram() {
global_tick = 0;
while (!task_list.empty()) task_list.pop();
Schedule(g_watchdog);
memset(strip, 0x80, sizeof(strip));
write_strip(strip, sizeof(strip));
if (programs_.empty()) return;
programs_[next_program_]->time_ = 0;
Schedule(programs_[next_program_]);
}
private:
vector<Schedulable*> programs_;
int next_program_; // indexes the programs_ array.
} supervisor;
class ProgramWatchdog : public Schedulable
{
public:
ProgramWatchdog() {
time_ = 5 * 60 * 1000; // 5 minutes deadline
}
virtual void Run() {
supervisor.CurrentProgramDone();
led2 = 1;
}
} g_watchdog_impl;
class MultiDropBucketFillProgram : public Schedulable
{
public:
MultiDropBucketFillProgram() {
supervisor.RegisterProgram(this);
}
virtual void Run() {
int time = global_tick;
const int kLength = sizeof(google_colors);
memset(done_, 0, sizeof(done_));
for (int i = 0; i < kLength; i++) {
new DropBucketFill(time, 10 + i * 20, 20, 4, BLACK, google_colors[i], 2560, BLACK, done_ + i);
}
new EndWatcher(done_, kLength);
}
private:
class EndWatcher : public Schedulable {
public:
EndWatcher(bool* done_array, int len) : done_(done_array), len_(len) {
time_ = 0;
Schedule(this);
}
virtual void Run() {
int i;
for (i = 0; i < len_ && done_[i]; i++);
if (i < len_) {
// not done yet.
time_ = global_tick + 2;
Schedule(this);
} else {
supervisor.CurrentProgramDone();
delete this;
}
}
private:
bool* done_;
int len_;
};
bool done_[6];
};
void init_board()
{
pc.baud(115200);
myled = 0;
latch = 0;
spi.format(8, 0);
spi.frequency(300000);
wait_ms(500);
myled = 1;
memset(strip, BLACK, sizeof(strip));
write_strip(strip, sizeof(strip));
g_ticker.attach(&tick_cb, 1.0/1000);
memset(strip, 0x0, sizeof(strip));
}
void run_loop()
{
while(1) {
while (task_list.empty() || global_tick < task_list.top()->time_) {
if (strip_changed) {
write_strip(strip, sizeof(strip));
strip_changed = false;
memset(strip, 0x0, sizeof(strip));
}
}
Schedulable* action = task_list.top();
task_list.pop();
action->Run();
}
}
int main()
{
init_board();
g_watchdog = &g_watchdog_impl;
MultiDropBucketFillProgram multi_drop;
supervisor.ScheduleProgram();
run_loop();
}
