summaryrefslogtreecommitdiff
path: root/shiftbrite.c
blob: 048405f01e02e82bd90375b1ab2cd0e45a152c79 (plain)
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
/*
 * Simple ShiftBrite interface code for remoodlamp firmware
 * Copyright 2012 (C) Johannes Kroll <jkroll at lavabit com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with This program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdint.h>
#include <string.h>
#include <util/delay.h>
#include <stdio.h>
#include <inttypes.h>
#include "serial.h"

/* shiftbrites connected to header labeled as 'aux', setup:
   PC0 -> CI (clock)
   PC1 -> LI (latch)
   PC2 -> DI (data) */

#define SBCI    (1<<PC0)
#define SBLI    (1<<PC1)
#define SBDI    (1<<PC2)

#define MAXSHIFTBRITES  16


typedef struct rgb
{
    uint16_t r, g, b;   /* 10-bit values */
} rgb_t;

static volatile rgb_t sb_colors[MAXSHIFTBRITES];

/* number of connected shiftbrites
  (automatically updated in sb_setcolor) */
static volatile uint8_t sb_num_shiftbrites= 3;

/* index of next shiftbrite register to be shifted out 
   used by sb_pwmtick */
static uint8_t sb_shiftidx;

/* toggle the latch so the shiftbrites accept new values */
static void sb_toggle_latch(void)
{
    PORTC |= SBLI;
    _delay_us(15);
    PORTC &= ~SBLI;
    _delay_us(15);
}

/* shift out one 32-bit shiftbrite register. */
static void sb_shiftout(uint32_t val)
{
    const unsigned clkdelay = 0;
    for(int8_t i = 31; i>=0; i--) {
        _delay_us(clkdelay);
        PORTC&= ~SBCI;      /* clock lo */
        if((val>>i)&1)
            PORTC|= SBDI;   /* data bit */
        else
            PORTC&= ~SBDI;
        _delay_us(clkdelay);
        PORTC|= SBCI;       /* clock hi */
    }
}

#if 0
/* shift out all color values to connected shiftbrites */
static void sb_update_all_colors(void)
{
    for(int i = sb_num_shiftbrites-1; i>=0; i--)
        sb_shiftout( (uint32_t)sb_colors[i].g | ((uint32_t)sb_colors[i].r<<10) | ((uint32_t)sb_colors[i].b<<20) );
    sb_toggle_latch();
}
#endif

/* set the color of a shiftbrite. */
void sb_setcolor(uint8_t lamp_index, uint8_t r, uint8_t g, uint8_t b)
{
    if(lamp_index >= MAXSHIFTBRITES) return;
    if(lamp_index+1 > sb_num_shiftbrites) sb_num_shiftbrites= lamp_index+1;

    sb_colors[lamp_index].r= (uint16_t)r*r>>6;
    sb_colors[lamp_index].g= (uint16_t)g*g>>6;
    sb_colors[lamp_index].b= (uint16_t)b*b>>6;
    
/* 
    updates are now done in sb_tick()
    sb_update_all_colors();
*/
}


/* write default values to config registers of all shiftbrites */
static void sb_set_default_config_values(void)
{
    for(int i= 0; i<sb_num_shiftbrites; i++)
        sb_shiftout( (uint32_t)(100) | ((uint32_t)(120)<<10) | ((uint32_t)(100)<<20) | ((uint32_t)1<<30) );
    sb_toggle_latch();
}

/* shift out a shiftbrite register, or toggle latch once finished
   to be called from pwm worker loop */
void sb_tick(void)
{
    sb_shiftidx= (sb_shiftidx+1)%(sb_num_shiftbrites+1);
    if(sb_shiftidx==sb_num_shiftbrites)
        sb_toggle_latch();
    else
    {
        int i= sb_num_shiftbrites-sb_shiftidx-1;
        sb_shiftout( (uint32_t)(sb_colors[i].g&0x3FF) | ((uint32_t)(sb_colors[i].r&0x3FF)<<10) | ((uint32_t)(sb_colors[i].b&0x3FF)<<20) );
    }
}

/* setup port for shiftbrites */
void sb_init(void)
{
    PORTC= 0;
    DDRC= SBCI | SBLI | SBDI;
    sb_set_default_config_values();
}