Userspace Raspberry Pi library for controlling WS281X LEDs.
Posted: Wed Dec 22, 2021 3:05 pm
				
				I have found a simple library for led strings. Since my case has 4 led's, I could also try to control them with PB.
Do not forget. Hardware needs root rights. PB so start with sudo
Update v1.01.6
WS2811.pbi
			Do not forget. Hardware needs root rights. PB so start with sudo
Update v1.01.6
WS2811.pbi
Code: Select all
;TOP
; Comment : Userspace Raspberry Pi library for controlling WS281X LEDs.
; Author  : mk-soft
; Version : v1.01.6
; Create  : 21.12.2021
; Update  : 28.12.2021
; Lisence : MIT and see github project
; Library : https://github.com/jgarff/rpi_ws281x
; Compile library: (See github projekt)
; -------------------------------------
;
; Open terminal:
;
; first install cmake:
;
;   sudo apt-get install cmake
; 
; also if git is not installed, install it:
;
;   sudo apt-get install git
; 
; now get the repository from the web:
;
;   git clone https://github.com/jgarff/rpi_ws281x.git
; 
; then go to the new directory:
;
;   cd rpi_ws281x
;
; follow:
;   mkdir build
;   cd build
;   cmake -D BUILD_SHARED=ON -D BUILD_TEST=OFF .. <--- don't forget double dots ;)
;   cmake --build . <--- don't forget dot ;)
;   sudo make install
; *********
EnableExplicit
  
; Header pwm.h
#RPI_PWM_CHANNELS = 2
; Header ws2811.h
#WS2811_TARGET_FREQ                     = 800000    ; Can go As low As 400000
#WS2811_TARGET_FREQ_LOW                 = 400000
; 4 color R, G, B And W ordering
#SK6812_STRIP_RGBW                      = $18100800
#SK6812_STRIP_RBGW                      = $18100008
#SK6812_STRIP_GRBW                      = $18081000
#SK6812_STRIP_GBRW                      = $18080010
#SK6812_STRIP_BRGW                      = $18001008
#SK6812_STRIP_BGRW                      = $18000810
#SK6812_SHIFT_WMASK                     = $f0000000
; 3 color R, G And B ordering
#WS2811_STRIP_RGB                       = $00100800
#WS2811_STRIP_RBG                       = $00100008
#WS2811_STRIP_GRB                       = $00081000
#WS2811_STRIP_GBR                       = $00080010
#WS2811_STRIP_BRG                       = $00001008
#WS2811_STRIP_BGR                       = $00000810
; predefined fixed LED types
#WS2812_STRIP                           = #WS2811_STRIP_GRB
#SK6812_STRIP                           = #WS2811_STRIP_GRB
#SK6812W_STRIP                          = #SK6812_STRIP_GRBW
;struct ws2811_device;
;typedef uint32_t ws2811_led_t;                   //< 0xWWRRGGBB
Structure ws2811_led_t
  Led.l[0]
