Skip to content

Commit

Permalink
Add an extra pixel buffer, implement Write (translating the internal …
Browse files Browse the repository at this point in the history
…buffer into the to-be-PWMed format).

With this commit, WS281x pixels work as expected.
  • Loading branch information
Jon-Bright committed Jan 4, 2021
1 parent e991224 commit 2ffcd9b
Showing 1 changed file with 57 additions and 9 deletions.
66 changes: 57 additions & 9 deletions pixarray/ws281x.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@ type WS281x struct {
r int
b int
w int
pixels []byte
mbox *os.File
mboxSize uint32
rp *RasPiHW
pixHandle uintptr
pixBusAddr uintptr
pixBuf mmap.MMap
pixBufUint []uint32
pixBufOffs uintptr
dmaCb *dmaCallback
dmaCb *dmaControl
dmaBuf mmap.MMap
dmaBufOffs uintptr
dma *dmaT
pwmBuf mmap.MMap
pwm *pwmT
Expand All @@ -44,6 +47,7 @@ func NewWS281x(numPixels int, numColors int, order int, freq uint, dma int, pins
r: offsets[1],
b: offsets[2],
w: offsets[3],
pixels: make([]byte, numPixels*numColors),
rp: rp,
}
wa.mbox, err = wa.mboxOpen()
Expand All @@ -69,7 +73,8 @@ func NewWS281x(numPixels int, numColors int, order int, freq uint, dma int, pins
return nil, fmt.Errorf("couldn't map pixBuf: %v", err)
}
fmt.Printf("got offset %d\n", wa.pixBufOffs)
wa.initDmaCb()
wa.pixBufUint = mmapToUintSlice(wa.pixBuf)
wa.initDmaControl()
err = wa.mapDmaRegisters(dma)
if err != nil {
wa.unlockMem(wa.pixHandle) // Ignore error
Expand All @@ -92,19 +97,62 @@ func (ws *WS281x) MaxPerChannel() int {
}

func (ws *WS281x) GetPixel(i int) Pixel {
return Pixel{}
p := Pixel{int(ws.pixels[i*ws.numColors+ws.r]), int(ws.pixels[i*ws.numColors+ws.g]), int(ws.pixels[i*ws.numColors+ws.b]), -1}
if ws.numColors == 4 {
p.W = int(ws.pixels[i*ws.numColors+ws.w])
}
return p
}

func (ws *WS281x) SetPixel(i int, p Pixel) {
ws.pixBuf[int(ws.pixBufOffs)+i*ws.numColors+ws.r] = byte(p.R)
ws.pixBuf[int(ws.pixBufOffs)+i*ws.numColors+ws.g] = byte(p.G)
ws.pixBuf[int(ws.pixBufOffs)+i*ws.numColors+ws.b] = byte(p.B)
ws.pixels[i*ws.numColors+ws.r] = byte(p.R)
ws.pixels[i*ws.numColors+ws.g] = byte(p.G)
ws.pixels[i*ws.numColors+ws.b] = byte(p.B)
if ws.numColors == 4 {
ws.pixBuf[int(ws.pixBufOffs)+i*ws.numColors+ws.w] = byte(p.W)
ws.pixels[i*ws.numColors+ws.w] = byte(p.W)
}
}

func (wa *WS281x) Write() error {
// TODO
const (
SYMBOL_HIGH = 0x6 // 1 1 0
SYMBOL_LOW = 0x4 // 1 0 0
)

func (ws *WS281x) Write() error {
pbOffs := (uintptr(ws.dmaCb.sourceAd) - ws.pixBusAddr) / 4

// We need to wait for DMA to be done before we start touching the buffer it's outputting
err := ws.waitForDMAEnd()
if err != nil {
return fmt.Errorf("pre-DMA wait failed: %v", err)
}

// TODO: channels, do properly - this just assumes both channels show the same thing
for c := 0; c < 2; c++ {
rpPos := pbOffs + uintptr(c)
bitPos := 31
for i := 0; i < ws.numPixels; i++ {
for j := 0; j < ws.numColors; j++ {
for k := 7; k >= 0; k-- {
symbol := SYMBOL_LOW
if (ws.pixels[i*ws.numColors+j] & (1 << uint(k))) != 0 {
symbol = SYMBOL_HIGH
}
for l := 2; l >= 0; l-- {
ws.pixBufUint[rpPos] &= ^(1 << uint(bitPos))
if (symbol & (1 << uint(l))) != 0 {
ws.pixBufUint[rpPos] |= 1 << uint(bitPos)
}
bitPos--
if bitPos < 0 {
rpPos += 2
bitPos = 31
}
}
}
}
}
}
ws.startDma()
return nil
}

0 comments on commit 2ffcd9b

Please sign in to comment.