Julio G / Mbed 2 deprecated LedStrip

Dependencies:   mbed

Fork of LedStrip_test by Balazs Racz

main.cpp

Committer:
juliogerchman
Date:
2013-09-21
Revision:
2:590e99f4a313
Parent:
1:1a0d5a780e57
Child:
3:42efa00ffef4

File content as of revision 2:590e99f4a313:

#include <queue>

#include "mbed.h"

DigitalOut myled(LED1);

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 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_ && drop_ && !repeat_) {
                if (next_) {
                    next_->time_ = global_tick + 1;
                    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_;
};

/* 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)
        : start_led_(start_led), length_(length), drop_size_(drop_size), from_color_(from_color), to_color_(to_color) {
        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 < drop_size_; ++i) {
                Schedulable* next_drop = NULL;
                next_drop = this;
                new RegionWalkingFadeInOut(time_ + (256 * i / drop_size_), i, drop_size_, start_led_, length_ - 1, from_color_, to_color_, true, false, true, next_drop);
            }
            length_--;
        } else {
            // There's no more space in the bucket. Bail out.
            delete this;
            return;
        }
    }
    
private:
    int start_led_, length_;
    int drop_size_;
    uint8_t from_color_, to_color_;
};

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();

    int stride = 7;
    for (int i = 0; i < stride; i++) {
        //new WalkingFadeInOut((256 * i / stride), i, stride, BLACK, RED, true);
        /* new RepeatedFadeInOut(0, i, BLACK, RED, false); */
        //new RegionWalkingFadeInOut((256 * i / stride), i, stride, 5, 30, BLACK, BLUE, true, false);
    }

    new DropBucketFill(0, 10, 20, 3, BLACK, BLUE);

    run_loop();
}