EndStructure
;typedef struct ws2811_channel_t
Structure ws2811_channel_t Align #PB_Structure_AlignC
  ;{
  gpionum.l         ; //< GPIO Pin with PWM alternate function, 0 if unused
  invert.l          ; //< Invert output signal
  count.l           ; //< Number of LEDs, 0 if channel is unused
  strip_type.l      ; //< Strip color layout -- one of WS2811_STRIP_xxx constants
  *leds.ws2811_led_t; //< LED buffers, allocated by driver based on count
  brightness.a      ; //< Brightness value between 0 and 255
  wshift.a          ; //< White shift value
  rshift.a          ; //< Red shift value
  gshift.a          ; //< Green shift value
  bshift.a          ; //< Blue shift value
  *gamma            ; //< Gamma correction table
EndStructure
;typedef struct ws2811_t
Structure ws2811_t Align #PB_Structure_AlignC
  ;{
  render_wait_time.q; //< time in µs before the next render can run
  *device           ; //< Private data for driver use
  *rpi_hw           ; //< RPI Hardware Information
  freq.l            ; //< Required output frequency
  dmanum.l          ; //< DMA number _not_ already in use
  channel.ws2811_channel_t[#RPI_PWM_CHANNELS];
EndStructure  
;#define WS2811_RETURN_STATES(X)
#WS2811_SUCCESS = 0                 ; "Success"
#WS2811_ERROR_GENERIC = -1          ; "Generic failure"
#WS2811_ERROR_OUT_OF_MEMORY = -2    ; "Out of memory"
#WS2811_ERROR_HW_NOT_SUPPORTED = -3 ; "Hardware revision is not supported"
#WS2811_ERROR_MEM_LOCK = -4         ; "Memory lock failed"
#WS2811_ERROR_MMAP = -5             ; "mmap() failed"
#WS2811_ERROR_MAP_REGISTERS = -6    ; "Unable to map registers into userspace"
#WS2811_ERROR_GPIO_INIT = -7        ; "Unable to initialize GPIO"
#WS2811_ERROR_PWM_SETUP = -8        ; "Unable to initialize PWM"
#WS2811_ERROR_MAILBOX_DEVICE = -9   ; "Failed to create mailbox device"
#WS2811_ERROR_DMA = -10             ; "DMA error"
#WS2811_ERROR_ILLEGAL_GPIO = -11    ; "Selected GPIO not possible"
#WS2811_ERROR_PCM_SETUP = -12       ; "Unable to initialize PCM"
#WS2811_ERROR_SPI_SETUP = -13       ; "Unable to initialize SPI"
#WS2811_ERROR_SPI_TRANSFER = -14    ; "SPI transfer error"
; ws2811_return_t ws2811_init(ws2811_t *ws2811);                              //< Initialize buffers/hardware
; void ws2811_fini(ws2811_t *ws2811);                                         //< Tear it all down
; ws2811_return_t ws2811_render(ws2811_t *ws2811);                            //< Send LEDs off to hardware
; ws2811_return_t ws2811_wait(ws2811_t *ws2811);                              //< Wait for DMA completion
; const char * ws2811_get_return_t_str(const ws2811_return_t state);          //< Get string representation of the given return state
; void ws2811_set_custom_gamma_factor(ws2811_t *ws2811, double gamma_factor); //< Set a custom Gamma correction array based on a gamma correction factor
PrototypeC ws2811_init(*ws2811.ws2811_t);                                     //< Initialize buffers/hardware
PrototypeC ws2811_fini(*ws2811.ws2811_t);                                     //< Tear it all down
PrototypeC ws2811_render(*ws2811.ws2811_t);                                   //< Send LEDs off to hardware
PrototypeC ws2811_wait(*ws2811.ws2811_t)  ;                                   //< Wait for DMA completion
PrototypeC ws2811_get_return_t_str(ws2811_return_t_state);                    //< Get string representation of the given return state
PrototypeC ws2811_set_custom_gamma_factor(*ws2811.ws2811_t, gamma_factor.d);  //< Set a custom Gamma correction array based on a gamma correction factor
Global libws2811
Procedure InitLib_ws2811(pathlib.s = "libws2811.so")
  libws2811 = OpenLibrary(#PB_Any, pathlib)
  If libws2811
    Global ws2811_init.ws2811_init = GetFunction(libws2811, "ws2811_init")
    Global ws2811_fini.ws2811_fini = GetFunction(libws2811, "ws2811_fini")
    Global ws2811_render.ws2811_render = GetFunction(libws2811, "ws2811_render")
    Global ws2811_wait.ws2811_wait = GetFunction(libws2811, "ws2811_wait")
    Global __ws2811_get_return_t_str.ws2811_get_return_t_str = GetFunction(libws2811, "ws2811_get_return_t_str")
    Global ws2811_set_custom_gamma_factor.ws2811_set_custom_gamma_factor = GetFunction(libws2811, "ws2811_set_custom_gamma_factor")
  EndIf
  ProcedureReturn libws2811
EndProcedure
Procedure.s ws2811_get_return_t_str(state)
  Protected *state
  *state = __ws2811_get_return_t_str(state)
  If *state
    ProcedureReturn PeekS(*state, -1, #PB_UTF8)
  EndIf
EndProcedure
Procedure CloseLib_ws2811()
  CloseLibrary(libws2811)
EndProcedure
;- Example ws2812b (4 LEDs on GPIO 18 PWM)
CompilerIf #PB_Compiler_IsMainFile
  
  EnableExplicit
  
  ;IncludeFile "WS2811.pbi"
  
  If Not InitLib_ws2811()
    Debug "Error open library ws2811"
    End
  EndIf
  
  #TARGET_FREQ = #WS2811_TARGET_FREQ  ; Default 800000
  #GPIO_PIN = 18
  #DMA = 10
  ; #STRIP_TYPE = WS2811_STRIP_RGB    ; WS2812/SK6812RGB integrated chip+leds
  #STRIP_TYPE = #WS2811_STRIP_GRB     ; WS2812/SK6812RGB integrated chip+leds
  ;#STRIP_TYPE = #SK6812_STRIP_RGBW	  ; SK6812RGBW (Not SK6812RGB)
  #LED_COUNT = 4
  
  Global ledstring.ws2811_t
  Global r1
  
  With ledstring
    \freq = #TARGET_FREQ
    \dmanum = #DMA
    \channel[0]\gpionum = #GPIO_PIN
    \channel[0]\count = #LED_COUNT
    \channel[0]\invert = 0
    \channel[0]\brightness = 255
    \channel[0]\strip_type = #STRIP_TYPE
    
    Repeat ; Do
      r1 = ws2811_init(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Init: " + ws2811_get_return_t_str(r1)
        CloseLib_ws2811()
        End
      EndIf
      
      ; LEDs 0xWWRRGGBB
      \channel[0]\leds\led[0] = $00FF0000
      \channel[0]\leds\led[1] = $0000FF00
      \channel[0]\leds\led[2] = $000000FF
      \channel[0]\leds\led[3] = $00FFFFFF
      r1 = ws2811_render(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Render: " + ws2811_get_return_t_str(r1)
        Break
      EndIf
      ws2811_wait(ledstring)
      Delay(2000)
      
      ; LEDs
      \channel[0]\leds\led[0] = $00FFFFFF
      \channel[0]\leds\led[1] = $00FF0000
      \channel[0]\leds\led[2] = $0000FF00
      \channel[0]\leds\led[3] = $000000FF
      r1 = ws2811_render(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Render: " + ws2811_get_return_t_str(r1)
        Break
      EndIf
      ws2811_wait(ledstring)
      Delay(2000)
      
      ; LEDs
      \channel[0]\leds\led[0] = $000000FF
      \channel[0]\leds\led[1] = $00FFFFFF
      \channel[0]\leds\led[2] = $00FF0000
      \channel[0]\leds\led[3] = $0000FF00
      r1 = ws2811_render(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Render: " + ws2811_get_return_t_str(r1)
        Break
      EndIf
      ws2811_wait(ledstring)
      Delay(2000)
      
      \channel[0]\leds\led[0] = $00000000
      \channel[0]\leds\led[1] = $00000000
      \channel[0]\leds\led[2] = $00000000
      \channel[0]\leds\led[3] = $00000000
      r1 = ws2811_render(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Render: " + ws2811_get_return_t_str(r1)
        Break
      EndIf
      Delay(1000)
      
      \channel[0]\leds\led[0] = $0000FF00
      \channel[0]\leds\led[1] = $0000FF00
      \channel[0]\leds\led[2] = $0000FF00
      \channel[0]\leds\led[3] = $0000FF00
      r1 = ws2811_render(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Render: " + ws2811_get_return_t_str(r1)
        Break
      EndIf
      Delay(1000)
      
      \channel[0]\leds\led[0] = $00000000
      \channel[0]\leds\led[1] = $00000000
      \channel[0]\leds\led[2] = $00000000
      \channel[0]\leds\led[3] = $00000000
      r1 = ws2811_render(ledstring)
      If r1 <> #WS2811_SUCCESS
        Debug "Error Render: " + ws2811_get_return_t_str(r1)
        Break
      EndIf
      Delay(1000)
      
    Until #True ; EndDo
  EndWith
  
  ; Clear controler - DMA, etx
  ws2811_fini(ledstring)
  ; Close library
  CloseLib_ws2811()
  
CompilerEndIf