aboutsummaryrefslogtreecommitdiff
path: root/src/drv/ws2812B/ws2812b.c
blob: 3cf357062434fcb98ee03a14823bf3beab72a23f (plain) (blame)
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
#include "drv/ws2812B/ws2812b.h"

#include "kern/dma/dma_manager.h"
#include "kern/mem.h"
#include "kern/panic.h"

uint8_t sintable[256] = {
    128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170,
    173, 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211,
    213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240,
    241, 243, 244, 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254,
    254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251,
    250, 250, 249, 248, 246, 245, 244, 243, 241, 240, 238, 237, 235, 234, 232,
    230, 228, 226, 224, 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, 198,
    196, 193, 190, 188, 185, 182, 179, 176, 173, 170, 167, 165, 162, 158, 155,
    152, 149, 146, 143, 140, 137, 134, 131, 128, 124, 121, 118, 115, 112, 109,
    106, 103, 100, 97,  93,  90,  88,  85,  82,  79,  76,  73,  70,  67,  65,
    62,  59,  57,  54,  52,  49,  47,  44,  42,  40,  37,  35,  33,  31,  29,
    27,  25,  23,  21,  20,  18,  17,  15,  14,  12,  11,  10,  9,   7,   6,
    5,   5,   4,   3,   2,   2,   1,   1,   1,   0,   0,   0,   0,   0,   0,
    0,   1,   1,   1,   2,   2,   3,   4,   5,   5,   6,   7,   9,   10,  11,
    12,  14,  15,  17,  18,  20,  21,  23,  25,  27,  29,  31,  33,  35,  37,
    40,  42,  44,  47,  49,  52,  54,  57,  59,  62,  65,  67,  70,  73,  76,
    79,  82,  85,  88,  90,  93,  97,  100, 103, 106, 109, 112, 115, 118, 121,
    124,
};

uint8_t byte_sin(uint8_t n)
{
  return sintable[n];
}

ws2812b_t* ws2812b_new(spi_select_t spi_select, int* ec)
{
  spi_opts_t spi_opts = DEFAULT_SPI_OPTS;
  spi_opts.endianness = ENDIANNESS_BIG;
  spi_t* spi = reserve_spi(spi_select, &spi_opts, ec);

  if (*ec) {
    return NULL;
  }

  ws2812b_t* drv = kalloc(sizeof(ws2812b_t));
  drv->spi = spi;
  return drv;
}

void ws2812b_delete(ws2812b_t* drv)
{
  release_spi(drv->spi);
  kfree(drv);
}

void ws2812b_latch(ws2812b_t* drv)
{
  for (int i = 0; i < 20; ++i) {
    spi_write_8_sync(drv->spi, 0);
  }
}

#undef BIT
#define BIT(b, n) (!!((b) & (1 << (n))))
static inline void byte_compile(uint8_t byte, uint8_t compl [3])
{
  compl [0] = 0 | 1 << 7 | BIT(byte, 7) << 6 | 0 << 5 | 1 << 4 |
              BIT(byte, 6) << 3 | 0 << 2 | 1 << 1 | BIT(byte, 5) << 0;
  compl [1] = 0 | 0 << 7 | 1 << 6 | BIT(byte, 4) << 5 | 0 << 4 | 1 << 3 |
              BIT(byte, 3) << 2 | 0 << 1 | 1 << 0;
  compl [2] = 0 | BIT(byte, 2) << 7 | 0 << 6 | 1 << 5 | BIT(byte, 1) << 4 |
              0 << 3 | 1 << 2 | BIT(byte, 0) << 1 | 0 << 0;
}

void ws2812b_write_rgb_sync(
    ws2812b_t* drv, uint8_t red, uint8_t green, uint8_t blue)
{
  spi_t* spi = drv->spi;

  uint8_t comp[3];

  byte_compile(green, comp);
  spi_write_8_sync(spi, comp[0]);
  spi_write_8_sync(spi, comp[1]);
  spi_write_8_sync(spi, comp[2]);

  byte_compile(red, comp);
  spi_write_8_sync(spi, comp[0]);
  spi_write_8_sync(spi, comp[1]);
  spi_write_8_sync(spi, comp[2]);

  byte_compile(blue, comp);
  spi_write_8_sync(spi, comp[0]);
  spi_write_8_sync(spi, comp[1]);
  spi_write_8_sync(spi, comp[2]);
}

uint8_t* ws2812b_compile_rgb(rgb_t* out_, size_t arr_len)
{
  uint8_t* out = (uint8_t*)out_;
  uint8_t* spi_out = kalloc(arr_len * 9);

  if (!spi_out) {
    panic("Unable to allocate spi_out\n");
  }

  size_t i;
  size_t j;

  for (i = 0, j = 0; i < arr_len * 3; ++i, j += 3) {
    // stuff
    uint8_t c = out[i];
    spi_out[j] = 0 | (1 << 7) | ((c & (1 << 7)) << 6) | (0 << 5) | (1 << 4) |
                 ((c & (1 << 6)) << 3) | (0 << 2) | (1 << 1) |
                 ((c & (1 << 5)) << 0);

    spi_out[j + 1] = 0 | (0 << 7) | (1 << 6) | ((c & (1 << 4)) << 5) |
                     (0 << 4) | (1 << 3) | ((c & (1 << 3)) << 2) | (0 << 1) |
                     (1 << 0);

    spi_out[j + 2] = 0 | ((c & (1 << 2)) << 7) | (0 << 6) | (1 << 5) |
                     ((c & (1 << 1)) << 4) | (0 << 3) | (1 << 2) |
                     ((c & (1 << 0)) << 1) | (0 << 0);
  }

  return spi_out;
}