Advertisement
Guest User

Untitled

a guest
May 6th, 2016
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*------------------------------------------------------------------------
  2.   Python module to control Adafruit Dot Star addressable RGB LEDs.
  3.  
  4.   This has some Known Issues(tm):
  5.  
  6.   It's modeled after the Adafruit_DotStar Arduino library (C++), for
  7.   better or for worse.  The idea is that the majority of existing Arduino
  8.   code for DotStar & NeoPixel LEDs can then port over with less fuss.
  9.   As such, it's less "Python-like" than it could (and perhaps should)
  10.   be...for example, RGB colors might be more elegantly expressed as
  11.   tuples or something other than the packed 32-bit integers used here.
  12.   Also, it does not have 100% feature parity with that library...e.g.
  13.   getPixels() is missing here, and this code allows changing the SPI
  14.   bitrate (Arduino lib does not).
  15.  
  16.   There's no doc strings yet.
  17.  
  18.   The library can use either hardware SPI or "bitbang" output....but one
  19.   must be careful in the latter case not to overlap the SPI GPIO pins...
  20.   once they're set as bitbang outputs by this code, they're no longer
  21.   usable for SPI even after the code exits (and not just by this library;
  22.   subsequent runs, other code, etc. all are locked out of SPI, only fix
  23.   seems to be a reboot).  The library checks for an exact overlap between
  24.   the requested bitbang data & clock pins and the hardware SPI pins, and
  25.   will switch over to hardware SPI in that case...but partial overlaps
  26.   (just the data -or- clock pin, or if their positions are swapped) are
  27.   not protected.
  28.  
  29.   As of 9/15 this is using the empirical APA102 data format (rather than
  30.   the datasheet specification).  If it suddenly starts misbehaving with
  31.   new LEDs in the future, may be a hardware production change in the LEDs.
  32.  
  33.   Written by Phil Burgess for Adafruit Industries, with contributions from
  34.   the open source community.
  35.  
  36.   Adafruit invests time and resources providing this open source code,
  37.   please support Adafruit and open-source hardware by purchasing products
  38.   from Adafruit!
  39.  
  40.   ------------------------------------------------------------------------
  41.   This file is part of the Adafruit Dot Star library.
  42.  
  43.   Adafruit Dot Star is free software: you can redistribute it and/or
  44.   modify it under the terms of the GNU Lesser General Public License
  45.   as published by the Free Software Foundation, either version 3 of
  46.   the License, or (at your option) any later version.
  47.  
  48.   Adafruit Dot Star is distributed in the hope that it will be useful,
  49.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  50.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  51.   GNU Lesser General Public License for more details.
  52.  
  53.   You should have received a copy of the GNU Lesser General Public
  54.   License along with NeoPixel.  If not, see <http://www.gnu.org/licenses/>.
  55.   ------------------------------------------------------------------------*/
  56.  
  57. // #include <python2.7/Python.h>
  58. #include <stdint.h>
  59. #include <stdbool.h>
  60. #include <stdlib.h>
  61. #include <stdio.h>
  62. #include <string.h>
  63. #include <unistd.h>
  64. #include <stddef.h>
  65. #include <assert.h>
  66. #include <limits.h>
  67. #include <fcntl.h>
  68. #include <time.h>
  69. #include <sys/mman.h>
  70. #include <sys/ioctl.h>
  71. #include <linux/spi/spidev.h>
  72.  
  73. // From GPIO example code by Dom and Gert van Loo on elinux.org:
  74. #define PI1_BCM2708_PERI_BASE 0x20000000
  75. #define PI1_GPIO_BASE         (PI1_BCM2708_PERI_BASE + 0x200000)
  76. #define PI2_BCM2708_PERI_BASE 0x3F000000
  77. #define PI2_GPIO_BASE         (PI2_BCM2708_PERI_BASE + 0x200000)
  78. #define BLOCK_SIZE            (32768*10)
  79. #define INP_GPIO(g)          *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
  80. #define OUT_GPIO(g)          *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
  81.  
  82. #define SPI_MOSI_PIN 10
  83. #define SPI_CLK_PIN  11
  84.  
  85. static volatile unsigned
  86.   *gpio = NULL, // Memory-mapped GPIO peripheral
  87.   *gpioSet,     // Write bitmask of GPIO pins to set here
  88.   *gpioClr;     // Write bitmask of GPIO pins to clear here
  89.  
  90. static uint8_t isPi2 = 0; // For clock pulse timing & stuff
  91.  
  92. // SPI transfer operation setup.  These are only used w/hardware SPI
  93. // and LEDs at full brightness (or raw write); other conditions require
  94. // per-byte processing.  Explained further in the show() method.
  95. static struct spi_ioc_transfer xfer[3] = {
  96.  { .tx_buf        = 0, // Header (zeros)
  97.    .rx_buf        = 0,
  98.    .len           = 4,
  99.    .delay_usecs   = 0,
  100.    .bits_per_word = 8,
  101.    .cs_change     = 0 },
  102.  { .rx_buf        = 0, // Color payload
  103.    .delay_usecs   = 0,
  104.    .bits_per_word = 8,
  105.    .cs_change     = 0 },
  106.  { .tx_buf        = 0, // Footer (zeros)
  107.    .rx_buf        = 0,
  108.    .delay_usecs   = 0,
  109.    .bits_per_word = 8,
  110.    .cs_change     = 0 }
  111. };
  112.  
  113. typedef struct {
  114.     uint32_t numLEDs,    // Number of pixels in strip
  115.              dataMask,   // Data pin bitmask if using bitbang SPI
  116.              clockMask,  // Clock pin bitmask if bitbang SPI
  117.              bitrate;    // SPI clock speed if using hardware SPI
  118.     int      fd;         // File descriptor if using hardware SPI
  119.     uint8_t *pixels,     // -> pixel data
  120.             *pBuf,       // -> temp buf for brightness-scaling w/SPI
  121.              dataPin,    // Data pin # if bitbang SPI
  122.              clockPin,   // Clock pin # if bitbang SPI
  123.              brightness, // Global brightness setting
  124.              rOffset,    // Index of red in 4-byte pixel
  125.              gOffset,    // Index of green byte
  126.              bOffset;    // Index of blue byte
  127. } DotStarObject;
  128.  
  129. // Allocate new DotStar object.  There's a few ways this can be called:
  130. // x = Adafruit_DotStar(nleds, datapin, clockpin)       Bitbang output
  131. // x = Adafruit_DotStar(nleds, bitrate)   Use hardware SPI @ bitrate
  132. // x = Adafruit_DotStar(nleds)            Hardware SPI @ default rate
  133. // x = Adafruit_DotStar()                 0 LEDs, HW SPI, default rate
  134. // 0 LEDs is valid, but one must then pass a properly-sized and -rendered
  135. // bytearray to the show() method.
  136. static DotStarObject *DotStar_new(uint32_t pCount, uint8_t mosiPin, uint8_t clkPin, uint32_t bRate) {
  137.     // DotStarObject *self = malloc(sizeof(DotStarObject));
  138.     DotStarObject *self = (DotStarObject*)malloc(sizeof(DotStarObject));
  139.     uint8_t     *pixels   = NULL, dPin = 0xFF, cPin = 0xFF;
  140.     uint32_t    n_pixels = pCount;
  141.     printf("Pixel count assigned %i\n", n_pixels);
  142.     uint32_t    bitrate = bRate;
  143.     uint32_t i;
  144.     // PyObject      *string;
  145.     char          *order    = NULL, *c;
  146.     // uint8_t        rOffset = 2, gOffset = 3, bOffset = 1; // BRG default
  147.     uint8_t        rOffset = 3, gOffset = 1, bOffset = 2;
  148.  
  149.     // If pins happen to correspond to hardware SPI data and
  150.     // clock, hardware SPI is used instead.  Because reasons.
  151.     // if((dPin == SPI_MOSI_PIN) && (cPin  == SPI_CLK_PIN)){
  152.     //  dPin = cPin = 0xFF;
  153.     // }
  154.  
  155.     // Can optionally append keyword to specify R/G/B pixel order
  156.     // "order='rgb'" or similar (switch r/g/b around to match strip).
  157.     // Order string isn't much validated; nonsense may occur.
  158.     // if(kw && (string = PyDict_GetItemString(kw, "order")) &&
  159.       // (order = PyString_AsString(string))) {
  160.         // order = 'bgr';
  161.         // for(i=0; order[i]; i++) order[i] = tolower(order[i]);
  162.         // if((c = strchr(order, 'r'))) rOffset = c - order + 1;
  163.         // if((c = strchr(order, 'g'))) gOffset = c - order + 1;
  164.         // if((c = strchr(order, 'b'))) bOffset = c - order + 1;
  165.     // }
  166.  
  167.     // Allocate space for LED data:
  168.     if((!n_pixels) || ((pixels = (uint8_t *)malloc(n_pixels * 8)))) {
  169.             self->numLEDs    = n_pixels;
  170.             self->dataMask   = 0;
  171.             self->clockMask  = 0;
  172.             self->bitrate    = bitrate;
  173.             self->fd         = -1;
  174.             self->pixels     = pixels; // NULL if 0 pixels
  175.             self->pBuf       = NULL;   // alloc'd on 1st use
  176.             self->dataPin    = dPin;
  177.             self->clockPin   = cPin;
  178.             self->brightness = 0;
  179.             self->rOffset    = rOffset;
  180.             self->gOffset    = gOffset;
  181.             self->bOffset    = bOffset;
  182.     }
  183.  
  184.     return self;
  185. }
  186.  
  187. // Initialize DotStar object
  188. static int DotStar_init(DotStarObject *self) {
  189.     uint32_t i;
  190.     // Set first byte of each 4-byte pixel to 0xFF, rest to 0x00 (off)
  191.     memset(self->pixels, 0, self->numLEDs * 4);
  192.     for(i=0; i<self->numLEDs; i++) self->pixels[i * 4] = 0xFF;
  193.     return 0;
  194. }
  195.  
  196. // Detect Pi board type.  Doesn't return super-granular details,
  197. // just the most basic distinction needed for GPIO compatibility:
  198. // 0: Pi 1 Model B revision 1
  199. // 1: Pi 1 Model B revision 2, Model A, Model B+, Model A+
  200. // 2: Pi 2 Model B
  201.  
  202. static int boardType(void) {
  203.     FILE *fp;
  204.     char  buf[1024], *ptr;
  205.     int   n, board = 1; // Assume Pi1 Rev2 by default
  206.  
  207.     // Relies on info in /proc/cmdline.  If this becomes unreliable
  208.     // in the future, alt code below uses /proc/cpuinfo if any better.
  209. #if 1
  210.     if((fp = fopen("/proc/cmdline", "r"))) {
  211.         while(fgets(buf, sizeof(buf), fp)) {
  212.             if((ptr = strstr(buf, "mem_size=")) &&
  213.                (sscanf(&ptr[9], "%x", &n) == 1) &&
  214.                (n == 0x3F000000)) {
  215.                 board = 2; // Appears to be a Pi 2
  216.                 printf("Board is PI2\n");
  217.                 break;
  218.             } else if((ptr = strstr(buf, "boardrev=")) &&
  219.                       (sscanf(&ptr[9], "%x", &n) == 1) &&
  220.                       ((n == 0x02) || (n == 0x03))) {
  221.                 board = 0; // Appears to be an early Pi
  222.                 printf("Board is PI1\n");
  223.                 break;
  224.             }
  225.         }
  226.         fclose(fp);
  227.     }
  228. #else
  229.     char s[8];
  230.     if((fp = fopen("/proc/cpuinfo", "r"))) {
  231.         while(fgets(buf, sizeof(buf), fp)) {
  232.             if((ptr = strstr(buf, "Hardware")) &&
  233.                (sscanf(&ptr[8], " : %7s", s) == 1) &&
  234.                (!strcmp(s, "BCM2709"))) {
  235.                 board = 2; // Appears to be a Pi 2
  236.                 break;
  237.             } else if((ptr = strstr(buf, "Revision")) &&
  238.                       (sscanf(&ptr[8], " : %x", &n) == 1) &&
  239.                       ((n == 0x02) || (n == 0x03))) {
  240.                 board = 0; // Appears to be an early Pi
  241.                 break;
  242.             }
  243.         }
  244.         fclose(fp);
  245.     }
  246. #endif
  247.  
  248.     return board;
  249. }
  250.  
  251. // Initialize pins/SPI for output
  252. static void begin(DotStarObject *self) {
  253.     if(self->dataPin == 0xFF) { // Use hardware SPI
  254.         printf("Using hardware SPI\n");
  255.         if((self->fd = open("/dev/spidev0.0", O_RDWR)) < 0) {
  256.             printf("Can't open /dev/spidev0.0 (try 'sudo')\n");
  257.             return;
  258.         }
  259.         uint8_t mode = SPI_MODE_0 | SPI_NO_CS;
  260.         ioctl(self->fd, SPI_IOC_WR_MODE, &mode);
  261.         // The actual data rate may be less than requested.
  262.         // Hardware SPI speed is a function of the system core
  263.         // frequency and the smallest power-of-two prescaler
  264.         // that will not exceed the requested rate.
  265.         // e.g. 8 MHz request: 250 MHz / 32 = 7.8125 MHz.
  266.         ioctl(self->fd, SPI_IOC_WR_MAX_SPEED_HZ, self->bitrate);
  267.     } else { // Use bitbang "soft" SPI (any 2 pins)
  268.         if(gpio == NULL) { // First time accessing GPIO?
  269.             int fd;
  270.  
  271.             if((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
  272.                 printf("Can't open /dev/mem (try 'sudo')\n");
  273.                 return;
  274.             }
  275.             isPi2 = (boardType() == 2);
  276.             gpio  = (volatile unsigned *)mmap( // Memory-map I/O
  277.               NULL,                 // Any adddress will do
  278.               BLOCK_SIZE,           // Mapped block length
  279.               PROT_READ|PROT_WRITE, // Enable read+write
  280.               MAP_SHARED,           // Shared w/other processes
  281.               fd,                   // File to map
  282.               isPi2 ?
  283.                PI2_GPIO_BASE :      // -> GPIO registers
  284.                PI1_GPIO_BASE);
  285.             close(fd);              // Not needed after mmap()
  286.             if(gpio == MAP_FAILED) {
  287.                 err("Can't mmap()");
  288.                 return;
  289.             }
  290.             gpioSet = &gpio[7];
  291.             gpioClr = &gpio[10];
  292.         }
  293.  
  294.         self->dataMask  = 1 << self->dataPin;
  295.         self->clockMask = 1 << self->clockPin;
  296.  
  297.         // Set 2 pins as outputs.  Must use INP before OUT.
  298.         INP_GPIO(self->dataPin);  OUT_GPIO(self->dataPin);
  299.         INP_GPIO(self->clockPin); OUT_GPIO(self->clockPin);
  300.  
  301.         *gpioClr = self->dataMask | self->clockMask; // data+clock LOW
  302.     }
  303.     return;
  304. }
  305.  
  306. // Set strip data to 'off' (just clears buffer, does not write to strip)
  307. static void clear(DotStarObject *self) {
  308.     uint8_t *ptr;
  309.     uint32_t i;
  310.     for(ptr = self->pixels, i=0; i<self->numLEDs; i++, ptr += 4) {
  311.         ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
  312.     }
  313. }
  314.  
  315. // Set global strip brightness.  This does not have an immediate effect;
  316. // must be followed by a call to show().  Not a fan of this...for various
  317. // reasons I think it's better handled in one's application, but it's here
  318. // for parity with the Arduino NeoPixel library.
  319. static void setBrightness(DotStarObject *self, uint8_t b) {
  320.  
  321.     // Stored brightness value is different than what's passed.  This
  322.     // optimizes the actual scaling math later, allowing a fast multiply
  323.     // and taking the MSB.  'brightness' is a uint8_t, adding 1 here may
  324.     // (intentionally) roll over...so 0 = max brightness (color values
  325.     // are interpreted literally; no scaling), 1 = min brightness (off),
  326.     // 255 = just below max brightness.
  327.     self->brightness = b + 1;
  328. }
  329.  
  330. // Valid syntaxes:
  331. // x.setPixelColor(index, red, green, blue)
  332. // x.setPixelColor(index, 0x00RRGGBB)
  333. static void setPixelColor(DotStarObject *self, uint32_t i, uint8_t r, uint8_t g, uint8_t b) {
  334.     // uint32_t i, v;
  335.     // uint8_t  r, g, b;
  336.  
  337.     // switch(PyTuple_Size(arg)) {
  338.     //    case 4: // Index, r, g, b
  339.     //  if(!PyArg_ParseTuple(arg, "Ibbb", &i, &r, &g, &b))
  340.     //      return;
  341.     //  break;
  342.     //    case 2: // Index, value
  343.     //  if(!PyArg_ParseTuple(arg, "II", &i, &v))
  344.     //      return;
  345.     //  r = v >> 16;
  346.     //  g = v >>  8;
  347.     //  b = v;
  348.     //  break;
  349.     //    default:
  350.     //  return;
  351.     // }
  352.  
  353.     if(i < self->numLEDs) {
  354.         uint8_t *ptr = &self->pixels[i * 4];
  355.         ptr[self->rOffset] = r;
  356.         ptr[self->gOffset] = g;
  357.         ptr[self->bOffset] = b;
  358.     }
  359.     return;
  360. }
  361.  
  362. // Bitbang requires throttle on clock set/clear to avoid outpacing strip
  363. static void clockPulse(uint32_t mask) {
  364.     volatile uint8_t hi, lo;
  365.     *gpioSet = mask;
  366.     if(isPi2) {
  367.         hi = 60; // These were found empirically
  368.         lo = 50; // using 'Pi2' overclock setting and...
  369.     } else {
  370.         hi = 14; // ...'Medium' setting, respectively,
  371.         lo = 2;  // driving a 2 meter x 144 LED strip.
  372.     }
  373.     while(hi--);
  374.     *gpioClr = mask;
  375.     while(lo--);
  376.     return;
  377. }
  378.  
  379. // Private method.  Writes pixel data without brightness scaling.
  380. static void raw_write(DotStarObject *self, uint8_t *ptr, uint32_t len) {
  381.     if(self->fd >= 0) { // Hardware SPI
  382.         // printf("SPI write\n");
  383.         xfer[0].speed_hz = self->bitrate;
  384.         xfer[1].speed_hz = self->bitrate;
  385.         xfer[2].speed_hz = self->bitrate;
  386.         xfer[1].tx_buf   = (unsigned long)ptr;
  387.         xfer[1].len      = len;
  388.         if(self->numLEDs) xfer[2].len = (self->numLEDs + 15) / 16;
  389.         else              xfer[2].len = ((len / 4) + 15) / 16;
  390.         // All that spi_ioc_transfer struct stuff earlier in
  391.         // the code is so we can use this single ioctl to concat
  392.         // the data & footer into one operation:
  393.         (void)ioctl(self->fd, SPI_IOC_MESSAGE(3), xfer);
  394.     } else if(self->dataMask) { // Bitbang
  395.         printf("Bitbang write\n");
  396.         unsigned char byte, bit,
  397.                       headerLen = 32;
  398.         uint32_t      footerLen;
  399.         if(self->numLEDs) footerLen = (self->numLEDs + 1) / 2;
  400.         else              footerLen = ((len / 4) + 1) / 2;
  401.         *gpioClr = self->dataMask;
  402.         while(headerLen--) clockPulse(self->clockMask);
  403.         while(len--) { // Pixel data
  404.             byte = *ptr++;
  405.             for(bit = 0x80; bit; bit >>= 1) {
  406.                 if(byte & bit) *gpioSet = self->dataMask;
  407.                 else           *gpioClr = self->dataMask;
  408.                 clockPulse(self->clockMask);
  409.             }
  410.         }
  411.         *gpioClr = self->dataMask;
  412.         while(footerLen--) clockPulse(self->clockMask);
  413.     }
  414. }
  415.  
  416. // Issue data to strip.  Optional arg = raw bytearray to issue to strip
  417. // (else object's pixel buffer is used).  If passing raw data, it must
  418. // be in strip-ready format (4 bytes/pixel, 0xFF/B/G/R) and no brightness
  419. // scaling is performed...it's all about speed (for POV, etc.)
  420. static void show(DotStarObject *self) {
  421.     // if(PyTuple_Size(arg) == 1) { // Raw bytearray passed
  422.     //  Py_buffer buf;
  423.     //  if(!PyArg_ParseTuple(arg, "s*", &buf)) return NULL;
  424.     //  raw_write(self, buf.buf, buf.len);
  425.     //  PyBuffer_Release(&buf);
  426.     // } else { // Write object's pixel buffer
  427.         if(self->brightness == 0) { // Send raw (no scaling)
  428.             printf("Sending raw\n");
  429.             raw_write(self, self->pixels, self->numLEDs * 8);
  430.         } else { // Adjust brightness during write
  431.             uint32_t i;
  432.             uint8_t *ptr   = self->pixels;
  433.             uint16_t scale = self->brightness;
  434.             if(self->fd >= 0) { // Hardware SPI
  435.                 // Allocate pBuf if using hardware
  436.                 // SPI and not previously alloc'd
  437.                 if((self->pBuf == NULL) && ((self->pBuf =
  438.                   (uint8_t *)malloc(self->numLEDs * 8)))) {
  439.                     memset(self->pBuf, 0xFF,
  440.                       self->numLEDs * 8); // Init MSBs
  441.                 }
  442.  
  443.                 if(self->pBuf) {
  444.                     // Scale from 'pixels' buffer into
  445.                     // 'pBuf' (if available) and then
  446.                     // use a single efficient write
  447.                     // operation (thx Eric Bayer).
  448.                     uint8_t *pb = self->pBuf;
  449.                     for(i=0; i<self->numLEDs;
  450.                       i++, ptr += 4, pb += 4) {
  451.                         pb[1] = (ptr[1] * scale) >> 8;
  452.                         pb[2] = (ptr[2] * scale) >> 8;
  453.                         pb[3] = (ptr[3] * scale) >> 8;
  454.                     }
  455.                     raw_write(self, self->pBuf,
  456.                       self->numLEDs * 4);
  457.                 } else {
  458.                     // Fallback if pBuf not available
  459.                     // (just in case malloc fails),
  460.                     // also write() bugfix via Eric Bayer
  461.                     uint8_t x[4];
  462.                     // Header:
  463.                     x[0] = 0;
  464.                     i    = 4;
  465.                     while(i--) write(self->fd, x, 1);
  466.                     // Payload:
  467.                     x[0] = 0xFF;
  468.                     for(i=0; i<self->numLEDs;
  469.                       i++, ptr += 4) {
  470.                         x[1] = (ptr[1] * scale) >> 8;
  471.                         x[2] = (ptr[2] * scale) >> 8;
  472.                         x[3] = (ptr[3] * scale) >> 8;
  473.                         write(self->fd, x, sizeof(x));
  474.                     }
  475.                     // Footer:
  476.                     x[0] = 0;
  477.                     i = (self->numLEDs + 15) / 16;
  478.                     while(i--) write(self->fd, x, 1);
  479.                 }
  480.             } else if(self->dataMask) {
  481.                 uint32_t word, bit;
  482.                 // Header (32 bits)
  483.                 *gpioClr = self->dataMask;
  484.                 bit      = 32;
  485.                 while(bit--) clockPulse(self->clockMask);
  486.                 for(i=0; i<self->numLEDs; i++, ptr += 4) {
  487.                     word = 0xFF000000                   |
  488.                      (((ptr[1] * scale) & 0xFF00) << 8) |
  489.                      ( (ptr[2] * scale) & 0xFF00      ) |
  490.                      ( (ptr[3] * scale)           >> 8);
  491.                     for(bit = 0x80000000; bit; bit >>= 1) {
  492.                         if(word & bit)
  493.                           *gpioSet = self->dataMask;
  494.                         else
  495.                           *gpioClr = self->dataMask;
  496.                         clockPulse(self->clockMask);
  497.                     }
  498.                 }
  499.                 // Footer (1/2 bit per LED)
  500.                 *gpioClr = self->dataMask;
  501.                 bit      = (self->numLEDs + 1) / 2;
  502.                 while(bit--) clockPulse(self->clockMask);
  503.             }
  504.         }
  505.     // }
  506. }
  507.  
  508. // Given separate R, G, B, return a packed 32-bit color.
  509. // Meh, mostly here for parity w/Arduino library.
  510. static unsigned int Color(uint8_t r, uint8_t g, uint8_t b) {
  511.     return (r << 16) | (g << 8) | b;
  512. }
  513.  
  514. // Return color of previously-set pixel (as packed 32-bit value)
  515. static unsigned int getPixelColor(DotStarObject *self, uint32_t  i) {
  516.     uint8_t r=0, g=0, b=0;
  517.     if(i < self->numLEDs) {
  518.         uint8_t *ptr = &self->pixels[i * 4];
  519.         r = ptr[self->rOffset];
  520.         g = ptr[self->gOffset];
  521.         b = ptr[self->bOffset];
  522.     }
  523.  
  524.     return (r << 16) | (g << 8) | b;
  525. }
  526.  
  527. // Return strip length
  528. static int numPixels(DotStarObject *self) {
  529.     return self->numLEDs;
  530. }
  531.  
  532. // Return strip brightness
  533. static int getBrightness(DotStarObject *self) {
  534.     return (uint8_t)(self->brightness - 1);
  535. }
  536.  
  537. // DON'T USE THIS.  One of those "parity with Arduino library" methods,
  538. // but current'y doesn't work (and might never).  Supposed to return strip's
  539. // pixel buffer, but doesn't seem to be an easy way to do this in Python 2.X.
  540. // That's okay -- instead of 'raw' access to a strip's previously-allocated
  541. // buffer, a Python program can instead allocate its own buffer and pass this
  542. // to the show() method, basically achieving the same thing and then some.
  543. // static PyObject *getPixels(DotStarObject *self) {
  544. //  PyObject *result = Py_BuildValue("s#",
  545. //    self->pixels, self->numLEDs * 4);
  546. //  Py_INCREF(result);
  547. //  return result;
  548. // }
  549.  
  550. static void _close(DotStarObject *self) {
  551.     if(self->fd) {
  552.         close(self->fd);
  553.         self->fd = -1;
  554.     } else {
  555.         INP_GPIO(self->dataPin);
  556.         INP_GPIO(self->clockPin);
  557.         self->dataMask  = 0;
  558.         self->clockMask = 0;
  559.     }
  560.     return;
  561. }
  562.  
  563. static void DotStar_dealloc(DotStarObject *self) {
  564.     _close(self);
  565.     if(self->pBuf)   free(self->pBuf);
  566.     if(self->pixels) free(self->pixels);
  567.     return;
  568. }
  569.  
  570. // Method names are silly and inconsistent, but following NeoPixel
  571. // and prior libraries, which formed through centuries of accretion.
  572. // static PyMethodDef methods[] = {
  573. //   { "begin"        , (PyCFunction)begin        , METH_NOARGS , NULL },
  574. //   { "clear"        , (PyCFunction)clear        , METH_NOARGS , NULL },
  575. //   { "setBrightness", (PyCFunction)setBrightness, METH_VARARGS, NULL },
  576. //   { "setPixelColor", (PyCFunction)setPixelColor, METH_VARARGS, NULL },
  577. //   { "show"         , (PyCFunction)show         , METH_VARARGS, NULL },
  578. //   { "Color"        , (PyCFunction)Color        , METH_VARARGS, NULL },
  579. //   { "getPixelColor", (PyCFunction)getPixelColor, METH_VARARGS, NULL },
  580. //   { "numPixels"    , (PyCFunction)numPixels    , METH_NOARGS , NULL },
  581. //   { "getBrightness", (PyCFunction)getBrightness, METH_NOARGS , NULL },
  582. //   { "getPixels"    , (PyCFunction)getPixels    , METH_NOARGS , NULL },
  583. //   { "close"        , (PyCFunction)_close       , METH_NOARGS , NULL },
  584. //   { NULL, NULL, 0, NULL }
  585. // };
  586.  
  587. // static PyTypeObject DotStarObjectType = {
  588. //  PyObject_HEAD_INIT(NULL)
  589. //  0,                           // ob_size (not used, always set to 0)
  590. //  "dotstar.Adafruit_DotStar",  // tp_name (module name, object name)
  591. //  sizeof(DotStarObject),       // tp_basicsize
  592. //  0,                           // tp_itemsize
  593. //  (destructor)DotStar_dealloc, // tp_dealloc
  594. //  0,                           // tp_print
  595. //  0,                           // tp_getattr
  596. //  0,                           // tp_setattr
  597. //  0,                           // tp_compare
  598. //  0,                           // tp_repr
  599. //  0,                           // tp_as_number
  600. //  0,                           // tp_as_sequence
  601. //  0,                           // tp_as_mapping
  602. //  0,                           // tp_hash
  603. //  0,                           // tp_call
  604. //  0,                           // tp_str
  605. //  0,                           // tp_getattro
  606. //  0,                           // tp_setattro
  607. //  0,                           // tp_as_buffer
  608. //  Py_TPFLAGS_DEFAULT,          // tp_flags
  609. //  0,                           // tp_doc
  610. //  0,                           // tp_traverse
  611. //  0,                           // tp_clear
  612. //  0,                           // tp_richcompare
  613. //  0,                           // tp_weaklistoffset
  614. //  0,                           // tp_iter
  615. //  0,                           // tp_iternext
  616. //  methods,                     // tp_methods
  617. //  0,                           // tp_members
  618. //  0,                           // tp_getset
  619. //  0,                           // tp_base
  620. //  0,                           // tp_dict
  621. //  0,                           // tp_descr_get
  622. //  0,                           // tp_descr_set
  623. //  0,                           // tp_dictoffset
  624. //  (initproc)DotStar_init,      // tp_init
  625. //  0,                           // tp_alloc
  626. //  DotStar_new,                 // tp_new
  627. //  0,                           // tp_free
  628. // };
  629.  
  630. // PyMODINIT_FUNC initdotstar(void) { // Module initialization function
  631. //  PyObject* m;
  632.  
  633. //  if((m = Py_InitModule("dotstar", methods)) &&
  634. //     (PyType_Ready(&DotStarObjectType) >= 0)) {
  635. //      Py_INCREF(&DotStarObjectType);
  636. //      PyModule_AddObject(m, "Adafruit_DotStar",
  637. //        (PyObject *)&DotStarObjectType);
  638. //  }
  639. // }
  640.  
  641. int main(){
  642.     printf("Hello APA102\n");
  643.     DotStarObject *dotty;
  644.     dotty = DotStar_new(300, 10, 11, 16000000);
  645.     uint8_t r = 0, g = 255, b = 255;
  646.     bool direction = true;
  647.     begin(dotty);
  648.     DotStar_init(dotty);
  649.     setBrightness(dotty,3);
  650.     // for (int i = 1; i < dotty->numLEDs-1; ++i){
  651.     //  setPixelColor(dotty,i,r,g,b);
  652.     // }
  653.     // show(dotty);
  654.     while(1){
  655.         for (uint8_t i = 0; i < dotty->numLEDs; ++i){
  656.             // setPixelColor(dotty,i,r,g,b);
  657.             setPixelColor(dotty,i,r,0,0);
  658.         }
  659.         if(direction && r != 255){
  660.             r++;
  661.             // r = 255;
  662.         }else if (direction && r == 255){
  663.             direction = !direction;
  664.         }
  665.  
  666.         if (!direction && r != 0){
  667.             r--;
  668.             // r = 0;
  669.         }else if (!direction && r == 0){
  670.             direction = !direction;
  671.         }
  672.         // printf("%i\n", r);
  673.         show(dotty);
  674.         // usleep(16 * 1000);
  675.     }
  676. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement