├── .gitignore ├── Makefile ├── README.md ├── am335x ├── app_loader │ ├── include │ │ ├── pruss_intc_mapping.h │ │ └── prussdrv.h │ ├── interface │ │ ├── FIXME │ │ ├── Makefile │ │ ├── __prussdrv.h │ │ └── prussdrv.c │ └── lib │ │ ├── libprussdrv.so │ │ └── libprussdrvd.so └── pasm │ ├── LICENCE.txt │ ├── Makefile │ ├── pasm.c │ ├── pasm.h │ ├── pasmdbg.h │ ├── pasmdot.c │ ├── pasmexp.c │ ├── pasmmacro.c │ ├── pasmop.c │ ├── pasmpp.c │ ├── pasmstruct.c │ └── pru_ins.h ├── dirtrees ├── BB-PRU-00A0.dtbo ├── am335x-bone.dtb ├── am335x-boneblack.dtb └── dtbo_loader.sh ├── examples ├── 2048.cpp ├── binary_clock.cpp ├── clear.cpp ├── clock.cpp ├── fade-test.c ├── fire.c ├── game_of_life.cpp ├── matrix-test.cpp ├── python-test ├── rainbow.pl ├── rgb-test.cpp ├── scroll.cpp └── tile-test.cpp ├── gamma.h ├── gfx.cpp ├── gfx.hpp ├── glcdfont.c ├── matrix.cpp ├── matrix.hpp ├── matrix.i ├── network ├── bbb-network-setup ├── ledscape.service ├── opc-rx.c ├── run-ledscape └── udp-rx.c ├── pixel.cpp ├── pixel.hpp ├── pixel.i ├── pru.c ├── pru.h ├── setup.py ├── util.c ├── util.h ├── ws281x.hp └── ws281x.p /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | .*.swo 3 | *.i 4 | *.o 5 | *.a 6 | *.bin 7 | pcb/*.b[^r][^d] 8 | pcb/*.p[^c][^b] 9 | rgb-test 10 | am335x/pasm/pasm 11 | .*.d 12 | *~ 13 | *~ 14 | a.out 15 | fade-test 16 | fire 17 | udp-rx 18 | opc-rx 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ######### 2 | # 3 | # The top level targets link in the two .o files for now. 4 | # 5 | TARGETS += examples/rgb-test 6 | TARGETS += examples/matrix-test 7 | TARGETS += examples/tile-test 8 | TARGETS += examples/scroll 9 | TARGETS += examples/clear 10 | TARGETS += examples/game_of_life 11 | TARGETS += examples/clock 12 | TARGETS += examples/binary_clock 13 | TARGETS += examples/test 14 | TARGETS += examples/2048 15 | # TARGETS += examples/fade-test 16 | # TARGETS += examples/fire 17 | # TARGETS += network/udp-rx 18 | # TARGETS += network/opc-rx 19 | 20 | PIXELBONE_OBJS = pixel.o gfx.o matrix.o pru.o util.o 21 | PIXELBONE_LIB := libpixelbone.a 22 | 23 | all: $(TARGETS) ws281x.bin 24 | 25 | CFLAGS += \ 26 | -std=c99 \ 27 | -W \ 28 | -Wall \ 29 | -D_BSD_SOURCE \ 30 | -Wp,-MMD,$(dir $@).$(notdir $@).d \ 31 | -Wp,-MT,$@ \ 32 | -I. \ 33 | -O2 \ 34 | -mtune=cortex-a8 \ 35 | -march=armv7-a \ 36 | 37 | LDFLAGS += \ 38 | 39 | LDLIBS += \ 40 | -lpthread \ 41 | 42 | export CROSS_COMPILE:= 43 | 44 | ##### 45 | # 46 | # The TI "app_loader" is the userspace library for talking to 47 | # the PRU and mapping memory between it and the ARM. 48 | # 49 | APP_LOADER_DIR ?= ./am335x/app_loader 50 | APP_LOADER_LIB := $(APP_LOADER_DIR)/lib/libprussdrv.a 51 | CFLAGS += -I$(APP_LOADER_DIR)/include 52 | LDLIBS += $(APP_LOADER_LIB) 53 | 54 | ##### 55 | # 56 | # The TI PRU assembler looks like it has macros and includes, 57 | # but it really doesn't. So instead we use cpp to pre-process the 58 | # file and then strip out all of the directives that it adds. 59 | # PASM also doesn't handle multiple statements per line, so we 60 | # insert hard newline characters for every ; in the file. 61 | # 62 | PASM_DIR ?= ./am335x/pasm 63 | PASM := $(PASM_DIR)/pasm 64 | 65 | %.bin: %.p $(PASM) 66 | $(CPP) - < $< | perl -p -e 's/^#.*//; s/;/\n/g; s/BYTE\((\d+)\)/t\1/g' > $<.i 67 | $(PASM) -V3 -b $<.i $(basename $@) 68 | $(RM) $<.i 69 | 70 | %.o: %.cpp 71 | $(CXX) $(CXXFLAGS) -std=c++11 -c -o $@ $< 72 | 73 | %.o: %.c 74 | $(CC) $(CFLAGS) -c -o $@ $< 75 | 76 | 77 | $(foreach O,$(TARGETS),$(eval $O: $O.o $(PIXELBONE_OBJS) $(APP_LOADER_LIB))) 78 | 79 | $(TARGETS): 80 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) 81 | 82 | 83 | .PHONY: clean 84 | 85 | clean: 86 | rm -rf \ 87 | **/*.o \ 88 | *.o \ 89 | ws281x.hp.i \ 90 | .*.o.d \ 91 | *~ \ 92 | $(INCDIR_APP_LOADER)/*~ \ 93 | $(TARGETS) \ 94 | *.bin \ 95 | 96 | ########### 97 | # 98 | # PRU Libraries and PRU assembler are build from their own trees. 99 | # 100 | $(APP_LOADER_LIB): 101 | $(MAKE) -C $(APP_LOADER_DIR)/interface 102 | 103 | $(PASM): 104 | $(MAKE) -C $(PASM_DIR) 105 | 106 | # Include all of the generated dependency files 107 | -include .*.o.d 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Testing PixelBone](https://lh3.googleusercontent.com/-de4gV0F2_Gk/U1vb6bDet1I/AAAAAAAACJg/mGFfGTMWo4c/w1084-h813-no/IMG_20140426_121532.jpg) 2 | 3 | #DANGER! 4 | 5 | This code works with the PRU units on the BeagleBone and can easily 6 | cause *hard crashes*. It is still being debugged and developed. 7 | Be careful hot-plugging things into the headers -- it is possible to 8 | damage the pin drivers and cause problems in the ARM, especially if 9 | there are +5V signals involved. 10 | 11 | 12 | #Overview 13 | 14 | This is a modified version of the LEDscape library designed to control a single chain of WS2811-based LED modules from a BeagleBone (Black). The timing has been updated and verified to work with both WS2812 and WS2812b chips. This version of the library uses a single PRU on the BeagleBone. This allows sending at about 60fps to strings of 512 pixels or at ~120fps for 256 pixels. 15 | 16 | The bit-unpacking is handled by the PRU, which allows PixelBone to take almost no cpu time to run, freeing up time for the actual generation of animations or dealing with network protocols. 17 | 18 | 19 | #Installation and Usage 20 | 21 | To use PixelBone, download it to your BeagleBone Black. 22 | 23 | First, make sure that PixelBone compiles: 24 | 25 | ```sh 26 | make 27 | ``` 28 | 29 | Before PixelBone will function, you will need to replace the device tree 30 | file and reboot. 31 | 32 | There are two different dtb files in the `dirtrees` folder, one for the original BeagleBone, and one for the BeagleBone Black. There is also an overlay file for other operating systems (such as Arch Linux). Whichever you choose, place it in the proper folder. `/boot/` for the dtb file, or `/usr/lib/firmware/` for the overlay. Please check your distro to make sure this is correct. 33 | 34 | Reboot if you're using the dtb, or run the provided `dtbo_loader.sh` script if using the dtbo. 35 | 36 | Connect a WS2811-based LED chain to the Beagle Bone. The strip must be running at the same voltage as the data signal. If you are using an external 5v supply for the LEDs, you'll need to use a level shifter or other technique to bring the BBB's 3.3v signals up to 5v. 37 | 38 | Once everything is connected, run the `rgb-test` program: 39 | 40 | ```sh 41 | ./examples/rgb-test 42 | ``` 43 | 44 | The LEDs should now be fading prettily. If not, go back and make 45 | sure everything is setup correctly. 46 | 47 | 48 | #Pin Mapping 49 | 50 | The mapping from PixelBone channel to BeagleBone GPIO pin: 51 | 52 | ``` 53 | PixelBone Channel Index 54 | Row Pin# P9 Pin# 55 | 1 1 2 56 | 2 3 4 57 | 3 5 6 58 | 4 7 8 59 | 5 9 10 60 | 6 11 12 61 | 7 13 14 62 | 8 15 16 63 | 9 17 18 64 | 10 19 20 65 | 11 21 [0] 22 66 | 12 23 24 67 | 13 25 26 68 | 14 27 28 69 | 15 29 30 70 | 16 31 32 71 | 17 33 34 72 | 18 35 36 73 | 19 37 38 74 | 20 39 40 75 | 21 41 42 76 | 22 43 44 77 | 23 45 46 78 | 79 | ``` 80 | 81 | The numbers on the inside of each block indicate the PixelBone channel. 82 | 83 | 84 | #Implementation Notes 85 | 86 | The WS281x LED chips are built like shift registers and make for very easy LED strip construction. The signals are duty-cycle modulated, with a 0 measuring 250 ns long and a 1 being 600 ns long, and 1250 ns between bits. Since this doesn't map to normal SPI hardware and requires an 800 KHz bit clock, it is typically handled with a dedicated microcontroller or DMA hardware on something like the Teensy 3. 87 | 88 | However, the TI AM335x ARM Cortex-A8 in the BeagleBone has two programmable "microcontrollers" built into the CPU that can handle realtime tasks and also access the ARM's memory. This allows things that might have been delegated to external devices to be handled without any additional hardware, and without the overhead of clocking data out the USB port. 89 | 90 | The frames are stored in memory as a series of 4-byte pixels in the order GRBA. This means that it looks like this in RAM: 91 | 92 | `S0P0 S0P1 S0P2 ... etc` 93 | 94 | 4 * 32 * length bytes are required per frame buffer. The maximum frame rate also depends on the length. 95 | 96 | 97 | API 98 | === 99 | 100 | `pixel.hpp` and `matrix.hpp` defines the API. The key components are: 101 | 102 | ```cpp 103 | class PixelBone_Pixel { 104 | public: 105 | PixelBone_Pixel(uint16_t pixel_count); 106 | void show(void); 107 | void clear(void); 108 | void setPixelColor(uint32_t n, uint8_t r, uint8_t g, uint8_t b); 109 | void setPixelColor(uint32_t n, uint32_t c); 110 | void moveToNextBuffer(); 111 | uint32_t wait(); 112 | uint32_t numPixels() const; 113 | uint32_t getPixelColor(uint32_t n) const; 114 | static uint32_t Color(uint8_t red, uint8_t green, uint8_t blue); 115 | static uint32_t HSB(uint16_t hue, uint8_t saturation, uint8_t brightness); 116 | }; 117 | 118 | class PixelBone_Matrix{ 119 | public: 120 | // Constructor for single matrix: 121 | PixelBone_Matrix(int w, int h, 122 | uint8_t matrixType = MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS); 123 | 124 | // Constructor for tiled matrices: 125 | PixelBone_Matrix(uint8_t matrixW, uint8_t matrixH, uint8_t tX, uint8_t tY, 126 | uint8_t matrixType = MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS + 127 | TILE_TOP + TILE_LEFT + TILE_ROWS); 128 | 129 | void drawPixel(int16_t x, int16_t y, uint16_t color); 130 | void fillScreen(uint16_t color); 131 | static uint16_t Color(uint8_t r, uint8_t g, uint8_t b); 132 | }; 133 | ``` 134 | 135 | You can double buffer like this: 136 | 137 | ```cpp 138 | const int num_pixels = 256; 139 | PixelBone_Pixel strip(num_pixels); 140 | 141 | while (true) { 142 | render(strip); //modify the pixels here 143 | 144 | // wait for the previous frame to finish; 145 | strip.wait(); 146 | strip.show() 147 | 148 | // Alternate frame buffers on each draw command 149 | strip.moveToNextBuffer(); 150 | } 151 | ``` 152 | 153 | The 24-bit RGB data to be displayed is laid out with BRGA format, 154 | since that is how it will be translated during the clock out from the PRU. 155 | 156 | ```cpp 157 | struct PixelBone_pixel_t{ 158 | uint8_t b; 159 | uint8_t r; 160 | uint8_t g; 161 | uint8_t a; 162 | } __attribute__((__packed__)); 163 | ``` 164 | 165 | #Low level API 166 | 167 | If you want to poke at the PRU directly, there is a command structure 168 | shared in PRU DRAM that holds a pointer to the current frame buffer, 169 | the length in pixels, a command byte and a response byte. 170 | Once the PRU has cleared the command byte you are free to re-write the 171 | dma address or number of pixels. 172 | 173 | ```cpp 174 | struct ws281x_command_t { 175 | // in the DDR shared with the PRU 176 | const uintptr_t pixels_dma; 177 | 178 | // Length in pixels of the longest LED strip. 179 | unsigned num_pixels; 180 | 181 | // write 1 to start, 0xFF to abort. will be cleared when started 182 | volatile unsigned command; 183 | 184 | // will have a non-zero response written when done 185 | volatile unsigned response; 186 | } __attribute__((__packed__)); 187 | ``` 188 | 189 | Reference 190 | ========== 191 | * http://www.adafruit.com/products/1138 192 | * http://www.adafruit.com/datasheets/WS2811.pdf 193 | -------------------------------------------------------------------------------- /am335x/app_loader/include/pruss_intc_mapping.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pruss_intc_mapping.h 3 | * 4 | * Example PRUSS INTC mapping for the application 5 | * 6 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 7 | * 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 13 | * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 16 | * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the 19 | * distribution. 20 | * 21 | * Neither the name of Texas Instruments Incorporated nor the names of 22 | * its contributors may be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | /* 40 | * ============================================================================ 41 | * Copyright (c) Texas Instruments Inc 2010-11 42 | * 43 | * Use of this software is controlled by the terms and conditions found in the 44 | * license agreement under which this software has been supplied or provided. 45 | * ============================================================================ 46 | */ 47 | 48 | #define AM33XX 49 | #ifdef AM33XX 50 | #define PRU0_PRU1_INTERRUPT 17 51 | #define PRU1_PRU0_INTERRUPT 18 52 | #define PRU0_ARM_INTERRUPT 19 53 | #define PRU1_ARM_INTERRUPT 20 54 | #define ARM_PRU0_INTERRUPT 21 55 | #define ARM_PRU1_INTERRUPT 22 56 | #else 57 | #define PRU0_PRU1_INTERRUPT 32 58 | #define PRU1_PRU0_INTERRUPT 33 59 | #define PRU0_ARM_INTERRUPT 34 60 | #define PRU1_ARM_INTERRUPT 35 61 | #define ARM_PRU0_INTERRUPT 36 62 | #define ARM_PRU1_INTERRUPT 37 63 | #endif 64 | #define CHANNEL0 0 65 | #define CHANNEL1 1 66 | #define CHANNEL2 2 67 | #define CHANNEL3 3 68 | #define CHANNEL4 4 69 | #define CHANNEL5 5 70 | #define CHANNEL6 6 71 | #define CHANNEL7 7 72 | #define CHANNEL8 8 73 | #define CHANNEL9 9 74 | 75 | #define PRU0 0 76 | #define PRU1 1 77 | #define PRU_EVTOUT0 2 78 | #define PRU_EVTOUT1 3 79 | #define PRU_EVTOUT2 4 80 | #define PRU_EVTOUT3 5 81 | #define PRU_EVTOUT4 6 82 | #define PRU_EVTOUT5 7 83 | #define PRU_EVTOUT6 8 84 | #define PRU_EVTOUT7 9 85 | 86 | #define PRU0_HOSTEN_MASK 0x0001 87 | #define PRU1_HOSTEN_MASK 0x0002 88 | #define PRU_EVTOUT0_HOSTEN_MASK 0x0004 89 | #define PRU_EVTOUT1_HOSTEN_MASK 0x0008 90 | #define PRU_EVTOUT2_HOSTEN_MASK 0x0010 91 | #define PRU_EVTOUT3_HOSTEN_MASK 0x0020 92 | #define PRU_EVTOUT4_HOSTEN_MASK 0x0040 93 | #define PRU_EVTOUT5_HOSTEN_MASK 0x0080 94 | #define PRU_EVTOUT6_HOSTEN_MASK 0x0100 95 | #define PRU_EVTOUT7_HOSTEN_MASK 0x0200 96 | 97 | 98 | #define PRUSS_INTC_INITDATA { \ 99 | { PRU0_PRU1_INTERRUPT, PRU1_PRU0_INTERRUPT, PRU0_ARM_INTERRUPT, PRU1_ARM_INTERRUPT, ARM_PRU0_INTERRUPT, ARM_PRU1_INTERRUPT, (char)-1 }, \ 100 | { {PRU0_PRU1_INTERRUPT,CHANNEL1}, {PRU1_PRU0_INTERRUPT, CHANNEL0}, {PRU0_ARM_INTERRUPT,CHANNEL2}, {PRU1_ARM_INTERRUPT, CHANNEL3}, {ARM_PRU0_INTERRUPT, CHANNEL0}, {ARM_PRU1_INTERRUPT, CHANNEL1}, {-1,-1}}, \ 101 | { {CHANNEL0,PRU0}, {CHANNEL1, PRU1}, {CHANNEL2, PRU_EVTOUT0}, {CHANNEL3, PRU_EVTOUT1}, {-1,-1} }, \ 102 | (PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK | PRU_EVTOUT1_HOSTEN_MASK) /*Enable PRU0, PRU1, PRU_EVTOUT0 */ \ 103 | } \ 104 | 105 | -------------------------------------------------------------------------------- /am335x/app_loader/include/prussdrv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * prussdrv.h 3 | * 4 | * Describes PRUSS userspace driver for Industrial Communications 5 | * 6 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 7 | * 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 13 | * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 16 | * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the 19 | * distribution. 20 | * 21 | * Neither the name of Texas Instruments Incorporated nor the names of 22 | * its contributors may be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | /* 40 | * ============================================================================ 41 | * Copyright (c) Texas Instruments Inc 2010-11 42 | * 43 | * Use of this software is controlled by the terms and conditions found in the 44 | * license agreement under which this software has been supplied or provided. 45 | * ============================================================================ 46 | */ 47 | 48 | #ifndef _PRUSSDRV_H 49 | #define _PRUSSDRV_H 50 | 51 | #include 52 | 53 | #if defined (__cplusplus) 54 | extern "C" { 55 | #endif 56 | 57 | #define NUM_PRU_HOSTIRQS 8 58 | #define NUM_PRU_HOSTS 10 59 | #define NUM_PRU_CHANNELS 10 60 | #define NUM_PRU_SYS_EVTS 64 61 | 62 | #define PRUSS0_PRU0_DATARAM 0 63 | #define PRUSS0_PRU1_DATARAM 1 64 | #define PRUSS0_PRU0_IRAM 2 65 | #define PRUSS0_PRU1_IRAM 3 66 | 67 | #define PRUSS_V1 1 // AM18XX 68 | #define PRUSS_V2 2 // AM33XX 69 | 70 | //Available in AM33xx series - begin 71 | #define PRUSS0_SHARED_DATARAM 4 72 | #define PRUSS0_CFG 5 73 | #define PRUSS0_UART 6 74 | #define PRUSS0_IEP 7 75 | #define PRUSS0_ECAP 8 76 | #define PRUSS0_MII_RT 9 77 | #define PRUSS0_MDIO 10 78 | //Available in AM33xx series - end 79 | 80 | #define PRU_EVTOUT_0 0 81 | #define PRU_EVTOUT_1 1 82 | #define PRU_EVTOUT_2 2 83 | #define PRU_EVTOUT_3 3 84 | #define PRU_EVTOUT_4 4 85 | #define PRU_EVTOUT_5 5 86 | #define PRU_EVTOUT_6 6 87 | #define PRU_EVTOUT_7 7 88 | 89 | typedef struct __sysevt_to_channel_map { 90 | short sysevt; 91 | short channel; 92 | } tsysevt_to_channel_map; 93 | typedef struct __channel_to_host_map { 94 | short channel; 95 | short host; 96 | } tchannel_to_host_map; 97 | typedef struct __pruss_intc_initdata { 98 | //Enabled SYSEVTs - Range:0..63 99 | //{-1} indicates end of list 100 | char sysevts_enabled[NUM_PRU_SYS_EVTS]; 101 | //SysEvt to Channel map. SYSEVTs - Range:0..63 Channels -Range: 0..9 102 | //{-1, -1} indicates end of list 103 | tsysevt_to_channel_map sysevt_to_channel_map[NUM_PRU_SYS_EVTS]; 104 | //Channel to Host map.Channels -Range: 0..9 HOSTs - Range:0..9 105 | //{-1, -1} indicates end of list 106 | tchannel_to_host_map channel_to_host_map[NUM_PRU_CHANNELS]; 107 | //10-bit mask - Enable Host0-Host9 {Host0/1:PRU0/1, Host2..9 : PRUEVT_OUT0..7} 108 | unsigned int host_enable_bitmask; 109 | } tpruss_intc_initdata; 110 | 111 | int prussdrv_init(void); 112 | 113 | int prussdrv_open(unsigned int host_interrupt); 114 | 115 | /** Return version of PRU. This must be called after prussdrv_open. */ 116 | int prussdrv_version(); 117 | 118 | /** Return string description of PRU version. */ 119 | const char* prussdrv_strversion(int version); 120 | 121 | int prussdrv_pru_reset(unsigned int prunum); 122 | 123 | int prussdrv_pru_disable(unsigned int prunum); 124 | 125 | int prussdrv_pru_enable(unsigned int prunum); 126 | 127 | int prussdrv_pru_write_memory(unsigned int pru_ram_id, 128 | unsigned int wordoffset, 129 | const unsigned int *memarea, 130 | unsigned int bytelength); 131 | 132 | int prussdrv_pruintc_init(const tpruss_intc_initdata *prussintc_init_data); 133 | 134 | /** Find and return the channel a specified event is mapped to. 135 | * Note that this only searches for the first channel mapped and will not 136 | * detect error cases where an event is mapped erroneously to multiple 137 | * channels. 138 | * @return channel-number to which a system event is mapped. 139 | * @return -1 for no mapping found 140 | */ 141 | short prussdrv_get_event_to_channel_map( unsigned int eventnum ); 142 | 143 | /** Find and return the host interrupt line a specified channel is mapped 144 | * to. Note that this only searches for the first host interrupt line 145 | * mapped and will not detect error cases where a channel is mapped 146 | * erroneously to multiple host interrupt lines. 147 | * @return host-interrupt-line to which a channel is mapped. 148 | * @return -1 for no mapping found 149 | */ 150 | short prussdrv_get_channel_to_host_map( unsigned int channel ); 151 | 152 | /** Find and return the host interrupt line a specified event is mapped 153 | * to. This first finds the intermediate channel and then the host. 154 | * @return host-interrupt-line to which a system event is mapped. 155 | * @return -1 for no mapping found 156 | */ 157 | short prussdrv_get_event_to_host_map( unsigned int eventnum ); 158 | 159 | int prussdrv_map_l3mem(void **address); 160 | 161 | int prussdrv_map_extmem(void **address); 162 | 163 | unsigned int prussdrv_extmem_size(void); 164 | 165 | int prussdrv_map_prumem(unsigned int pru_ram_id, void **address); 166 | 167 | int prussdrv_map_peripheral_io(unsigned int per_id, void **address); 168 | 169 | unsigned int prussdrv_get_phys_addr(const void *address); 170 | 171 | void *prussdrv_get_virt_addr(unsigned int phyaddr); 172 | 173 | /** Wait for the specified host interrupt. 174 | * @return the number of times the event has happened. */ 175 | unsigned int prussdrv_pru_wait_event(unsigned int host_interrupt); 176 | 177 | int prussdrv_pru_event_fd(unsigned int host_interrupt); 178 | 179 | int prussdrv_pru_send_event(unsigned int eventnum); 180 | 181 | /** Clear the specified event and re-enable the host interrupt. */ 182 | int prussdrv_pru_clear_event(unsigned int host_interrupt, 183 | unsigned int sysevent); 184 | 185 | int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum, 186 | unsigned int host_interrupt, 187 | unsigned int ack_eventnum); 188 | 189 | int prussdrv_exit(void); 190 | 191 | int prussdrv_exec_program(int prunum, const char *filename); 192 | 193 | int prussdrv_exec_code(int prunum, const unsigned int *code, int codelen); 194 | 195 | #if defined (__cplusplus) 196 | } 197 | #endif 198 | #endif 199 | -------------------------------------------------------------------------------- /am335x/app_loader/interface/FIXME: -------------------------------------------------------------------------------- 1 | is there a cleaner way to have the host interrupts be assigned so that we don't 2 | have to do the +-2 all the time? 3 | -------------------------------------------------------------------------------- /am335x/app_loader/interface/Makefile: -------------------------------------------------------------------------------- 1 | ROOTDIR = .. 2 | TARGET = libprussdrv 3 | CROSS_COMPILE?=arm-arago-linux-gnueabi- 4 | PREFIX?=/usr/local 5 | 6 | CC = $(CROSS_COMPILE)gcc 7 | AR = $(CROSS_COMPILE)ar 8 | 9 | INCLUDEDIR = ../include 10 | LIBDIR = ../lib 11 | 12 | C_FLAGS += -I. -Wall -I$(INCLUDEDIR) 13 | 14 | COMPILE.c = $(CC) $(C_FLAGS) $(CPP_FLAGS) -c 15 | AR.c = $(AR) rc 16 | LINK.c = $(CC) -shared 17 | 18 | DBGTARGET = $(LIBDIR)/$(TARGET)d.a 19 | RELTARGET = $(LIBDIR)/$(TARGET).a 20 | SODBGTARGET = $(LIBDIR)/$(TARGET)d.so 21 | SORELTARGET = $(LIBDIR)/$(TARGET).so 22 | 23 | DBGCFLAGS = -g -O0 -D__DEBUG 24 | RELCFLAGS = -O3 -mtune=cortex-a8 -march=armv7-a 25 | 26 | SOURCES = $(wildcard *.c) 27 | 28 | PUBLIC_HDRS = $(wildcard $(INCLUDEDIR)/*.h) 29 | PRIVATE_HDRS = $(wildcard *.h) 30 | HEADERS = $(PUBLIC_HDRS) $(PRIVATE_HDRS) 31 | 32 | DBGOBJFILES = $(SOURCES:%.c=debug/%.o) 33 | RELOBJFILES = $(SOURCES:%.c=release/%.o) 34 | PIC_DBGOBJFILES = $(SOURCES:%.c=debug/%_PIC.o) 35 | PIC_RELOBJFILES = $(SOURCES:%.c=release/%_PIC.o) 36 | 37 | .PHONY: clean debug release sodebug sorelease install 38 | 39 | all: debug release sodebug sorelease 40 | 41 | install: release 42 | install -m 0755 -d $(DESTDIR)$(PREFIX)/lib 43 | install -m 0755 -d $(DESTDIR)$(PREFIX)/include 44 | install -m 0644 $(LIBDIR)/* $(DESTDIR)$(PREFIX)/lib 45 | install -m 0644 $(PUBLIC_HDRS) $(DESTDIR)$(PREFIX)/include 46 | 47 | release: $(RELTARGET) 48 | 49 | sorelease: $(SORELTARGET) 50 | 51 | sodebug: $(SODBGTARGET) 52 | 53 | debug: $(DBGTARGET) 54 | 55 | $(RELTARGET): $(RELOBJFILES) 56 | @mkdir -p $(ROOTDIR)/lib 57 | $(AR.c) $@ $(RELOBJFILES) 58 | 59 | $(SORELTARGET): $(PIC_RELOBJFILES) 60 | @mkdir -p $(ROOTDIR)/lib 61 | $(LINK.c) -o $@ $(PIC_RELOBJFILES) 62 | 63 | $(SODBGTARGET): $(PIC_DBGOBJFILES) 64 | @mkdir -p $(ROOTDIR)/lib 65 | $(LINK.c) -o $@ $(PIC_DBGOBJFILES) 66 | 67 | $(DBGTARGET): $(DBGOBJFILES) 68 | @mkdir -p $(ROOTDIR)/lib 69 | $(AR.c) $@ $(DBGOBJFILES) 70 | 71 | $(RELOBJFILES): release/%.o: %.c $(HEADERS) 72 | @mkdir -p release 73 | $(COMPILE.c) $(RELCFLAGS) -o $@ $< 74 | 75 | $(PIC_RELOBJFILES): release/%_PIC.o: %.c $(HEADERS) 76 | @mkdir -p release 77 | $(COMPILE.c) -fPIC $(RELCFLAGS) -o $@ $< 78 | 79 | $(DBGOBJFILES): debug/%.o: %.c $(HEADERS) 80 | @mkdir -p debug 81 | $(COMPILE.c) $(DBGCFLAGS) -o $@ $< 82 | 83 | $(PIC_DBGOBJFILES): debug/%_PIC.o: %.c $(HEADERS) 84 | @mkdir -p debug 85 | $(COMPILE.c) -fPIC $(DBGCFLAGS) -o $@ $< 86 | 87 | clean: 88 | -rm -rf release debug *~ ../lib/* 89 | -------------------------------------------------------------------------------- /am335x/app_loader/interface/__prussdrv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * __prussdrv.h 3 | * 4 | * 5 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 6 | * 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the 18 | * distribution. 19 | * 20 | * Neither the name of Texas Instruments Incorporated nor the names of 21 | * its contributors may be used to endorse or promote products derived 22 | * from this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | /* 39 | * ============================================================================ 40 | * Copyright (c) Texas Instruments Inc 2010-12 41 | * 42 | * Use of this software is controlled by the terms and conditions found in the 43 | * license agreement under which this software has been supplied or provided. 44 | * ============================================================================ 45 | */ 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | #include 63 | 64 | #define DISABLE_L3RAM_SUPPORT 65 | 66 | #define PAGE_SIZE 4096 67 | 68 | #define PRUSS_V1_STR "AM18XX" 69 | #define PRUSS_V2_STR "AM33XX" 70 | #define PRUSS_UNKNOWN_STR "UNKNOWN" 71 | 72 | #define AM33XX_PRUSS_INTC_REV 0x4E82A900 73 | #define AM18XX_PRUSS_INTC_REV 0x4E825900 74 | 75 | #define PRUSS_MAX_IRAM_SIZE 8192 76 | 77 | #define AM33XX_PRUSS_IRAM_SIZE 8192 78 | #define AM33XX_PRUSS_MMAP_SIZE 0x40000 79 | #define AM33XX_DATARAM0_PHYS_BASE 0x4a300000 80 | #define AM33XX_DATARAM1_PHYS_BASE 0x4a302000 81 | #define AM33XX_INTC_PHYS_BASE 0x4a320000 82 | #define AM33XX_PRU0CONTROL_PHYS_BASE 0x4a322000 83 | #define AM33XX_PRU0DEBUG_PHYS_BASE 0x4a322400 84 | #define AM33XX_PRU1CONTROL_PHYS_BASE 0x4a324000 85 | #define AM33XX_PRU1DEBUG_PHYS_BASE 0x4a324400 86 | #define AM33XX_PRU0IRAM_PHYS_BASE 0x4a334000 87 | #define AM33XX_PRU1IRAM_PHYS_BASE 0x4a338000 88 | #define AM33XX_PRUSS_SHAREDRAM_BASE 0x4a310000 89 | #define AM33XX_PRUSS_CFG_BASE 0x4a326000 90 | #define AM33XX_PRUSS_UART_BASE 0x4a328000 91 | #define AM33XX_PRUSS_IEP_BASE 0x4a32e000 92 | #define AM33XX_PRUSS_ECAP_BASE 0x4a330000 93 | #define AM33XX_PRUSS_MIIRT_BASE 0x4a332000 94 | #define AM33XX_PRUSS_MDIO_BASE 0x4a332400 95 | 96 | #define AM18XX_PRUSS_IRAM_SIZE 4096 97 | #define AM18XX_PRUSS_MMAP_SIZE 0x7C00 98 | #define AM18XX_DATARAM0_PHYS_BASE 0x01C30000 99 | #define AM18XX_DATARAM1_PHYS_BASE 0x01C32000 100 | #define AM18XX_INTC_PHYS_BASE 0x01C34000 101 | #define AM18XX_PRU0CONTROL_PHYS_BASE 0x01C37000 102 | #define AM18XX_PRU0DEBUG_PHYS_BASE 0x01C37400 103 | #define AM18XX_PRU1CONTROL_PHYS_BASE 0x01C37800 104 | #define AM18XX_PRU1DEBUG_PHYS_BASE 0x01C37C00 105 | #define AM18XX_PRU0IRAM_PHYS_BASE 0x01C38000 106 | #define AM18XX_PRU1IRAM_PHYS_BASE 0x01C3C000 107 | 108 | //PRUSS INTC register offsets 109 | #define PRU_INTC_REVID_REG 0x000 110 | #define PRU_INTC_CR_REG 0x004 111 | #define PRU_INTC_HCR_REG 0x00C 112 | #define PRU_INTC_GER_REG 0x010 113 | #define PRU_INTC_GNLR_REG 0x01C 114 | #define PRU_INTC_SISR_REG 0x020 115 | #define PRU_INTC_SICR_REG 0x024 116 | #define PRU_INTC_EISR_REG 0x028 117 | #define PRU_INTC_EICR_REG 0x02C 118 | #define PRU_INTC_HIEISR_REG 0x034 119 | #define PRU_INTC_HIDISR_REG 0x038 120 | #define PRU_INTC_GPIR_REG 0x080 121 | 122 | #define PRU_INTC_SRSR1_REG 0x200 123 | #define PRU_INTC_SRSR2_REG 0x204 124 | 125 | #define PRU_INTC_SECR1_REG 0x280 126 | #define PRU_INTC_SECR2_REG 0x284 127 | 128 | #define PRU_INTC_ESR1_REG 0x300 129 | #define PRU_INTC_ESR2_REG 0x304 130 | 131 | #define PRU_INTC_ECR1_REG 0x380 132 | #define PRU_INTC_ECR2_REG 0x384 133 | 134 | #define PRU_INTC_CMR1_REG 0x400 135 | #define PRU_INTC_CMR2_REG 0x404 136 | #define PRU_INTC_CMR3_REG 0x408 137 | #define PRU_INTC_CMR4_REG 0x40C 138 | #define PRU_INTC_CMR5_REG 0x410 139 | #define PRU_INTC_CMR6_REG 0x414 140 | #define PRU_INTC_CMR7_REG 0x418 141 | #define PRU_INTC_CMR8_REG 0x41C 142 | #define PRU_INTC_CMR9_REG 0x420 143 | #define PRU_INTC_CMR10_REG 0x424 144 | #define PRU_INTC_CMR11_REG 0x428 145 | #define PRU_INTC_CMR12_REG 0x42C 146 | #define PRU_INTC_CMR13_REG 0x430 147 | #define PRU_INTC_CMR14_REG 0x434 148 | #define PRU_INTC_CMR15_REG 0x438 149 | #define PRU_INTC_CMR16_REG 0x43C 150 | 151 | #define PRU_INTC_HMR1_REG 0x800 152 | #define PRU_INTC_HMR2_REG 0x804 153 | #define PRU_INTC_HMR3_REG 0x808 154 | 155 | #define PRU_INTC_SIPR1_REG 0xD00 156 | #define PRU_INTC_SIPR2_REG 0xD04 157 | 158 | #define PRU_INTC_SITR1_REG 0xD80 159 | #define PRU_INTC_SITR2_REG 0xD84 160 | 161 | #define PRU_INTC_HIER_REG 0x1500 162 | 163 | 164 | #define MAX_HOSTS_SUPPORTED 10 165 | 166 | //UIO driver expects user space to map PRUSS_UIO_MAP_OFFSET_XXX to 167 | //access corresponding memory regions - region offset is N*PAGE_SIZE 168 | 169 | #define PRUSS_UIO_MAP_OFFSET_PRUSS 0*PAGE_SIZE 170 | #define PRUSS_UIO_DRV_PRUSS_BASE "/sys/class/uio/uio0/maps/map0/addr" 171 | #define PRUSS_UIO_DRV_PRUSS_SIZE "/sys/class/uio/uio0/maps/map0/size" 172 | 173 | #ifndef DISABLE_L3RAM_SUPPORT 174 | 175 | #define PRUSS_UIO_MAP_OFFSET_L3RAM 1*PAGE_SIZE 176 | #define PRUSS_UIO_DRV_L3RAM_BASE "/sys/class/uio/uio0/maps/map1/addr" 177 | #define PRUSS_UIO_DRV_L3RAM_SIZE "/sys/class/uio/uio0/maps/map1/size" 178 | 179 | #define PRUSS_UIO_MAP_OFFSET_EXTRAM 2*PAGE_SIZE 180 | #define PRUSS_UIO_DRV_EXTRAM_BASE "/sys/class/uio/uio0/maps/map2/addr" 181 | #define PRUSS_UIO_DRV_EXTRAM_SIZE "/sys/class/uio/uio0/maps/map2/size" 182 | 183 | #else 184 | 185 | #define PRUSS_UIO_MAP_OFFSET_EXTRAM 1*PAGE_SIZE 186 | #define PRUSS_UIO_DRV_EXTRAM_BASE "/sys/class/uio/uio0/maps/map1/addr" 187 | #define PRUSS_UIO_DRV_EXTRAM_SIZE "/sys/class/uio/uio0/maps/map1/size" 188 | 189 | 190 | #endif 191 | 192 | 193 | typedef struct __prussdrv { 194 | int version; 195 | int fd[NUM_PRU_HOSTIRQS]; 196 | void *pru0_dataram_base; 197 | void *pru1_dataram_base; 198 | void *intc_base; 199 | void *pru0_control_base; 200 | void *pru0_debug_base; 201 | void *pru1_control_base; 202 | void *pru1_debug_base; 203 | void *pru0_iram_base; 204 | void *pru1_iram_base; 205 | void *l3ram_base; 206 | void *extram_base; 207 | int mmap_fd; 208 | void *pruss_sharedram_base; 209 | void *pruss_cfg_base; 210 | void *pruss_uart_base; 211 | void *pruss_iep_base; 212 | void *pruss_ecap_base; 213 | void *pruss_miirt_base; 214 | void *pruss_mdio_base; 215 | unsigned int pru0_dataram_phy_base; 216 | unsigned int pru1_dataram_phy_base; 217 | unsigned int intc_phy_base; 218 | unsigned int pru0_control_phy_base; 219 | unsigned int pru0_debug_phy_base; 220 | unsigned int pru1_control_phy_base; 221 | unsigned int pru1_debug_phy_base; 222 | unsigned int pru0_iram_phy_base; 223 | unsigned int pru1_iram_phy_base; 224 | unsigned int l3ram_phy_base; 225 | unsigned int extram_phy_base; 226 | unsigned int pruss_sharedram_phy_base; 227 | unsigned int pruss_cfg_phy_base; 228 | unsigned int pruss_uart_phy_base; 229 | unsigned int pruss_iep_phy_base; 230 | unsigned int pruss_ecap_phy_base; 231 | unsigned int pruss_miirt_phy_base; 232 | unsigned int pruss_mdio_phy_base; 233 | unsigned int pruss_phys_base; 234 | unsigned int pruss_map_size; 235 | unsigned int l3ram_phys_base; 236 | unsigned int l3ram_map_size; 237 | unsigned int extram_phys_base; 238 | unsigned int extram_map_size; 239 | tpruss_intc_initdata intc_data; 240 | } tprussdrv; 241 | 242 | 243 | int __pruss_detect_hw_version(unsigned int *pruss_io) 244 | { 245 | 246 | if (pruss_io[(AM18XX_INTC_PHYS_BASE - AM18XX_DATARAM0_PHYS_BASE) >> 2] 247 | == AM18XX_PRUSS_INTC_REV) 248 | return PRUSS_V1; 249 | else { 250 | if (pruss_io 251 | [(AM33XX_INTC_PHYS_BASE - AM33XX_DATARAM0_PHYS_BASE) >> 2] == 252 | AM33XX_PRUSS_INTC_REV) 253 | return PRUSS_V2; 254 | else 255 | return -1; 256 | } 257 | } 258 | 259 | void __prussintc_set_cmr(unsigned int *pruintc_io, unsigned short sysevt, 260 | unsigned short channel) 261 | { 262 | pruintc_io[(PRU_INTC_CMR1_REG + (sysevt & ~(0x3))) >> 2] |= 263 | ((channel & 0xF) << ((sysevt & 0x3) << 3)); 264 | 265 | } 266 | 267 | 268 | void __prussintc_set_hmr(unsigned int *pruintc_io, unsigned short channel, 269 | unsigned short host) 270 | { 271 | pruintc_io[(PRU_INTC_HMR1_REG + (channel & ~(0x3))) >> 2] = 272 | pruintc_io[(PRU_INTC_HMR1_REG + 273 | (channel & ~(0x3))) >> 2] | (((host) & 0xF) << 274 | (((channel) & 0x3) << 3)); 275 | 276 | } 277 | -------------------------------------------------------------------------------- /am335x/app_loader/lib/libprussdrv.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toroidal-code/PixelBone/a5a432ebe30c61190d280cecd7d000bffef48622/am335x/app_loader/lib/libprussdrv.so -------------------------------------------------------------------------------- /am335x/app_loader/lib/libprussdrvd.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toroidal-code/PixelBone/a5a432ebe30c61190d280cecd7d000bffef48622/am335x/app_loader/lib/libprussdrvd.so -------------------------------------------------------------------------------- /am335x/pasm/LICENCE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * {module name} 3 | * 4 | * {module description} 5 | * 6 | * Copyright (C) {YEAR} Texas Instruments Incorporated - http://www.ti.com/ 7 | * 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 13 | * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 16 | * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the 19 | * distribution. 20 | * 21 | * Neither the name of Texas Instruments Incorporated nor the names of 22 | * its contributors may be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | 40 | -------------------------------------------------------------------------------- /am335x/pasm/Makefile: -------------------------------------------------------------------------------- 1 | # Builds with whatever the host format is 2 | CC := gcc 3 | 4 | CFLAGS += \ 5 | -O3 \ 6 | -W \ 7 | -Wall \ 8 | -D_UNIX_ \ 9 | 10 | OBJS := \ 11 | pasm.o \ 12 | pasmpp.o \ 13 | pasmexp.o \ 14 | pasmop.o \ 15 | pasmdot.o \ 16 | pasmstruct.o \ 17 | pasmmacro.o \ 18 | 19 | all: pasm 20 | 21 | pasm: $(OBJS) 22 | $(CC) -o $@ $^ 23 | 24 | clean: 25 | $(RM) -f *.o 26 | 27 | 28 | -------------------------------------------------------------------------------- /am335x/pasm/pasmdbg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pasmdbg.h 3 | * 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the 17 | * distribution. 18 | * 19 | * Neither the name of Texas Instruments Incorporated nor the names of 20 | * its contributors may be used to endorse or promote products derived 21 | * from this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | 37 | /*=========================================================================== 38 | * Copyright (c) Texas Instruments Inc 2010-12 39 | * 40 | * Use of this software is controlled by the terms and conditions found in the 41 | * license agreement under which this software has been supplied or provided. 42 | * ============================================================================ 43 | */ 44 | 45 | /*=========================================================================== 46 | // PASM - PRU Assembler 47 | //--------------------------------------------------------------------------- 48 | // 49 | // File : pasmdbg.h 50 | // 51 | // Description: 52 | // File format for pView debugger debug file 53 | // 54 | //--------------------------------------------------------------------------- 55 | // Revision: 56 | // 21-Jun-13: 0.84 - Open source version 57 | ============================================================================*/ 58 | 59 | #define DBGFILE_NAMELEN_SHORT 64 60 | 61 | typedef struct _DBGFILE_HEADER { 62 | unsigned int FileID; 63 | #define DBGFILE_FILEID_VER3 (0x10150000 | 0x03) 64 | unsigned int LabelCount; /* Number of label records */ 65 | unsigned int LabelOffset; /* File offset to label records */ 66 | unsigned int FileCount; /* Number of file records */ 67 | unsigned int FileOffset; /* File offset to file records */ 68 | unsigned int CodeCount; /* Number of code records */ 69 | unsigned int CodeOffset; /* File offset to code records */ 70 | unsigned int EntryPoint; /* Program entrypoint */ 71 | unsigned int Flags; /* File format flags */ 72 | #define DBGHDR_FLAGS_BIGENDIAN 0x00000001 73 | } DBGFILE_HEADER; 74 | 75 | typedef struct _DBGFILE_LABEL { 76 | unsigned int AddrOffset; 77 | char Name[DBGFILE_NAMELEN_SHORT]; 78 | } DBGFILE_LABEL; 79 | 80 | typedef struct _DBGFILE_FILE { 81 | char SourceName[DBGFILE_NAMELEN_SHORT]; 82 | } DBGFILE_FILE; 83 | 84 | typedef struct _DBGFILE_CODE { 85 | unsigned char Flags; /* Record flags */ 86 | #define DBGFILE_CODE_FLG_FILEINFO 0x01 87 | #define DBGFILE_CODE_FLG_CANMAP 0x02 88 | unsigned char Resv8; /* Reserved */ 89 | unsigned short FileIndex; /* Source file index */ 90 | unsigned int Line; /* The line number */ 91 | unsigned int AddrOffset; /* Code address offset */ 92 | unsigned int CodeWord; /* Code */ 93 | } DBGFILE_CODE; 94 | -------------------------------------------------------------------------------- /am335x/pasm/pasmdot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pasmdot.c 3 | * 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the 17 | * distribution. 18 | * 19 | * Neither the name of Texas Instruments Incorporated nor the names of 20 | * its contributors may be used to endorse or promote products derived 21 | * from this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | 37 | /*=========================================================================== 38 | * Copyright (c) Texas Instruments Inc 2010-12 39 | * 40 | * Use of this software is controlled by the terms and conditions found in the 41 | * license agreement under which this software has been supplied or provided. 42 | * ============================================================================ 43 | */ 44 | 45 | /*=========================================================================== 46 | // PASM - PRU Assembler 47 | //--------------------------------------------------------------------------- 48 | // 49 | // File : pasmdot.c 50 | // 51 | // Description: 52 | // Processes the "dot" commands (.ret, .origin, .main, etc.) 53 | // 54 | //--------------------------------------------------------------------------- 55 | // Revision: 56 | // 21-Jun-13: 0.84 - Open source version 57 | ============================================================================*/ 58 | 59 | #include 60 | #include 61 | #include 62 | #if !defined(__APPLE__) 63 | #include 64 | #else 65 | #include 66 | #endif 67 | #include 68 | #include "pasm.h" 69 | 70 | #define DOTCMD_MAIN 0 71 | #define DOTCMD_END 1 72 | #define DOTCMD_PROC 2 73 | #define DOTCMD_RET 3 74 | #define DOTCMD_ORIGIN 4 75 | #define DOTCMD_ENTRYPOINT 5 76 | #define DOTCMD_STRUCT 6 77 | #define DOTCMD_ENDS 7 78 | #define DOTCMD_U32 8 79 | #define DOTCMD_U16 9 80 | #define DOTCMD_U8 10 81 | #define DOTCMD_ASSIGN 11 82 | #define DOTCMD_SETCALLREG 12 83 | #define DOTCMD_ENTER 13 84 | #define DOTCMD_LEAVE 14 85 | #define DOTCMD_USING 15 86 | #define DOTCMD_MACRO 16 87 | #define DOTCMD_MPARAM 17 88 | #define DOTCMD_ENDM 18 89 | #define DOTCMD_CODEWORD 19 90 | #define DOTCMD_MAX 19 91 | char *DotCmds[] = { ".main", ".end", ".proc", ".ret", 92 | ".origin", ".entrypoint", ".struct", ".ends", 93 | ".u32", ".u16", ".u8", ".assign", 94 | ".setcallreg", ".enter", ".leave", ".using", 95 | ".macro", ".mparam", ".endm", ".codeword" }; 96 | 97 | /*=================================================================== 98 | // 99 | // Public Functions 100 | // 101 | ====================================================================*/ 102 | 103 | /* 104 | // CheckDotCommand 105 | // 106 | // Check to see if supplied word is a dot command 107 | // 108 | // Returns 1 if the word is a command, else zero 109 | */ 110 | int CheckDotCommand(char *word) { 111 | int i; 112 | 113 | /* Commands are reserved */ 114 | for (i = 0; i <= DOTCMD_MAX; i++) { 115 | if (!stricmp(word, DotCmds[i])) 116 | return (1); 117 | } 118 | return (0); 119 | } 120 | 121 | /* 122 | // DotCommand 123 | // 124 | // Dot command processor 125 | // 126 | // This is the function where users add their assembler commands 127 | // 128 | // ps - Pointer to source file record 129 | // TermCnt - Number of terms (including the command) 130 | // pTerms - Pointer to the terms 131 | // Src - Buffer to write any resulting assembly line 132 | // MaxSrc - Size of assembly line buffer 133 | // 134 | // Returns: 135 | // >=0 : Success - Length of assemby line (0 to MaxSrc) 136 | // <0 : Illegal command 137 | */ 138 | int DotCommand(SOURCEFILE *ps, int TermCnt, char **pTerms, char *Src, 139 | int MaxSrc) { 140 | int i; 141 | 142 | for (i = 0; i <= DOTCMD_MAX; i++) { 143 | if (!stricmp(pTerms[0], DotCmds[i])) 144 | break; 145 | } 146 | if (i > DOTCMD_MAX) { 147 | Report(ps, REP_ERROR, "Unrecognized dot command"); 148 | return (-1); 149 | } 150 | 151 | if (i == DOTCMD_MAIN) { 152 | char c, cs; 153 | int quote = 0; 154 | int idx = 0, nameidx = 0; 155 | 156 | /* 157 | // .main command 158 | // 159 | // Just print a warning - its only here for compatibility 160 | */ 161 | if (TermCnt != 2) { 162 | Report(ps, REP_ERROR, "Expected 1 operand"); 163 | return (-1); 164 | } 165 | 166 | /* If the string is in quotes, skip the first charater */ 167 | if (pTerms[1][0] == '"') { 168 | quote++; 169 | idx++; 170 | } 171 | c = pTerms[1][idx++]; 172 | cs = ps->SourceName[nameidx++]; 173 | while (c && c != '"') { 174 | if (toupper(c) != toupper(cs)) { 175 | NO_MATCH: 176 | Report(ps, REP_WARN1, ".main name '%s' doesn't match '%s'", pTerms[1], 177 | ps->SourceName); 178 | return (0); 179 | } 180 | c = pTerms[1][idx++]; 181 | cs = ps->SourceName[nameidx++]; 182 | } 183 | if (cs && cs != '.') 184 | goto NO_MATCH; 185 | if (c == '"') { 186 | quote--; 187 | c = pTerms[1][idx++]; 188 | } 189 | if (c) { 190 | Report(ps, REP_ERROR, "Trailing characters on name"); 191 | return (-1); 192 | } 193 | if (quote) { 194 | Report(ps, REP_ERROR, "Unbalanced quotes on name"); 195 | return (-1); 196 | } 197 | return (0); 198 | } else if (i == DOTCMD_END) { 199 | /* 200 | // .end command 201 | // 202 | // Do nothing - its only here for compatibility 203 | */ 204 | if (TermCnt != 1) { 205 | Report(ps, REP_ERROR, "Expected no operands"); 206 | return (-1); 207 | } 208 | return (0); 209 | } else if (i == DOTCMD_PROC) { 210 | /* 211 | // .proc command 212 | // 213 | // Create a label from the proc name, with a leading '.' 214 | // (this is for compatibility) 215 | */ 216 | if (TermCnt != 2) { 217 | Report(ps, REP_ERROR, "Expected 1 operand"); 218 | return (-1); 219 | } 220 | sprintf(Src, ".%s:", pTerms[1]); 221 | return (strlen(Src)); 222 | } else if (i == DOTCMD_RET) { 223 | /* 224 | // .ret command 225 | // 226 | // Generate the line "jmp r30.w0" 227 | // This makes us compatible with "CALL", although inexplicably, 228 | // the CALL command is not a "dot" command. 229 | // 230 | */ 231 | if (TermCnt != 1) { 232 | Report(ps, REP_ERROR, "Expected no operands"); 233 | return (-1); 234 | } 235 | if (Options & OPTION_RETREGSET) { 236 | Report(ps, REP_ERROR, ".ret incompatible with .setcallreg, use ret"); 237 | return (-1); 238 | } 239 | if (Core > CORE_V1) { 240 | Report(ps, REP_ERROR, 241 | ".ret illegal with specified core version, use ret"); 242 | return (-1); 243 | } 244 | strcpy(Src, "jmp r30.w0"); 245 | return (strlen(Src)); 246 | } else if (i == DOTCMD_ORIGIN) { 247 | int val, tmp; 248 | char tstr[TOKEN_MAX_LEN]; 249 | 250 | /* 251 | // .origin command 252 | // 253 | // Alter the origin for writing code 254 | */ 255 | if (TermCnt != 2) { 256 | Report(ps, REP_ERROR, "Expected 1 operand"); 257 | return (-1); 258 | } 259 | 260 | strcpy(tstr, pTerms[1]); 261 | if (Expression(ps, tstr, (uint *)&val, &tmp) < 0) { 262 | Report(ps, REP_ERROR, "Error in processing .origin value"); 263 | return (-1); 264 | } 265 | if (Core == CORE_V0) { 266 | Report(ps, REP_ERROR, ".origin illegal with specified core version"); 267 | return (-1); 268 | } 269 | if (val < CodeOffset) { 270 | Report(ps, REP_ERROR, ".origin value is less than current offset"); 271 | return (-1); 272 | } 273 | if (CodeOffset >= 0) 274 | Report(ps, REP_WARN1, "Resetting .origin value after use"); 275 | if (EntryPoint < 0) 276 | EntryPoint = val; 277 | 278 | CodeOffset = val; 279 | return (0); 280 | } else if (i == DOTCMD_ENTRYPOINT) { 281 | int val, tmp; 282 | char tstr[TOKEN_MAX_LEN]; 283 | 284 | /* 285 | // .entrypoint command 286 | // 287 | // Alter the origin for writing code 288 | */ 289 | if (TermCnt != 2) { 290 | Report(ps, REP_ERROR, "Expected 1 operand"); 291 | return (-1); 292 | } 293 | 294 | strcpy(tstr, pTerms[1]); 295 | if (Expression(ps, tstr, (uint *)&val, &tmp) < 0) { 296 | Report(ps, REP_ERROR, "Error in processing .entrypoint value"); 297 | return (-1); 298 | } 299 | 300 | if (Core == CORE_V0) { 301 | Report(ps, REP_ERROR, ".entrypoint illegal with specified core version"); 302 | return (-1); 303 | } 304 | 305 | if (HaveEntry) { 306 | Report(ps, REP_ERROR, "Multiple .entrypoint declarations"); 307 | return (-1); 308 | } 309 | 310 | EntryPoint = val; 311 | HaveEntry = 1; 312 | return (0); 313 | } else if (i == DOTCMD_STRUCT) { 314 | if (TermCnt != 2) { 315 | Report(ps, REP_ERROR, "Expected 1 operand"); 316 | return (-1); 317 | } 318 | return (StructNew(ps, pTerms[1])); 319 | 320 | } else if (i == DOTCMD_ENDS) { 321 | if (TermCnt != 1) { 322 | Report(ps, REP_ERROR, "Expected no operands"); 323 | return (-1); 324 | } 325 | return (StructEnd(ps)); 326 | } else if (i == DOTCMD_U32) { 327 | if (TermCnt != 2) { 328 | Report(ps, REP_ERROR, "Expected 1 operand"); 329 | return (-1); 330 | } 331 | return (StructAddElement(ps, pTerms[1], 4)); 332 | } else if (i == DOTCMD_U16) { 333 | if (TermCnt != 2) { 334 | Report(ps, REP_ERROR, "Expected 1 operand"); 335 | return (-1); 336 | } 337 | return (StructAddElement(ps, pTerms[1], 2)); 338 | } else if (i == DOTCMD_U8) { 339 | if (TermCnt != 2) { 340 | Report(ps, REP_ERROR, "Expected 1 operand"); 341 | return (-1); 342 | } 343 | return (StructAddElement(ps, pTerms[1], 1)); 344 | } else if (i == DOTCMD_ASSIGN) { 345 | if (TermCnt != 5) { 346 | Report(ps, REP_ERROR, "Expected 4 operands"); 347 | return (-1); 348 | } 349 | return (StructAssign(ps, pTerms[1], pTerms[2], pTerms[3], pTerms[4])); 350 | } else if (i == DOTCMD_SETCALLREG) { 351 | PRU_ARG r; 352 | 353 | if (TermCnt != 2) { 354 | Report(ps, REP_ERROR, "Expected 1 operand"); 355 | return (-1); 356 | } 357 | if (Core == CORE_V0) { 358 | Report(ps, REP_ERROR, ".setcallreg illegal with specified core version"); 359 | return (-1); 360 | } 361 | if (Pass == 1 && (Options & OPTION_RETREGSET)) { 362 | Report(ps, REP_ERROR, ".setcallreg redefinition"); 363 | return (-1); 364 | } 365 | if (CodeOffset >= 0) { 366 | Report(ps, REP_ERROR, "Can not use .setcallreg after code generation"); 367 | return (-1); 368 | } 369 | if (!GetRegister(ps, 1, pTerms[1], &r, 0, 0)) 370 | return -1; 371 | 372 | switch (r.Field) { 373 | case FIELDTYPE_15_0: 374 | case FIELDTYPE_23_8: 375 | case FIELDTYPE_31_16: 376 | if (r.Value < 31) { 377 | RetRegValue = r.Value; 378 | RetRegField = r.Field; 379 | Options |= OPTION_RETREGSET; 380 | return 0; 381 | } 382 | } 383 | 384 | Report(ps, REP_ERROR, "Register field must be r0 to r30 and 16 bits wide"); 385 | return (-1); 386 | } else if (i == DOTCMD_ENTER) { 387 | if (TermCnt != 2) { 388 | Report(ps, REP_ERROR, "Expected 1 operand"); 389 | return (-1); 390 | } 391 | return (ScopeEnter(ps, pTerms[1])); 392 | } else if (i == DOTCMD_LEAVE) { 393 | if (TermCnt != 2) { 394 | Report(ps, REP_ERROR, "Expected 1 operand"); 395 | return (-1); 396 | } 397 | return (ScopeLeave(ps, pTerms[1])); 398 | } else if (i == DOTCMD_USING) { 399 | if (TermCnt != 2) { 400 | Report(ps, REP_ERROR, "Expected 1 operand"); 401 | return (-1); 402 | } 403 | return (ScopeUsing(ps, pTerms[1])); 404 | } else if (i == DOTCMD_MACRO) { 405 | if (TermCnt != 2) { 406 | Report(ps, REP_ERROR, "Expected 1 operand"); 407 | return (-1); 408 | } 409 | return (MacroEnter(ps, pTerms[1])); 410 | } else if (i == DOTCMD_MPARAM || i == DOTCMD_ENDM) { 411 | Report(ps, REP_ERROR, "%s can not be used outside of macro", pTerms[0]); 412 | return (-1); 413 | } else if (i == DOTCMD_CODEWORD) { 414 | uint opcode; 415 | int tmp; 416 | char tstr[TOKEN_MAX_LEN]; 417 | 418 | /* 419 | // .codeword command 420 | */ 421 | if (TermCnt != 2) { 422 | Report(ps, REP_ERROR, "Expected 1 operand"); 423 | return (-1); 424 | } 425 | 426 | strcpy(tstr, pTerms[1]); 427 | if (Expression(ps, tstr, &opcode, &tmp) < 0) { 428 | Report(ps, REP_ERROR, "Error in processing .codeword value"); 429 | return (-1); 430 | } 431 | 432 | GenOp(ps, TermCnt, pTerms, opcode); 433 | return (0); 434 | } 435 | 436 | Report(ps, REP_ERROR, "Dot command - Internal Error"); 437 | return (-1); 438 | } 439 | 440 | /* 441 | // DotInitialize 442 | // 443 | // Open the dot-command environment 444 | // 445 | // void 446 | */ 447 | void DotInitialize(int pass) { StructInit(); } 448 | 449 | /* 450 | // DotCleanup 451 | // 452 | // Clean up the dot-command environment 453 | // 454 | // void 455 | */ 456 | void DotCleanup(int pass) { 457 | StructCleanup(); 458 | MacroCleanup(); 459 | } 460 | -------------------------------------------------------------------------------- /am335x/pasm/pasmexp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pasmexp.c 3 | * 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the 17 | * distribution. 18 | * 19 | * Neither the name of Texas Instruments Incorporated nor the names of 20 | * its contributors may be used to endorse or promote products derived 21 | * from this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | 37 | /*=========================================================================== 38 | * Copyright (c) Texas Instruments Inc 2010-12 39 | * 40 | * Use of this software is controlled by the terms and conditions found in the 41 | * license agreement under which this software has been supplied or provided. 42 | * ============================================================================ 43 | */ 44 | 45 | /*=========================================================================== 46 | // PASM - PRU Assembler 47 | //--------------------------------------------------------------------------- 48 | // 49 | // File : pasmexp.c 50 | // 51 | // Description: 52 | // Expression analyzer. This module is a "drop in", and thus does't 53 | // have much knowledge of the rest of the assembler. 54 | // - Handles expression processing 55 | // 56 | // Note that the expression analyzer will only report errors on pass 2 57 | // 58 | //--------------------------------------------------------------------------- 59 | // Revision: 60 | // 21-Jun-13: 0.84 - Open source version 61 | ============================================================================*/ 62 | 63 | #include 64 | #include 65 | #include 66 | #if !defined(__APPLE__) 67 | #include 68 | #else 69 | #include 70 | #endif 71 | #include 72 | #include "pasm.h" 73 | 74 | #define MAXTERM 32 75 | 76 | #define EOP_MULTIPLY 1 77 | #define EOP_DIVIDE 2 78 | #define EOP_MOD 3 79 | #define EOP_ADD 4 80 | #define EOP_SUBTRACT 5 81 | #define EOP_LEFTSHIFT 6 82 | #define EOP_RIGHTSHIFT 7 83 | #define EOP_AND 8 84 | #define EOP_XOR 9 85 | #define EOP_OR 10 86 | 87 | uint prec[] = { 999, 1, /* EOP_MULTIPLY */ 88 | 1, /* EOP_DIVIDE */ 89 | 1, /* EOP_MOD */ 90 | 2, /* EOP_ADD */ 91 | 2, /* EOP_SUBTRACT */ 92 | 3, /* EOP_LEFTSHIFT */ 93 | 3, /* EOP_RIGHTSHIFT */ 94 | 4, /* EOP_AND */ 95 | 5, /* EOP_XOR */ 96 | 6 }; /* EOP_OR */ 97 | 98 | int EXP_getValue(SOURCEFILE *ps, char *s, int *pIdx, uint *pValue); 99 | int EXP_getOperation(SOURCEFILE *ps, char *s, int *pIdx, uint *pValue); 100 | static int GetRegisterOffset(char *src, uint *pValue); 101 | 102 | /* 103 | // Expression - Math Expression Parser 104 | // 105 | // Returns 0 on success, <0 on error 106 | */ 107 | int Expression(SOURCEFILE *ps, char *s, uint *pResult, int *pIndex) { 108 | uint values[MAXTERM]; 109 | uint ops[MAXTERM]; 110 | int maxprec; 111 | int i; 112 | int validx, opidx, stridx; 113 | 114 | validx = 0; 115 | opidx = 0; 116 | stridx = 0; 117 | 118 | while (validx < MAXTERM) { 119 | i = EXP_getValue(ps, s, &stridx, &values[validx]); 120 | if (!i) 121 | break; 122 | if (i < 0) { 123 | if (pIndex) 124 | *pIndex = stridx; 125 | return (-1); 126 | } 127 | validx++; 128 | 129 | i = EXP_getOperation(ps, s, &stridx, &ops[opidx]); 130 | if (!i) 131 | break; 132 | if (i < 0) { 133 | if (pIndex) 134 | *pIndex = stridx; 135 | return (-1); 136 | } 137 | opidx++; 138 | } 139 | 140 | if (i) { 141 | Report(ps, REP_ERROR, "Max term count exceeded"); 142 | return (-1); 143 | } 144 | 145 | if (pIndex) 146 | *pIndex = stridx; 147 | 148 | /* If values and ops unbalanced, quit now */ 149 | if (opidx >= validx || !validx) 150 | return (-1); 151 | 152 | while (opidx) { 153 | /* Find the highest prec op */ 154 | maxprec = 0; 155 | for (i = 1; i < opidx; i++) 156 | if (prec[ops[i]] < prec[ops[maxprec]]) 157 | maxprec = i; 158 | 159 | switch (ops[maxprec]) { 160 | case EOP_MULTIPLY: 161 | values[maxprec] = values[maxprec] * values[maxprec + 1]; 162 | break; 163 | case EOP_DIVIDE: 164 | if (!values[maxprec + 1]) { 165 | if (Pass == 2) { 166 | Report(ps, REP_ERROR, "Divide by zero"); 167 | return (-1); 168 | } else 169 | values[maxprec] = 0; 170 | } else 171 | values[maxprec] = values[maxprec] / values[maxprec + 1]; 172 | break; 173 | case EOP_MOD: 174 | if (!values[maxprec + 1]) { 175 | if (Pass == 2) { 176 | Report(ps, REP_ERROR, "Mod by zero"); 177 | return (-1); 178 | } else 179 | values[maxprec] = 0; 180 | } else 181 | values[maxprec] = values[maxprec] % values[maxprec + 1]; 182 | break; 183 | case EOP_ADD: 184 | values[maxprec] = values[maxprec] + values[maxprec + 1]; 185 | break; 186 | case EOP_SUBTRACT: 187 | values[maxprec] = values[maxprec] - values[maxprec + 1]; 188 | break; 189 | case EOP_LEFTSHIFT: 190 | values[maxprec] = values[maxprec] << values[maxprec + 1]; 191 | break; 192 | case EOP_RIGHTSHIFT: 193 | values[maxprec] = values[maxprec] >> values[maxprec + 1]; 194 | break; 195 | case EOP_AND: 196 | values[maxprec] = values[maxprec] & values[maxprec + 1]; 197 | break; 198 | case EOP_XOR: 199 | values[maxprec] = values[maxprec] ^ values[maxprec + 1]; 200 | break; 201 | case EOP_OR: 202 | values[maxprec] = values[maxprec] | values[maxprec + 1]; 203 | break; 204 | } 205 | 206 | // Remove this op and 2nd value term from the list 207 | i = MAXTERM - 2 - maxprec; 208 | if (i > 0) { 209 | memcpy(&values[maxprec + 1], &values[maxprec + 2], i * sizeof(uint)); 210 | memcpy(&ops[maxprec], &ops[maxprec + 1], i * sizeof(uint)); 211 | } 212 | 213 | opidx--; 214 | validx--; 215 | } 216 | 217 | if (validx != 1) { 218 | Report(ps, REP_ERROR, "Exp internal error"); 219 | return (-1); 220 | } 221 | 222 | *pResult = values[0]; 223 | return (0); 224 | } 225 | 226 | /* 227 | // EXP_getValue - Get a value from the supplied string 228 | // 229 | // Returns 0 no value, 1 on success, <0 on error 230 | */ 231 | int EXP_getValue(SOURCEFILE *ps, char *s, int *pIdx, uint *pValue) { 232 | int base = 10, index, i, j, k; 233 | int rc = 1; 234 | uint tval = 0; 235 | char c; 236 | 237 | index = *pIdx; 238 | 239 | c = s[index]; 240 | while (c == ' ' || c == 9) { 241 | index++; 242 | c = s[index]; 243 | } 244 | 245 | if (!c) 246 | return (0); 247 | 248 | /* Look for a label */ 249 | if (LabelChar(c, 1) || c == '.' || c == '&') { 250 | LABEL *pl; 251 | char lblstr[LABEL_NAME_LEN]; 252 | int lblidx = 0; 253 | 254 | for (;;) { 255 | lblstr[lblidx++] = c; 256 | index++; 257 | c = s[index]; 258 | if (!LabelChar(c, 0) && c != '.') 259 | break; 260 | } 261 | lblstr[lblidx] = 0; 262 | *pIdx = index; 263 | 264 | if (CheckTokenType(lblstr) & TOKENTYPE_FLG_REG_ADDR) { 265 | if (GetRegisterOffset(lblstr + 1, &tval)) { 266 | *pValue = tval; 267 | return (1); 268 | } 269 | } 270 | pl = LabelFind(lblstr); 271 | if (!pl && Pass == 1) 272 | *pValue = 0; 273 | else if (!pl) { 274 | Report(ps, REP_ERROR, "Not found: '%s'", lblstr); 275 | return (0); 276 | } else 277 | *pValue = pl->Offset; 278 | return (1); 279 | } 280 | 281 | if (c == '-') { 282 | index++; 283 | i = EXP_getValue(ps, s, &index, &tval); 284 | if (i < 0) 285 | rc = i; 286 | else 287 | tval = (uint)(-(int)tval); 288 | goto EGV_EXIT; 289 | } 290 | if (c == '~') { 291 | index++; 292 | i = EXP_getValue(ps, s, &index, &tval); 293 | if (i < 0) 294 | rc = i; 295 | else 296 | tval = ~tval; 297 | goto EGV_EXIT; 298 | } 299 | if (c == '(') { 300 | /* Scan to the far ')' */ 301 | index++; 302 | j = index; 303 | i = 1; 304 | for (;;) { 305 | c = *(s + j); 306 | if (!c) { 307 | rc = -1; 308 | goto EGV_EXIT; 309 | } 310 | if (c == '(') 311 | i++; 312 | if (c == ')') { 313 | i--; 314 | if (!i) { 315 | /* Terminate the string and eval the () */ 316 | *(s + j) = 0; 317 | i = Expression(0, s + index, &tval, &k); 318 | if (i < 0) { 319 | index += k; 320 | rc = i; 321 | } else 322 | index = j + 1; 323 | goto EGV_EXIT; 324 | } 325 | } 326 | j++; 327 | } 328 | } 329 | 330 | /* This character must be a number */ 331 | if (c < '0' || c > '9') { 332 | rc = -1; 333 | goto EGV_EXIT; 334 | } 335 | index++; 336 | tval = c - '0'; 337 | if (tval == 0) { 338 | c = s[index]; 339 | if (c == 'x') { 340 | base = 16; 341 | index++; 342 | } else if (c == 'b') { 343 | base = 2; 344 | index++; 345 | } else 346 | base = 8; 347 | } 348 | 349 | for (;;) { 350 | c = s[index]; 351 | if (c >= '0' && c <= '9') 352 | i = c - '0'; 353 | else if (c >= 'a' && c <= 'f') 354 | i = c - 'a' + 10; 355 | else if (c >= 'A' && c <= 'F') 356 | i = c - 'A' + 10; 357 | else 358 | break; 359 | 360 | if (i >= base) { 361 | rc = -1; 362 | goto EGV_EXIT; 363 | } 364 | tval *= base; 365 | tval += i; 366 | index++; 367 | } 368 | 369 | EGV_EXIT: 370 | *pValue = tval; 371 | *pIdx = index; 372 | return (rc); 373 | } 374 | 375 | /* 376 | // EXP_getOperation - Get an operation from the supplied string 377 | // 378 | // Returns 0 no value, 1 on success, <0 on error 379 | */ 380 | int EXP_getOperation(SOURCEFILE *ps, char *s, int *pIdx, uint *pValue) { 381 | int index; 382 | char c; 383 | int rc = 1; 384 | 385 | index = *pIdx; 386 | 387 | c = s[index]; 388 | while (c == ' ' || c == 9) { 389 | index++; 390 | c = s[index]; 391 | } 392 | 393 | if (!c) 394 | return (0); 395 | else if (c == '*') 396 | *pValue = EOP_MULTIPLY; 397 | else if (c == '/') 398 | *pValue = EOP_DIVIDE; 399 | else if (c == '%') 400 | *pValue = EOP_MOD; 401 | else if (c == '+') 402 | *pValue = EOP_ADD; 403 | else if (c == '-') 404 | *pValue = EOP_SUBTRACT; 405 | else if (c == '<') { 406 | index++; 407 | c = s[index]; 408 | if (c != '<') 409 | rc = -1; 410 | else 411 | *pValue = EOP_LEFTSHIFT; 412 | } else if (c == '>') { 413 | index++; 414 | c = s[index]; 415 | if (c != '>') 416 | rc = -1; 417 | else 418 | *pValue = EOP_RIGHTSHIFT; 419 | } else if (c == '&') 420 | *pValue = EOP_AND; 421 | else if (c == '^') 422 | *pValue = EOP_XOR; 423 | else if (c == '|') 424 | *pValue = EOP_OR; 425 | else 426 | rc = -1; 427 | 428 | if (rc == 1) 429 | index++; 430 | 431 | *pIdx = index; 432 | return (rc); 433 | } 434 | 435 | /* 436 | // GetRegisterOffset 437 | // 438 | // Get Register Offset 439 | // 440 | // Returns: 441 | // 1 : Success 442 | // 0 : Error 443 | */ 444 | static int GetRegisterOffset(char *src, uint *pValue) { 445 | uint idx; 446 | char c, field; 447 | int val, reg, width, offset; 448 | 449 | if (Core == CORE_V0) 450 | return (0); 451 | 452 | /* 453 | // The following register syntaxes are valid: 454 | // Raa aa=(0-31) 455 | // Raa.Wb aa=(0-31) b=(0-2) 456 | // Raa.Bc aa=(0-31) c=(0-3) 457 | // Raa.Tdd aa=(0-31) dd=(0-31) 458 | // Raa.Wb.Be aa=(0-31) b=(0-2) e=(0-1) 459 | */ 460 | 461 | idx = 0; 462 | c = src[idx++]; 463 | /* Get initial 'R##' */ 464 | if (toupper(c) != 'R') 465 | return (0); 466 | c = src[idx++]; 467 | if (!isdigit(c)) 468 | return (0); 469 | val = 0; 470 | while (isdigit(c)) { 471 | val *= 10; 472 | val += c - '0'; 473 | c = src[idx++]; 474 | } 475 | if (val > 31) 476 | return (0); 477 | 478 | reg = val; 479 | width = 32; 480 | offset = 0; 481 | 482 | for (;;) { 483 | /* This char must be '.', or terminator */ 484 | 485 | /* If terminated, we're done */ 486 | if (!c) 487 | break; 488 | if (c != '.') 489 | return (0); 490 | 491 | c = src[idx++]; 492 | 493 | /* This char must be 'W', or 'B' */ 494 | c = toupper(c); 495 | if (c != 'W' && c != 'B') 496 | return (0); 497 | field = c; 498 | c = src[idx++]; 499 | if (!isdigit(c)) 500 | return (0); 501 | val = 0; 502 | while (isdigit(c)) { 503 | val *= 10; 504 | val += c - '0'; 505 | c = src[idx++]; 506 | } 507 | if (field == 'W') { 508 | if (((val * 8) + 16) > width) 509 | return (0); 510 | width = 16; 511 | offset += val; 512 | } 513 | if (field == 'B') { 514 | if (((val * 8) + 8) > width) 515 | return (0); 516 | width = 8; 517 | offset += val; 518 | } 519 | } 520 | 521 | if (!(Options & OPTION_BIGENDIAN)) 522 | *pValue = reg * 4 + offset; 523 | else { 524 | width /= 8; 525 | offset = 4 - offset - width; 526 | *pValue = reg * 4 + offset; 527 | } 528 | 529 | return (1); 530 | } 531 | -------------------------------------------------------------------------------- /am335x/pasm/pasmmacro.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pasmmacro.c 3 | * 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the 17 | * distribution. 18 | * 19 | * Neither the name of Texas Instruments Incorporated nor the names of 20 | * its contributors may be used to endorse or promote products derived 21 | * from this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | 37 | /*=========================================================================== 38 | * Copyright (c) Texas Instruments Inc 2010-12 39 | * 40 | * Use of this software is controlled by the terms and conditions found in the 41 | * license agreement under which this software has been supplied or provided. 42 | * ============================================================================ 43 | */ 44 | 45 | /*=========================================================================== 46 | // PASM - PRU Assembler 47 | //--------------------------------------------------------------------------- 48 | // 49 | // File : pasmmacro.c 50 | // 51 | // Description: 52 | // Processes the macro commands 53 | // 54 | //--------------------------------------------------------------------------- 55 | // Revision: 56 | // 21-Jun-13: 0.84 - Open source version 57 | ============================================================================*/ 58 | 59 | #include 60 | #include 61 | #include 62 | #if !defined(__APPLE__) 63 | #include 64 | #else 65 | #include 66 | #endif 67 | #include 68 | #include "pasm.h" 69 | 70 | /* Local Macro Definitions */ 71 | 72 | #define MACRO_NAME_LEN TOKEN_MAX_LEN 73 | #define MACRO_MAX_ARGS 8 74 | #define MACRO_MAX_LINES 128 75 | #define MACRO_LINE_LENGTH 256 76 | #define MACRO_MAX_LABELS 32 77 | #define MAX_SOURCE_LINE 256 78 | 79 | /* Macro Struct Record */ 80 | typedef struct _MACRO { 81 | struct _MACRO *pPrev; /* Previous in MACRO list */ 82 | struct _MACRO *pNext; /* Next in MACRO list */ 83 | char Name[MACRO_NAME_LEN]; 84 | int InUse; /* Macro is in use */ 85 | int Id; /* Macro ID */ 86 | int Arguments; /* Number of arguments */ 87 | int Required; /* Number of required arguments */ 88 | int Labels; /* Number of labels */ 89 | int Expands; /* Number of label expansions */ 90 | int CodeLines; /* Number of code lines */ 91 | char ArgName[MACRO_MAX_ARGS][TOKEN_MAX_LEN]; 92 | char ArgDefault[MACRO_MAX_ARGS][TOKEN_MAX_LEN]; 93 | char LableName[MACRO_MAX_LABELS][TOKEN_MAX_LEN]; 94 | char Code[MACRO_MAX_LINES][MACRO_LINE_LENGTH]; 95 | } MACRO; 96 | 97 | /* Local Support Funtions */ 98 | static int _strncat(char *dst, int len, char *src); 99 | static MACRO *MacroFind(char *Name); 100 | static MACRO *MacroCreate(SOURCEFILE *ps, char *Name); 101 | int MacroAddArg(SOURCEFILE *ps, MACRO *pm, char *ArgText); 102 | static void MacroDestroy(MACRO *pm); 103 | 104 | /* Local macro list */ 105 | int MacroId = 0; 106 | MACRO *pMacroList = 0; /* List of declared structs */ 107 | MACRO *pMacroCurrent = 0; 108 | 109 | /*=================================================================== 110 | // 111 | // Public Functions 112 | // 113 | ====================================================================*/ 114 | 115 | /* 116 | // MacroEnter 117 | // Returns: 118 | // 0 - Success 119 | // -1 - Error 120 | */ 121 | int MacroEnter(SOURCEFILE *ps, char *Name) { 122 | SRCLINE sl; 123 | MACRO *pm; 124 | char src[MAX_SOURCE_LINE]; 125 | int i; 126 | 127 | if (Core == CORE_V0) { 128 | Report(ps, REP_ERROR, ".macro illegal with specified core version"); 129 | return (-1); 130 | } 131 | 132 | /* Create the macro */ 133 | pm = MacroCreate(ps, Name); 134 | if (!pm) 135 | return (-1); 136 | 137 | /* Scan source lines until we see .endm */ 138 | for (;;) { 139 | /* Abort on a total disaster */ 140 | if (FatalError || Errors >= 25) 141 | return (-1); 142 | 143 | /* Get a line of source code */ 144 | i = GetSourceLine(ps, src, MAX_SOURCE_LINE); 145 | if (!i) { 146 | Report(ps, REP_ERROR, "Missing .endm on macro"); 147 | return (-1); 148 | } 149 | if (i < 0) 150 | continue; 151 | 152 | if (!ParseSourceLine(ps, i, src, &sl)) 153 | continue; 154 | 155 | /* Check for a label */ 156 | if (sl.Flags & SRC_FLG_LABEL) { 157 | if (pm->Labels == MACRO_MAX_LABELS) 158 | Report(ps, REP_ERROR, "Macro contains too many labels"); 159 | else { 160 | strcpy(pm->LableName[pm->Labels], sl.Label); 161 | pm->Labels++; 162 | } 163 | } 164 | 165 | /* Check for a macro related dot command */ 166 | if (sl.Terms && (sl.Flags & SRC_FLG_DOTCMD1)) { 167 | if (!stricmp(sl.Term[0], ".mparam")) { 168 | if (sl.Terms == 1) { 169 | Report(ps, REP_ERROR, "Expected at least 1 parameter on .mparam"); 170 | continue; 171 | } 172 | for (i = 1; i < (int)sl.Terms; i++) 173 | MacroAddArg(ps, pm, sl.Term[i]); 174 | continue; 175 | } else if (!stricmp(sl.Term[0], ".macro")) { 176 | Report(ps, REP_ERROR, "Macro definitions may not be nested"); 177 | continue; 178 | } else if (!stricmp(sl.Term[0], ".endm")) { 179 | pm->InUse = 0; 180 | return (0); 181 | } 182 | } 183 | /* Else store the line as part of the macro */ 184 | else { 185 | if (pm->CodeLines == MACRO_MAX_LINES) { 186 | Report(ps, REP_ERROR, "Macro line count exceeded"); 187 | continue; 188 | } 189 | strcpy(pm->Code[pm->CodeLines], src); 190 | pm->CodeLines++; 191 | } 192 | } 193 | } 194 | 195 | /* 196 | // ProcessMacro 197 | // 198 | // ps - Pointer to source file record 199 | // TermCnt - Number of terms (including the command) 200 | // pTerms - Pointer to the terms 201 | // 202 | // Returns: 203 | // 1 : Success 204 | // 0 : Error 205 | */ 206 | int ProcessMacro(SOURCEFILE *ps, int TermCnt, char **pTerms) { 207 | MACRO *pm; 208 | int cidx, sidx, nidx, i; 209 | char src[MAX_SOURCE_LINE]; 210 | char namebuf[MACRO_NAME_LEN]; 211 | char c; 212 | 213 | pm = MacroFind(pTerms[0]); 214 | if (!pm) 215 | return (0); 216 | 217 | if (pm->InUse) { 218 | Report(ps, REP_ERROR, "Illegal recursive use of macro '%s'", pTerms[0]); 219 | return (0); 220 | } 221 | 222 | if (pm->Required >= TermCnt) { 223 | Report(ps, REP_ERROR, "Expected at least %d arguments on '%s'", 224 | pm->Required, pTerms[0]); 225 | return (0); 226 | } 227 | 228 | if (pm->Arguments < (TermCnt - 1)) { 229 | Report(ps, REP_ERROR, "Expected no more than %d arguments on '%s'", 230 | pm->Arguments, pTerms[0]); 231 | return (0); 232 | } 233 | 234 | /* Bump expansion count */ 235 | pm->Expands++; 236 | pm->InUse = 1; 237 | 238 | for (cidx = 0; cidx < pm->CodeLines; cidx++) { 239 | /* Build the assembly statement */ 240 | sidx = 0; 241 | nidx = 0; 242 | src[0] = 0; 243 | for (;;) { 244 | c = pm->Code[cidx][sidx++]; 245 | /* Check for start of name */ 246 | if (!nidx) { 247 | if (LabelChar(c, 1)) { 248 | namebuf[nidx++] = c; 249 | continue; 250 | } 251 | } 252 | /* Else continue a previously started name */ 253 | else { 254 | if (LabelChar(c, 0)) { 255 | /* Check for name too long */ 256 | if (nidx == (MACRO_NAME_LEN - 1)) { 257 | Report(ps, REP_ERROR, "Term too long in macro assembly text"); 258 | pm->InUse = 0; 259 | return (0); 260 | } 261 | namebuf[nidx++] = c; 262 | continue; 263 | } 264 | 265 | /* This name is done */ 266 | namebuf[nidx] = 0; 267 | 268 | /* Look for an argument match */ 269 | for (i = 0; i < pm->Arguments; i++) { 270 | if (!strcmp(namebuf, pm->ArgName[i])) { 271 | /* Match! */ 272 | if ((i + 1) >= TermCnt) 273 | _strncat(src, MAX_SOURCE_LINE, pm->ArgDefault[i]); 274 | else 275 | _strncat(src, MAX_SOURCE_LINE, pTerms[i + 1]); 276 | goto SUBTEXTDONE; 277 | } 278 | } 279 | 280 | /* Look for a label match */ 281 | for (i = 0; i < pm->Labels; i++) { 282 | if (!strcmp(namebuf, pm->LableName[i])) { 283 | char labeltext[TOKEN_MAX_LEN + 32]; 284 | 285 | /* Match! */ 286 | sprintf(labeltext, "_%s_%d_%d_", pm->LableName[i], pm->Id, 287 | pm->Expands); 288 | _strncat(src, MAX_SOURCE_LINE, labeltext); 289 | goto SUBTEXTDONE; 290 | } 291 | } 292 | 293 | /* Sub in the original text */ 294 | _strncat(src, MAX_SOURCE_LINE, namebuf); 295 | SUBTEXTDONE: 296 | nidx = 0; 297 | } 298 | /* Check for text too long */ 299 | i = strlen(src); 300 | if (i == (MAX_SOURCE_LINE - 1)) { 301 | Report(ps, REP_ERROR, "Macro expansion too long"); 302 | pm->InUse = 0; 303 | return (0); 304 | } 305 | src[i++] = c; 306 | src[i] = 0; 307 | if (!c) 308 | break; 309 | } 310 | 311 | i = strlen(src); 312 | if (i) { 313 | if (!ProcessSourceLine(ps, i, src)) { 314 | Report(ps, REP_ERROR, "(While expanding code line %d of macro '%s')", 315 | (cidx + 1), pm->Name); 316 | pm->InUse = 0; 317 | return (0); 318 | } 319 | } 320 | } 321 | pm->InUse = 0; 322 | return (1); 323 | } 324 | 325 | /* 326 | // MacroCleanup 327 | // 328 | // Returns: void 329 | */ 330 | void MacroCleanup() { 331 | while (pMacroList) 332 | MacroDestroy(pMacroList); 333 | MacroId = 0; 334 | } 335 | 336 | /* 337 | // CheckMacro 338 | // 339 | // Searches for an macro by name. 340 | // 341 | // Returns 1 on success, 0 on error 342 | */ 343 | int CheckMacro(char *name) { 344 | if (MacroFind(name)) 345 | return (1); 346 | return (0); 347 | } 348 | 349 | /*=================================================================== 350 | // 351 | // Private Functions 352 | // 353 | ====================================================================*/ 354 | 355 | static int _strncat(char *dst, int len, char *src) { 356 | int sidx, didx; 357 | 358 | didx = 0; 359 | while (didx < len && dst[didx]) 360 | didx++; 361 | if (didx > (len - 1)) 362 | return (-1); 363 | sidx = 0; 364 | while (src[sidx]) { 365 | if (didx > (len - 1)) { 366 | dst[didx] = 0; 367 | return (-1); 368 | } 369 | dst[didx++] = src[sidx++]; 370 | } 371 | dst[didx] = 0; 372 | return (didx); 373 | } 374 | 375 | /* 376 | // MacroFind 377 | // 378 | // Searches for a macro record by name. If found, returns the record pointer. 379 | // 380 | // Returns MACRO * on success, 0 on error 381 | */ 382 | static MACRO *MacroFind(char *Name) { 383 | MACRO *pm; 384 | 385 | pm = pMacroList; 386 | while (pm) { 387 | if (!strcmp(Name, pm->Name)) 388 | break; 389 | pm = pm->pNext; 390 | } 391 | return (pm); 392 | } 393 | 394 | /* 395 | // MacroCreate 396 | // 397 | // Create a new macro record 398 | // 399 | // Returns MACRO * on success, 0 on error 400 | */ 401 | static MACRO *MacroCreate(SOURCEFILE *ps, char *Name) { 402 | MACRO *pm; 403 | 404 | /* Make sure this name is OK to use */ 405 | if (!CheckName(ps, Name)) 406 | return (0); 407 | 408 | /* Make sure its not too long */ 409 | if (strlen(Name) >= MACRO_NAME_LEN) { 410 | Report(ps, REP_ERROR, "Macro name too long"); 411 | return (0); 412 | } 413 | 414 | /* Allocate a new record */ 415 | pm = malloc(sizeof(MACRO)); 416 | if (!pm) { 417 | Report(ps, REP_ERROR, "Memory allocation failed"); 418 | return (0); 419 | } 420 | 421 | strcpy(pm->Name, Name); 422 | pm->InUse = 1; 423 | pm->Id = MacroId++; 424 | pm->Arguments = 0; 425 | pm->Required = 0; 426 | pm->CodeLines = 0; 427 | pm->Labels = 0; 428 | pm->Expands = 0; 429 | 430 | /* Put this equate in the master list */ 431 | pm->pPrev = 0; 432 | pm->pNext = pMacroList; 433 | pMacroList = pm; 434 | 435 | if (Pass == 1 && (Options & OPTION_DEBUG)) 436 | printf("%s(%5d) : DOTCMD : Macro '%s' declared\n", ps->SourceName, 437 | ps->CurrentLine, pm->Name); 438 | 439 | return (pm); 440 | } 441 | 442 | /* 443 | // MacroAddArg 444 | // 445 | // Add an argument to a macro record 446 | // 447 | // Returns 0 on success, -1 on error 448 | */ 449 | int MacroAddArg(SOURCEFILE *ps, MACRO *pm, char *ArgText) { 450 | int i, sidx; 451 | 452 | if (Pass == 1 && (Options & OPTION_DEBUG)) 453 | printf("%s(%5d) : DOTCMD : Macro Parameter '%s' declared\n", ps->SourceName, 454 | ps->CurrentLine, ArgText); 455 | 456 | if (pm->Arguments == MACRO_MAX_ARGS) { 457 | Report(ps, REP_ERROR, "Too many macro arguments"); 458 | return (-1); 459 | } 460 | 461 | /* Scan in the argument */ 462 | sidx = 0; 463 | while (ArgText[sidx] == ' ' || ArgText[sidx] == 9) 464 | sidx++; 465 | i = 0; 466 | while (ArgText[sidx] != ' ' && ArgText[sidx] != 9 && ArgText[sidx] != '=' && 467 | ArgText[sidx] != 0) { 468 | if (i == TOKEN_MAX_LEN) { 469 | Report(ps, REP_ERROR, "Macro argument name too long"); 470 | return (-1); 471 | } 472 | if ((i == 0 && !LabelChar(ArgText[sidx], 1)) || 473 | (i != 0 && !LabelChar(ArgText[sidx], 0))) { 474 | Report(ps, REP_ERROR, "Illegal character in macro argument name"); 475 | return (-1); 476 | } 477 | pm->ArgName[pm->Arguments][i++] = ArgText[sidx++]; 478 | } 479 | pm->ArgName[pm->Arguments][i] = 0; 480 | if (!i) 481 | goto MARG_SYNTAX; 482 | 483 | /* Verify no duplicate naming */ 484 | for (i = 0; i < pm->Arguments; i++) { 485 | if (!strcmp(pm->ArgName[i], pm->ArgName[pm->Arguments])) { 486 | Report(ps, REP_ERROR, "Duplicate macro argument name '%s'", 487 | pm->ArgName[i]); 488 | return (-1); 489 | } 490 | } 491 | 492 | /* Scan in the default value (if any) */ 493 | while (ArgText[sidx] == ' ' || ArgText[sidx] == 9) 494 | sidx++; 495 | 496 | if (ArgText[sidx] == '=') { 497 | sidx++; 498 | while (ArgText[sidx] == ' ' || ArgText[sidx] == 9) 499 | sidx++; 500 | i = 0; 501 | while (ArgText[sidx] != ' ' && ArgText[sidx] != 9 && ArgText[sidx] != '=' && 502 | ArgText[sidx] != 0) { 503 | if (i == TOKEN_MAX_LEN) { 504 | Report(ps, REP_ERROR, "Macro argument value too long"); 505 | return (-1); 506 | } 507 | if (!LabelChar(ArgText[sidx], 0) && ArgText[sidx] != '.') 508 | goto MARG_SYNTAX; 509 | pm->ArgDefault[pm->Arguments][i++] = ArgText[sidx++]; 510 | } 511 | pm->ArgDefault[pm->Arguments][i] = 0; 512 | if (!i) 513 | goto MARG_SYNTAX; 514 | pm->Arguments++; 515 | } else { 516 | pm->ArgDefault[pm->Arguments][0] = 0; 517 | if (pm->Arguments > pm->Required) { 518 | Report(ps, REP_ERROR, "Optional macro arguments must be listed last"); 519 | return (-1); 520 | } 521 | pm->Arguments++; 522 | pm->Required++; 523 | } 524 | 525 | if (ArgText[sidx] != 0) { 526 | MARG_SYNTAX: 527 | Report(ps, REP_ERROR, 528 | "Syntax error in macro argument '%s' around character %d", ArgText, 529 | sidx + 1); 530 | return (-1); 531 | } 532 | 533 | return (0); 534 | } 535 | 536 | /* 537 | // MacroDestroy 538 | // 539 | // Frees a macro record. 540 | // 541 | // void 542 | */ 543 | static void MacroDestroy(MACRO *pm) { 544 | if (!pm->pPrev) 545 | pMacroList = pm->pNext; 546 | else 547 | pm->pPrev->pNext = pm->pNext; 548 | 549 | if (pm->pNext) 550 | pm->pNext->pPrev = pm->pPrev; 551 | 552 | free(pm); 553 | } 554 | -------------------------------------------------------------------------------- /am335x/pasm/pru_ins.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pru_ins.h 3 | * 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the 17 | * distribution. 18 | * 19 | * Neither the name of Texas Instruments Incorporated nor the names of 20 | * its contributors may be used to endorse or promote products derived 21 | * from this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | 37 | /*=========================================================================== 38 | * Copyright (c) Texas Instruments Inc 2010-12 39 | * 40 | * Use of this software is controlled by the terms and conditions found in the 41 | * license agreement under which this software has been supplied or provided. 42 | * ============================================================================ 43 | */ 44 | 45 | /*=========================================================================== 46 | // PASM - PRU Assembler 47 | //--------------------------------------------------------------------------- 48 | // 49 | // File : pru_ins.h 50 | // 51 | // Description: 52 | // Defines a data structre PRU_INST that can completely describe a 53 | // PRU opcode. 54 | // 55 | //--------------------------------------------------------------------------- 56 | // Revision: 57 | // 21-Jun-13: 0.84 - Open source version 58 | ============================================================================*/ 59 | 60 | typedef struct _PRU_ARG { 61 | uint Type; 62 | uint Flags; /* Flags for RegisterBit type */ 63 | #define PA_FLG_REGPOINTER 0x0001 64 | #define PA_FLG_POSTINC 0x0002 65 | #define PA_FLG_PREDEC 0x0004 66 | uint Value; /* Reg #, Imm Val, Count Val */ 67 | uint Field; /* Field for Registers */ 68 | uint Bit; /* Bit # for RegisterBit type */ 69 | } PRU_ARG; 70 | 71 | #define ARGTYPE_REGISTER 1 /* Standard register and field */ 72 | #define ARGTYPE_IMMEDIATE 2 /* Immediate value */ 73 | #define ARGTYPE_COUNT 3 /* Count for burst */ 74 | #define ARGTYPE_R0BYTE 4 /* Byte from R0 */ 75 | #define ARGTYPE_CONSTANT 5 /* Constant Table Index */ 76 | #define ARGTYPE_OFFSET 6 /* 10 bit offset for jumps */ 77 | #define ARGTYPE_REGISTERBIT 7 /* Register in Rxx.Txx format Field=bitno */ 78 | 79 | #define FIELDTYPE_7_0 0 /* Bits 7:0 */ 80 | #define FIELDTYPE_15_8 1 /* Bits 15:8 */ 81 | #define FIELDTYPE_23_16 2 /* Bits 23:16 */ 82 | #define FIELDTYPE_31_24 3 /* Bits 31:24 */ 83 | #define FIELDTYPE_15_0 4 /* Bits 15:0 */ 84 | #define FIELDTYPE_23_8 5 /* Bits 23:8 */ 85 | #define FIELDTYPE_31_16 6 /* Bits 31:16 */ 86 | #define FIELDTYPE_31_0 7 /* Bits 31:0 */ 87 | 88 | #define FIELDTYPE_OFF_0 0 /* Offset bit 0 */ 89 | #define FIELDTYPE_OFF_8 1 /* Offset bit 8 */ 90 | #define FIELDTYPE_OFF_16 2 /* Offset bit 16 */ 91 | #define FIELDTYPE_OFF_24 3 /* Offset bit 24 */ 92 | 93 | extern char *FieldText[]; 94 | 95 | typedef struct _PRU_INST { 96 | uint Op; /* Operation */ 97 | uint ArgCnt; /* Argument Count */ 98 | PRU_ARG Arg[4]; /* Arguments */ 99 | } PRU_INST; 100 | 101 | #define OP_ADD 1 102 | #define OP_ADC 2 103 | #define OP_SUB 3 104 | #define OP_SUC 4 105 | #define OP_LSL 5 106 | #define OP_LSR 6 107 | #define OP_RSB 7 108 | #define OP_RSC 8 109 | #define OP_AND 9 110 | #define OP_OR 10 111 | #define OP_XOR 11 112 | #define OP_NOT 12 113 | #define OP_MIN 13 114 | #define OP_MAX 14 115 | #define OP_CLR 15 116 | #define OP_SET 16 117 | #define OP_LDI 17 118 | #define OP_LBBO 18 119 | #define OP_LBCO 19 120 | #define OP_SBBO 20 121 | #define OP_SBCO 21 122 | #define OP_LFC 22 123 | #define OP_STC 23 124 | #define OP_JAL 24 125 | #define OP_JMP 25 126 | #define OP_QBGT 26 127 | #define OP_QBLT 27 128 | #define OP_QBEQ 28 129 | #define OP_QBGE 29 130 | #define OP_QBLE 30 131 | #define OP_QBNE 31 132 | #define OP_QBA 32 133 | #define OP_QBBS 33 134 | #define OP_QBBC 34 135 | #define OP_LMBD 35 136 | #define OP_CALL 36 137 | #define OP_WBC 37 138 | #define OP_WBS 38 139 | #define OP_MOV 39 140 | #define OP_MVIB 40 141 | #define OP_MVIW 41 142 | #define OP_MVID 42 143 | #define OP_SCAN 43 144 | #define OP_HALT 44 145 | #define OP_SLP 45 146 | #define OP_RET 46 147 | #define OP_ZERO 47 148 | #define OP_FILL 48 149 | #define OP_XIN 49 150 | #define OP_XOUT 50 151 | #define OP_XCHG 51 152 | #define OP_SXIN 52 153 | #define OP_SXOUT 53 154 | #define OP_SXCHG 54 155 | #define OP_LOOP 55 156 | #define OP_ILOOP 56 157 | #define OP_NOP0 57 158 | #define OP_NOP1 58 159 | #define OP_NOP2 59 160 | #define OP_NOP3 60 161 | #define OP_NOP4 61 162 | #define OP_NOP5 62 163 | #define OP_NOP6 63 164 | #define OP_NOP7 64 165 | #define OP_NOP8 65 166 | #define OP_NOP9 66 167 | #define OP_NOPA 67 168 | #define OP_NOPB 68 169 | #define OP_NOPC 69 170 | #define OP_NOPD 70 171 | #define OP_NOPE 71 172 | #define OP_NOPF 72 173 | #define OP_MAXIDX 72 174 | 175 | extern char *OpText[]; 176 | -------------------------------------------------------------------------------- /dirtrees/BB-PRU-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toroidal-code/PixelBone/a5a432ebe30c61190d280cecd7d000bffef48622/dirtrees/BB-PRU-00A0.dtbo -------------------------------------------------------------------------------- /dirtrees/am335x-bone.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toroidal-code/PixelBone/a5a432ebe30c61190d280cecd7d000bffef48622/dirtrees/am335x-bone.dtb -------------------------------------------------------------------------------- /dirtrees/am335x-boneblack.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toroidal-code/PixelBone/a5a432ebe30c61190d280cecd7d000bffef48622/dirtrees/am335x-boneblack.dtb -------------------------------------------------------------------------------- /dirtrees/dtbo_loader.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo BB-PRU:00A0 > /sys/devices/bone_capemgr.*/slots 3 | -------------------------------------------------------------------------------- /examples/2048.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This program is based on the 2048 implementation by Maurits van der Schee. 3 | This program is licensed under the MIT License. 4 | */ 5 | 6 | #define _XOPEN_SOURCE 500 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "../matrix.hpp" 17 | 18 | #define SIZE 4 19 | 20 | #define BLOCK_WIDTH 4 21 | #define BLOCK_HEIGHT 2 22 | 23 | #define BOARD_HEIGHT 8 24 | #define BOARD_WIDTH 16 25 | 26 | uint32_t score = 0; 27 | 28 | uint16_t getColor(uint16_t value) { 29 | if (value == 2) { 30 | return PixelBone_Matrix::Color(221, 221, 221); 31 | } else if (value == 4) { 32 | return PixelBone_Matrix::Color(152, 95, 168); 33 | } else if (value == 8) { 34 | return PixelBone_Matrix::Color(120, 197, 213); 35 | } else if (value == 16) { 36 | return PixelBone_Matrix::Color(121, 194, 104); 37 | } else if (value == 32) { 38 | return PixelBone_Matrix::Color(197, 215, 71); 39 | } else if (value == 64) { 40 | return PixelBone_Matrix::Color(245, 214, 61); 41 | } else if (value == 128) { 42 | return PixelBone_Matrix::Color(241, 140, 50); 43 | } else if (value == 256) { 44 | return PixelBone_Matrix::Color(232, 104, 161); 45 | } else if (value == 512) { 46 | return PixelBone_Matrix::Color(191, 99, 166); 47 | } else if (value == 1024) { 48 | return PixelBone_Matrix::Color(237, 197, 63); 49 | } else if (value == 2048) { 50 | return PixelBone_Matrix::Color(237, 194, 46); 51 | } else { 52 | return PixelBone_Matrix::Color(0, 0, 0); 53 | } 54 | } 55 | 56 | void drawBoard(PixelBone_Matrix &matrix, uint16_t board[SIZE][SIZE]) { 57 | matrix.clear(); 58 | for (int16_t y = 0; y < SIZE; y++) { 59 | for (int16_t x = 0; x < SIZE; x++) { 60 | uint16_t color = getColor(board[x][y]); 61 | matrix.fillRect(x * BLOCK_WIDTH, y * BLOCK_HEIGHT, 62 | BLOCK_WIDTH, BLOCK_HEIGHT, color); 63 | } 64 | } 65 | matrix.wait(); 66 | matrix.show(); 67 | matrix.moveToNextBuffer(); 68 | } 69 | 70 | int8_t findTarget(uint16_t array[SIZE], int8_t x, int8_t stop) { 71 | int8_t t; 72 | // if the position is already on the first, don't evaluate 73 | if (x == 0) { 74 | return x; 75 | } 76 | for (t = x - 1; t >= 0; t--) { 77 | if (array[t] != 0) { 78 | if (array[t] != array[x]) { 79 | // merge is not possible, take next position 80 | return t + 1; 81 | } 82 | return t; 83 | } else { 84 | // we should not slide further, return this one 85 | if (t == stop) { 86 | return t; 87 | } 88 | } 89 | } 90 | // we did not find a 91 | return x; 92 | } 93 | 94 | bool slideArray(uint16_t array[SIZE]) { 95 | bool success = false; 96 | int8_t x, t, stop = 0; 97 | 98 | for (x = 0; x < SIZE; x++) { 99 | if (array[x] != 0) { 100 | t = findTarget(array, x, stop); 101 | // if target is not original position, then move or merge 102 | if (t != x) { 103 | // if target is not zero, set stop to avoid double merge 104 | if (array[t] != 0) { 105 | score += array[t] + array[x]; 106 | stop = t + 1; 107 | } 108 | array[t] += array[x]; 109 | array[x] = 0; 110 | success = true; 111 | } 112 | } 113 | } 114 | return success; 115 | } 116 | 117 | void rotateBoard(uint16_t board[SIZE][SIZE]) { 118 | int8_t i, j, n = SIZE; 119 | uint16_t tmp; 120 | for (i = 0; i < n / 2; i++) { 121 | for (j = i; j < n - i - 1; j++) { 122 | tmp = board[i][j]; 123 | board[i][j] = board[j][n - i - 1]; 124 | board[j][n - i - 1] = board[n - i - 1][n - j - 1]; 125 | board[n - i - 1][n - j - 1] = board[n - j - 1][i]; 126 | board[n - j - 1][i] = tmp; 127 | } 128 | } 129 | } 130 | 131 | bool moveUp(uint16_t board[SIZE][SIZE]) { 132 | bool success = false; 133 | int8_t x; 134 | for (x = 0; x < SIZE; x++) { 135 | success |= slideArray(board[x]); 136 | } 137 | return success; 138 | } 139 | 140 | bool moveLeft(uint16_t board[SIZE][SIZE]) { 141 | bool success; 142 | rotateBoard(board); 143 | success = moveUp(board); 144 | rotateBoard(board); 145 | rotateBoard(board); 146 | rotateBoard(board); 147 | return success; 148 | } 149 | 150 | bool moveDown(uint16_t board[SIZE][SIZE]) { 151 | bool success; 152 | rotateBoard(board); 153 | rotateBoard(board); 154 | success = moveUp(board); 155 | rotateBoard(board); 156 | rotateBoard(board); 157 | return success; 158 | } 159 | 160 | bool moveRight(uint16_t board[SIZE][SIZE]) { 161 | bool success; 162 | rotateBoard(board); 163 | rotateBoard(board); 164 | rotateBoard(board); 165 | success = moveUp(board); 166 | rotateBoard(board); 167 | return success; 168 | } 169 | 170 | bool findPairDown(uint16_t board[SIZE][SIZE]) { 171 | bool success = false; 172 | int8_t x, y; 173 | for (x = 0; x < SIZE; x++) { 174 | for (y = 0; y < SIZE - 1; y++) { 175 | if (board[x][y] == board[x][y + 1]) 176 | return true; 177 | } 178 | } 179 | return success; 180 | } 181 | 182 | int16_t countEmpty(uint16_t board[SIZE][SIZE]) { 183 | int8_t x, y; 184 | int16_t count = 0; 185 | for (x = 0; x < SIZE; x++) { 186 | for (y = 0; y < SIZE; y++) { 187 | if (board[x][y] == 0) { 188 | count++; 189 | } 190 | } 191 | } 192 | return count; 193 | } 194 | 195 | bool gameEnded(uint16_t board[SIZE][SIZE]) { 196 | bool ended = true; 197 | if (countEmpty(board) > 0) 198 | return false; 199 | if (findPairDown(board)) 200 | return false; 201 | rotateBoard(board); 202 | if (findPairDown(board)) 203 | ended = false; 204 | rotateBoard(board); 205 | rotateBoard(board); 206 | rotateBoard(board); 207 | return ended; 208 | } 209 | 210 | void addRandom(uint16_t board[SIZE][SIZE]) { 211 | static bool initialized = false; 212 | int8_t x, y; 213 | int16_t r, len = 0; 214 | uint16_t n, list[SIZE * SIZE][2]; 215 | 216 | if (!initialized) { 217 | srand(time(NULL)); 218 | initialized = true; 219 | } 220 | 221 | for (x = 0; x < SIZE; x++) { 222 | for (y = 0; y < SIZE; y++) { 223 | if (board[x][y] == 0) { 224 | list[len][0] = x; 225 | list[len][1] = y; 226 | len++; 227 | } 228 | } 229 | } 230 | 231 | if (len > 0) { 232 | r = rand() % len; 233 | x = list[r][0]; 234 | y = list[r][1]; 235 | n = ((rand() % 10) / 9 + 1) * 2; 236 | board[x][y] = n; 237 | } 238 | } 239 | 240 | void setBufferedInput(bool enable) { 241 | static bool enabled = true; 242 | static struct termios old; 243 | struct termios newt; 244 | 245 | if (enable && !enabled) { 246 | // restore the former settings 247 | tcsetattr(STDIN_FILENO, TCSANOW, &old); 248 | // set the new state 249 | enabled = true; 250 | } else if (!enable && enabled) { 251 | // get the terminal settings for standard input 252 | tcgetattr(STDIN_FILENO, &newt); 253 | // we want to keep the old setting to restore them at the end 254 | old = newt; 255 | // disable canonical mode (buffered i/o) and local echo 256 | newt.c_lflag &= (~ICANON & ~ECHO); 257 | // set the new settings immediately 258 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); 259 | // set the new state 260 | enabled = false; 261 | } 262 | } 263 | 264 | int test() { 265 | uint16_t array[SIZE]; 266 | uint16_t data[] = { 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 4, 0, 0, 0, 0, 2, 267 | 0, 2, 4, 0, 0, 0, 2, 0, 0, 2, 4, 0, 0, 0, 2, 0, 2, 0, 268 | 4, 0, 0, 0, 2, 2, 2, 0, 4, 2, 0, 0, 2, 0, 2, 2, 4, 2, 269 | 0, 0, 2, 2, 0, 2, 4, 2, 0, 0, 2, 2, 2, 2, 4, 4, 0, 0, 270 | 4, 4, 2, 2, 8, 4, 0, 0, 2, 2, 4, 4, 4, 8, 0, 0, 8, 0, 271 | 2, 2, 8, 4, 0, 0, 4, 0, 2, 2, 4, 4, 0, 0 }; 272 | uint16_t *in, *out; 273 | uint16_t t, tests; 274 | uint8_t i; 275 | bool success = true; 276 | 277 | tests = (sizeof(data) / sizeof(data[0])) / (2 * SIZE); 278 | for (t = 0; t < tests; t++) { 279 | in = data + t * 2 * SIZE; 280 | out = in + SIZE; 281 | for (i = 0; i < SIZE; i++) { 282 | array[i] = in[i]; 283 | } 284 | slideArray(array); 285 | for (i = 0; i < SIZE; i++) { 286 | if (array[i] != out[i]) { 287 | success = false; 288 | } 289 | } 290 | if (success == false) { 291 | for (i = 0; i < SIZE; i++) { 292 | printf("%d ", in[i]); 293 | } 294 | printf("=> "); 295 | for (i = 0; i < SIZE; i++) { 296 | printf("%d ", array[i]); 297 | } 298 | printf("expected "); 299 | for (i = 0; i < SIZE; i++) { 300 | printf("%d ", in[i]); 301 | } 302 | printf("=> "); 303 | for (i = 0; i < SIZE; i++) { 304 | printf("%d ", out[i]); 305 | } 306 | printf("\n"); 307 | break; 308 | } 309 | } 310 | if (success) { 311 | printf("All %u tests executed successfully\n", tests); 312 | } 313 | return !success; 314 | } 315 | 316 | void signal_callback_handler(int signum) { 317 | printf(" TERMINATED \n"); 318 | setBufferedInput(true); 319 | exit(signum); 320 | } 321 | 322 | int main(int argc, char *argv[]) { 323 | uint16_t board[SIZE][SIZE]; 324 | char c; 325 | bool success; 326 | PixelBone_Matrix* matrix = 327 | new PixelBone_Matrix(BOARD_WIDTH,BOARD_HEIGHT, 328 | MATRIX_TOP + MATRIX_LEFT + 329 | MATRIX_ROWS + MATRIX_ZIGZAG); 330 | 331 | if (argc == 2 && strcmp(argv[1], "test") == 0) { 332 | return test(); 333 | } 334 | 335 | 336 | // register signal handler for when ctrl-c is pressed 337 | signal(SIGINT, signal_callback_handler); 338 | 339 | memset(board, 0, sizeof(board)); 340 | addRandom(board); 341 | addRandom(board); 342 | drawBoard(*matrix, board); 343 | setBufferedInput(false); 344 | while (true) { 345 | c = getchar(); 346 | switch (c) { 347 | case 97: // 'a' key 348 | case 104: // 'h' key 349 | case 68: // left arrow 350 | success = moveLeft(board); 351 | break; 352 | case 100: // 'd' key 353 | case 108: // 'l' key 354 | case 67: // right arrow 355 | success = moveRight(board); 356 | break; 357 | case 119: // 'w' key 358 | case 107: // 'k' key 359 | case 65: // up arrow 360 | success = moveUp(board); 361 | break; 362 | case 115: // 's' key 363 | case 106: // 'j' key 364 | case 66: // down arrow 365 | success = moveDown(board); 366 | break; 367 | default: 368 | success = false; 369 | } 370 | if (success) { 371 | drawBoard(*matrix, board); 372 | usleep(150000); 373 | addRandom(board); 374 | drawBoard(*matrix, board); 375 | if (gameEnded(board)) { 376 | printf(" GAME OVER \n"); 377 | break; 378 | } 379 | } 380 | if (c == 'q') { 381 | printf(" QUIT? (y/n) \n"); 382 | while (true) { 383 | c = getchar(); 384 | if (c == 'y') { 385 | setBufferedInput(true); 386 | exit(0); 387 | } else { 388 | drawBoard(*matrix, board); 389 | break; 390 | } 391 | } 392 | } 393 | if (c == 'r') { 394 | printf(" RESTART? (y/n) \n"); 395 | while (true) { 396 | c = getchar(); 397 | if (c == 'y') { 398 | memset(board, 0, sizeof(board)); 399 | addRandom(board); 400 | addRandom(board); 401 | drawBoard(*matrix, board); 402 | break; 403 | } else { 404 | drawBoard(*matrix, board); 405 | break; 406 | } 407 | } 408 | } 409 | } 410 | setBufferedInput(true); 411 | matrix->wait(); 412 | matrix->clear(); 413 | matrix->show(); 414 | delete matrix; 415 | 416 | return EXIT_SUCCESS; 417 | } 418 | -------------------------------------------------------------------------------- /examples/binary_clock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../matrix.hpp" 5 | 6 | #define HEIGHT 8 7 | #define WIDTH 16 8 | 9 | #define DIGIT_WIDTH 2 10 | #define DIGIT_HEIGHT 2 11 | 12 | const uint16_t color_hour = PixelBone_Pixel::Color(0x00, 0xff, 0xff); 13 | const uint16_t color_min = PixelBone_Pixel::Color( 0x00, 0xf0, 0x00); 14 | const uint16_t color_sec = PixelBone_Pixel::Color( 0xff, 0xff, 0x00); 15 | const uint16_t color_empty = PixelBone_Pixel::Color( 0x00, 0x00, 0x00); 16 | 17 | 18 | void draw_clock(PixelBone_Matrix *matrix, tm *t) { 19 | int tmp; 20 | 21 | uint16_t x = DIGIT_WIDTH; 22 | uint16_t y = HEIGHT - DIGIT_HEIGHT; 23 | 24 | /* Clear everything. */ 25 | matrix->clear(); 26 | tmp = t->tm_hour / 10; 27 | 28 | // printf("Drawing %d, %d\n", x, y); 29 | 30 | /* Draw hour (first digit). */ 31 | while (tmp != 0) { 32 | if (tmp % 2 == 1) { 33 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_hour); 34 | } else { 35 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_empty); 36 | } 37 | y -= DIGIT_HEIGHT; 38 | tmp >>= 1; 39 | } 40 | 41 | x += DIGIT_WIDTH; 42 | y = HEIGHT - DIGIT_HEIGHT; 43 | tmp = t->tm_hour % 10; 44 | 45 | /* Draw hour (second digit). */ 46 | while (tmp != 0) { 47 | if (tmp % 2 == 1) { 48 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_hour); 49 | } else { 50 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_empty); 51 | } 52 | y -= DIGIT_HEIGHT; 53 | tmp >>= 1; 54 | } 55 | 56 | x += DIGIT_WIDTH; 57 | y = HEIGHT - DIGIT_HEIGHT; 58 | tmp = t->tm_min / 10; 59 | 60 | /* Draw minute (first digit). */ 61 | while (tmp != 0) { 62 | if (tmp % 2 == 1) { 63 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_min); 64 | } else { 65 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_empty); 66 | } 67 | y -= DIGIT_HEIGHT; 68 | tmp >>= 1; 69 | } 70 | 71 | x += DIGIT_WIDTH; 72 | y = HEIGHT - DIGIT_HEIGHT; 73 | tmp = t->tm_min % 10; 74 | 75 | /* Draw minute (second digit). */ 76 | while (tmp != 0) { 77 | if (tmp % 2 == 1) { 78 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_min); 79 | } else { 80 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_empty); 81 | } 82 | y -= DIGIT_HEIGHT; 83 | tmp >>= 1; 84 | } 85 | 86 | x += DIGIT_WIDTH; 87 | y = HEIGHT - DIGIT_HEIGHT; 88 | tmp = t->tm_sec / 10; 89 | 90 | /* Draw second (first digit). */ 91 | while (tmp != 0) { 92 | if (tmp % 2 == 1) { 93 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_sec); 94 | } else { 95 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_empty); 96 | } 97 | y -= DIGIT_HEIGHT; 98 | tmp >>= 1; 99 | } 100 | 101 | x += DIGIT_WIDTH; 102 | y = HEIGHT - DIGIT_HEIGHT; 103 | tmp = t->tm_sec % 10; 104 | /* Draw second (second digit). */ 105 | while (tmp != 0) { 106 | if (tmp % 2 == 1) { 107 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_sec); 108 | } else { 109 | matrix->drawRect(x, y, DIGIT_WIDTH, DIGIT_HEIGHT, color_empty); 110 | } 111 | y -= DIGIT_HEIGHT; 112 | tmp >>= 1; 113 | } 114 | } 115 | 116 | int main(void) { 117 | PixelBone_Matrix* matrix = new PixelBone_Matrix(WIDTH,HEIGHT, 118 | MATRIX_TOP + MATRIX_LEFT + 119 | MATRIX_ROWS + MATRIX_ZIGZAG); 120 | 121 | struct tm *now; 122 | time_t t_curr; 123 | 124 | while (true) { 125 | /* Update time and draw clock here. */ 126 | t_curr = time(NULL); 127 | now = localtime(&(t_curr)); 128 | draw_clock(matrix, now); 129 | matrix->wait(); 130 | matrix->show(); 131 | matrix->moveToNextBuffer(); 132 | } 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /examples/clear.cpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Test the ledscape library by pulsing RGB on the first three LEDS. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | //#include 12 | #include "../pixel.hpp" 13 | 14 | int main(void) { 15 | const int num_pixels = 512; 16 | PixelBone_Pixel strip(num_pixels); 17 | strip.clear(); 18 | strip.show(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/clock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../gfx.hpp" 4 | #include "../matrix.hpp" 5 | 6 | // MATRIX DECLARATION: 7 | // Parameter 1 = width of NeoPixel matrix 8 | // Parameter 2 = height of matrix 9 | // Parameter 3 = number of matrices arranged horizontally 10 | // Parameter 4 = number of matrices arranged vertically 11 | // Parameter 5 = matrix layout flags, add together as needed: 12 | // MATRIX_TOP, MATRIX_BOTTOM, MATRIX_LEFT, MATRIX_RIGHT: 13 | // Position of the FIRST LED in the matrix; pick two, e.g. 14 | // MATRIX_TOP + MATRIX_LEFT for the top-left corner. 15 | // MATRIX_ROWS, MATRIX_COLUMNS: LEDs are arranged in horizontal 16 | // rows or in vertical columns, respectively; pick one or the other. 17 | // MATRIX_PROGRESSIVE, MATRIX_ZIGZAG: all rows/columns proceed 18 | // in the same order, or alternate lines reverse direction; pick one. 19 | // TILE_TOP, TILE_BOTTOM, TILE_LEFT, TILE_RIGHT: 20 | // Position of the FIRST MATRIX (tile) in the OVERALL DISPLAY; pick 21 | // two, e.g. TILE_TOP + TILE_LEFT for the top-left corner. 22 | // TILE_ROWS, TILE_COLUMNS: the matrices in the OVERALL DISPLAY 23 | // are arranged in horizontal rows or in vertical columns, respectively; 24 | // pick one or the other. 25 | // TILE_PROGRESSIVE, TILE_ZIGZAG: the ROWS/COLUMS OF MATRICES 26 | // (tiles) in the OVERALL DISPLAY proceed in the same order for every 27 | // line, or alternate lines reverse direction; pick one. When using 28 | // zig-zag order, the orientation of the matrices in alternate rows 29 | // will be rotated 180 degrees (this is normal -- simplifies wiring). 30 | // See example below for these values in action. 31 | 32 | int main() { 33 | PixelBone_Matrix matrix(16,8,4,1, 34 | TILE_TOP + TILE_LEFT + TILE_ROWS + TILE_PROGRESSIVE + 35 | MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS + MATRIX_ZIGZAG); 36 | 37 | matrix.setTextWrap(false); 38 | matrix.setTextColor(PixelBone_Pixel::Color(0,50,0)); 39 | 40 | int x = 0; 41 | while (1) { 42 | matrix.clear(); 43 | matrix.setCursor(x, 0); 44 | time_t t = time(0); // get time now 45 | struct tm * now = localtime( & t ); 46 | char buf[80]; 47 | //%a %Y-%m-%d 48 | strftime(buf, sizeof(buf), "%r", now); 49 | 50 | // if (--x < -36) 51 | // x = matrix.width(); 52 | matrix.print(buf); 53 | matrix.show(); 54 | matrix.wait(); 55 | matrix.moveToNextBuffer(); 56 | } 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/fade-test.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Test the ledscape library by pulsing RGB on the first three LEDS. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "../ledscape.h" 13 | 14 | 15 | int lumCorrection[] = { 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 17 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18 | 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 19 | 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 7, 7, 20 | 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 21 | 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 22 | 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 26, 27, 28, 23 | 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 38, 39, 24 | 39, 40, 41, 42, 43, 44, 44, 45, 46, 47, 48, 49, 50, 51, 52, 25 | 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 26 | 68, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 82, 83, 84, 85, 27 | 87, 89, 91, 92, 93, 95, 96, 98, 99, 100, 101, 102, 105, 106, 108, 28 | 109, 111, 112, 114, 115, 117, 118, 120, 121, 123, 125, 126, 128, 130, 131, 29 | 133, 135, 136, 138, 140, 142, 143, 145, 147, 149, 151, 152, 154, 156, 158, 30 | 160, 162, 164, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 31 | 190, 192, 194, 196, 198, 200, 202, 204, 207, 209, 211, 213, 216, 218, 220, 32 | 222, 225, 227, 229, 232, 234, 236, 239, 241, 244, 246, 249, 251, 253, 254, 33 | 255 34 | }; 35 | 36 | int main(void) { 37 | const int num_pixels = 128; 38 | ledscape_t *const leds = ledscape_init(num_pixels); 39 | time_t last_time = time(NULL); 40 | unsigned last_i = 0; 41 | 42 | 43 | unsigned i = 0; 44 | while (1) { 45 | // Alternate frame buffers on each draw command 46 | const unsigned frame_num = i++ % 2; 47 | ledscape_frame_t *const frame = ledscape_frame(leds, frame_num); 48 | 49 | 50 | for (unsigned strip = 0; strip < 32; strip++) { 51 | for (unsigned p = 0; p < num_pixels; p++) { 52 | int bInput = i % 256, bOutput = lumCorrection[bInput / 4]; 53 | 54 | if (p < 64 && bInput % 2 == 0) { 55 | bOutput++; 56 | } 57 | 58 | ledscape_set_color(frame, strip, p, bOutput, 0, 0); 59 | // ledscape_set_color(frame, strip, 3*p+1, 0, p+val + 80, 0); 60 | // ledscape_set_color(frame, strip, 3*p+2, 0, 0, p+val + 160); 61 | } 62 | } 63 | 64 | // wait for the previous frame to finish; 65 | const uint32_t response = ledscape_wait(leds); 66 | time_t now = time(NULL); 67 | if (now != last_time) { 68 | printf("%d fps. starting %d previous %" PRIx32 "\n", i - last_i, i, 69 | response); 70 | last_i = i; 71 | last_time = now; 72 | } 73 | 74 | ledscape_draw(leds, frame_num); 75 | } 76 | 77 | ledscape_close(leds); 78 | 79 | return EXIT_SUCCESS; 80 | } 81 | 82 | // Gamma Correction Curve 83 | const uint8_t dim_curve[] = { 84 | 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 85 | 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 86 | 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 87 | 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 88 | 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 89 | 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 90 | 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 91 | 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 92 | 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 93 | 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 94 | 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 95 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 96 | 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 97 | 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 98 | 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 99 | 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 100 | 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 101 | 255, 102 | }; 103 | 104 | void HSBtoRGB(int hue, int sat, int val, uint8_t out[]) { 105 | /* convert hue, saturation and brightness ( HSB/HSV ) to RGB 106 | The dim_curve is used only on brightness/value and on saturation 107 | (inverted). 108 | This looks the most natural. 109 | */ 110 | 111 | val = dim_curve[val]; 112 | sat = 255 - dim_curve[255 - sat]; 113 | 114 | int r; 115 | int g; 116 | int b; 117 | int base; 118 | 119 | if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. 120 | r = g = b = val; 121 | } else { 122 | base = ((255 - sat) * val) >> 8; 123 | 124 | switch ((hue % 360) / 60) { 125 | case 0: 126 | r = val; 127 | g = (((val - base) * hue) / 60) + base; 128 | b = base; 129 | break; 130 | 131 | case 1: 132 | r = (((val - base) * (60 - (hue % 60))) / 60) + base; 133 | g = val; 134 | b = base; 135 | break; 136 | 137 | case 2: 138 | r = base; 139 | g = val; 140 | b = (((val - base) * (hue % 60)) / 60) + base; 141 | break; 142 | 143 | case 3: 144 | r = base; 145 | g = (((val - base) * (60 - (hue % 60))) / 60) + base; 146 | b = val; 147 | break; 148 | 149 | case 4: 150 | r = (((val - base) * (hue % 60)) / 60) + base; 151 | g = base; 152 | b = val; 153 | break; 154 | 155 | case 5: 156 | r = val; 157 | g = base; 158 | b = (((val - base) * (60 - (hue % 60))) / 60) + base; 159 | break; 160 | } 161 | 162 | out[0] = r; 163 | out[1] = g; 164 | out[2] = b; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /examples/fire.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Draw fire patterns, derived from the pyramid Fire code. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "../ledscape.h" 13 | 14 | // Borrowed by OctoWS2811 rainbow test 15 | static unsigned int h2rgb(unsigned int v1, unsigned int v2, unsigned int hue) { 16 | if (hue < 60) 17 | return v1 * 60 + (v2 - v1) * hue; 18 | if (hue < 180) 19 | return v2 * 60; 20 | if (hue < 240) 21 | return v1 * 60 + (v2 - v1) * (240 - hue); 22 | 23 | return v1 * 60; 24 | } 25 | 26 | // Convert HSL (Hue, Saturation, Lightness) to RGB (Red, Green, Blue) 27 | // 28 | // hue: 0 to 359 - position on the color wheel, 0=red, 60=orange, 29 | // 120=yellow, 180=green, 240=blue, 300=violet 30 | // 31 | // saturation: 0 to 100 - how bright or dull the color, 100=full, 0=gray 32 | // 33 | // lightness: 0 to 100 - how light the color is, 100=white, 50=color, 0=black 34 | // 35 | static uint32_t hsv2rgb(unsigned int hue, unsigned int saturation, 36 | unsigned int lightness) { 37 | unsigned int red, green, blue; 38 | unsigned int var1, var2; 39 | 40 | if (hue > 359) 41 | hue = hue % 360; 42 | if (saturation > 100) 43 | saturation = 100; 44 | if (lightness > 100) 45 | lightness = 100; 46 | 47 | // algorithm from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19 48 | if (saturation == 0) { 49 | red = green = blue = lightness * 255 / 100; 50 | } else { 51 | if (lightness < 50) { 52 | var2 = lightness * (100 + saturation); 53 | } else { 54 | var2 = ((lightness + saturation) * 100) - (saturation * lightness); 55 | } 56 | var1 = lightness * 200 - var2; 57 | red = h2rgb(var1, var2, (hue < 240) ? hue + 120 : hue - 240) * 255 / 600000; 58 | green = h2rgb(var1, var2, hue) * 255 / 600000; 59 | blue = 60 | h2rgb(var1, var2, (hue >= 120) ? hue - 120 : hue + 240) * 255 / 600000; 61 | } 62 | return (blue << 16) | (green << 8) | red; 63 | } 64 | 65 | static const int w = 256; 66 | static const int h = 20; 67 | 68 | // This will contain the pixels used to calculate the fire effect 69 | static uint8_t fire[256][32]; 70 | 71 | // Flame colors 72 | static uint32_t palette[255]; 73 | static float angle; 74 | static uint32_t calc1[256], calc2[256], calc3[256], calc4[256], calc5[256]; 75 | 76 | static void draw(uint32_t *frame) { 77 | memset(frame, 0, w * 16 * sizeof(*frame)); 78 | 79 | angle = angle + 0.05; 80 | 81 | // Randomize the bottom row of the fire buffer 82 | for (int x = 0; x < w; x++) { 83 | fire[x][h - 1] = random() % 190; 84 | } 85 | 86 | int counter = 0; 87 | // Do the fire calculations for every pixel, from top to bottom 88 | for (int y = 0; y < h; y++) { 89 | for (int x = 0; x < w; x++) { 90 | // Add pixel values around current pixel 91 | 92 | fire[x][y] = ((fire[calc3[x]][calc2[y]] + fire[calc1[x]][calc2[y]] + 93 | fire[calc4[x]][calc2[y]] + fire[calc1[x]][calc5[y]]) 94 | << 5) / 95 | (128 + (abs(x - w / 2)) / 4); // 129; 96 | 97 | // Output everything to screen using our palette colors 98 | const uint32_t c = palette[fire[x][y]]; 99 | // frame[counter] = fire[x][y]; 100 | 101 | // Extract the red value using right shift and bit mask 102 | // equivalent of red(pgTemp.pixels[x+y*w]) 103 | // Only map 3D cube 'lit' pixels onto fire array needed for next frame 104 | if (((c >> 0) & 0xFF) == 128) 105 | fire[x][y] = 128; 106 | 107 | if (y > 1 && y < 2 + 16) 108 | frame[counter++] = c; 109 | } 110 | } 111 | } 112 | 113 | static int constrain(int x, int min, int max) { 114 | if (x < min) 115 | return min; 116 | if (x > max) 117 | return max; 118 | return x; 119 | } 120 | 121 | static void init_pallete(void) { 122 | for (int x = 0; x < 255; x++) { 123 | // Hue goes from 0 to 85: red to yellow 124 | // Saturation is always the maximum: 255 125 | // Lightness is 0..255 for x=0..128, and 255 for x=128..255 126 | palette[x] = hsv2rgb(x / 2, 100, constrain(x, 0, 40)); 127 | } 128 | 129 | // Precalculate which pixel values to add during animation loop 130 | // this speeds up the effect by 10fps 131 | for (int x = 0; x < w; x++) { 132 | calc1[x] = x % w; 133 | calc3[x] = (x - 1 + w) % w; 134 | calc4[x] = (x + 1) % w; 135 | } 136 | 137 | for (int y = 0; y < h; y++) { 138 | calc2[y] = (y + 1) % h; 139 | calc5[y] = (y + 2) % h; 140 | } 141 | } 142 | 143 | int main(void) { 144 | const int num_pixels = 256; 145 | ledscape_t *const leds = ledscape_init(num_pixels); 146 | printf("init done\n"); 147 | time_t last_time = time(NULL); 148 | unsigned last_i = 0; 149 | 150 | unsigned i = 0; 151 | init_pallete(); 152 | 153 | while (1) { 154 | // Alternate frame buffers on each draw command 155 | const unsigned frame_num = i++ % 2; 156 | ledscape_frame_t *const frame = ledscape_frame(leds, frame_num); 157 | 158 | uint32_t *const p = (void *)frame; 159 | 160 | draw(p); 161 | ledscape_draw(leds, frame_num); 162 | usleep(30000); 163 | 164 | // wait for the previous frame to finish; 165 | // const uint32_t response = ledscape_wait(leds); 166 | const uint32_t response = 0; 167 | time_t now = time(NULL); 168 | if (now != last_time) { 169 | printf("%d fps. starting %d previous %" PRIx32 "\n", i - last_i, i, 170 | response); 171 | last_i = i; 172 | last_time = now; 173 | } 174 | } 175 | 176 | ledscape_close(leds); 177 | 178 | return EXIT_SUCCESS; 179 | } 180 | -------------------------------------------------------------------------------- /examples/game_of_life.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../matrix.hpp" 3 | #define HEIGHT 8 4 | #define WIDTH 64 5 | 6 | const uint16_t BLANK = PixelBone_Pixel::Color(0,0,0); 7 | const uint16_t WHITE = PixelBone_Pixel::Color(255,255,255); 8 | 9 | struct Shape { 10 | uint8_t xCoord; 11 | uint8_t yCoord; 12 | uint8_t height; 13 | uint8_t width; 14 | uint16_t **figure; 15 | }; 16 | 17 | struct Glider : public Shape { 18 | static const uint8_t GLIDER_SIZE = 3; 19 | Glider( uint8_t x , uint8_t y ); 20 | ~Glider(); 21 | }; 22 | 23 | struct Blinker : public Shape { 24 | static const uint8_t BLINKER_HEIGHT = 3; 25 | static const uint8_t BLINKER_WIDTH = 1; 26 | Blinker( uint8_t x , uint8_t y ); 27 | ~Blinker(); 28 | }; 29 | 30 | class GameOfLife { 31 | public: 32 | PixelBone_Matrix* world; 33 | Shape shape; 34 | GameOfLife( Shape sh ); 35 | ~GameOfLife(); 36 | void update(); 37 | uint8_t getState(uint16_t state , uint8_t xCoord , uint8_t yCoord); 38 | void iterate(unsigned int iterations); 39 | }; 40 | 41 | GameOfLife::GameOfLife( Shape sh ) : 42 | shape(sh) 43 | { 44 | world = new PixelBone_Matrix(16, 8, 4, 1, MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS + MATRIX_ZIGZAG + TILE_TOP + TILE_LEFT + TILE_ROWS); 45 | world->clear(); 46 | 47 | for ( int i = shape.yCoord; i - shape.yCoord < shape.height; i++ ) { 48 | for ( int j = shape.xCoord; j - shape.xCoord < shape.width; j++ ) { 49 | if ( i < HEIGHT && j < WIDTH ) { 50 | world->drawPixel(j, i, shape.figure[ i - shape.yCoord ][j - shape.xCoord ]); 51 | } 52 | } 53 | } 54 | world->show(); 55 | } 56 | 57 | GameOfLife::~GameOfLife(){ 58 | delete world; 59 | } 60 | 61 | void GameOfLife::update() { 62 | for (uint16_t i = 0; i < WIDTH; i++) { 63 | for (uint16_t j = 0; j < HEIGHT; j++) { 64 | world->drawPixel(i, j, GameOfLife::getState(world->getPixelColor(i, j), j, i)); 65 | } 66 | } 67 | } 68 | 69 | uint8_t GameOfLife::getState(uint16_t state, uint8_t yCoord, uint8_t xCoord) { 70 | uint8_t neighbors = 0; 71 | for ( int8_t i = yCoord - 1; i <= yCoord + 1; i++ ) { 72 | for ( int8_t j = xCoord - 1; j <= xCoord + 1; j++ ) { 73 | if ( i == yCoord && j == xCoord ) { 74 | continue; 75 | } 76 | if ( i > -1 && i < HEIGHT && j > -1 && j < WIDTH ) { 77 | if ( world->getPixelColor(j, i) == WHITE) { 78 | neighbors++; 79 | } 80 | } 81 | } 82 | } 83 | if (state == WHITE) { 84 | return ( neighbors > 1 && neighbors < 4 ) ? WHITE : BLANK; 85 | } 86 | else { 87 | return ( neighbors == 3 ) ? WHITE : BLANK; 88 | } 89 | } 90 | 91 | void GameOfLife::iterate(uint iterations) { 92 | for (uint i = 0; i < iterations; i++ ) { 93 | update(); 94 | if (getchar() == ' '){ 95 | world->show(); 96 | world->wait(); 97 | } 98 | //world->moveToNextBuffer(); 99 | } 100 | } 101 | 102 | Glider::Glider( uint8_t x , uint8_t y ) { 103 | xCoord = x; 104 | yCoord = y; 105 | height = GLIDER_SIZE; 106 | width = GLIDER_SIZE; 107 | figure = new uint16_t*[GLIDER_SIZE]; 108 | for ( uint8_t i = 0; i < GLIDER_SIZE; i++ ) { 109 | figure[i] = new uint16_t[GLIDER_SIZE]; 110 | } 111 | for ( uint8_t i = 0; i < GLIDER_SIZE; i++ ) { 112 | for ( uint8_t j = 0; j < GLIDER_SIZE; j++ ) { 113 | figure[i][j] = BLANK; 114 | } 115 | } 116 | figure[0][1] = WHITE; 117 | figure[1][2] = WHITE; 118 | figure[2][0] = WHITE; 119 | figure[2][1] = WHITE; 120 | figure[2][2] = WHITE; 121 | } 122 | 123 | Glider::~Glider() { 124 | for ( uint8_t i = 0; i < GLIDER_SIZE; i++ ) { 125 | delete[] figure[i]; 126 | } 127 | delete[] figure; 128 | } 129 | 130 | Blinker::Blinker( uint8_t x , uint8_t y ) { 131 | xCoord = x; 132 | yCoord = y; 133 | height = BLINKER_HEIGHT; 134 | width = BLINKER_WIDTH; 135 | figure = new uint16_t*[BLINKER_HEIGHT]; 136 | for ( uint8_t i = 0; i < BLINKER_HEIGHT; i++ ) { 137 | figure[i] = new uint16_t[BLINKER_WIDTH]; 138 | } 139 | for ( uint8_t i = 0; i < BLINKER_HEIGHT; i++ ) { 140 | for ( uint8_t j = 0; j < BLINKER_WIDTH; j++ ) { 141 | figure[i][j] = WHITE; 142 | } 143 | } 144 | } 145 | 146 | Blinker::~Blinker() { 147 | for ( uint8_t i = 0; i < BLINKER_HEIGHT; i++ ) { 148 | delete[] figure[i]; 149 | } 150 | delete[] figure; 151 | } 152 | 153 | int main() { 154 | Glider glider(0,0); 155 | GameOfLife gol(glider); 156 | gol.iterate(20); 157 | // Blinker blinker(1,0); 158 | // GameOfLife gol2(blinker); 159 | // gol2.iterate(4); 160 | } 161 | 162 | -------------------------------------------------------------------------------- /examples/matrix-test.cpp: -------------------------------------------------------------------------------- 1 | #include "../gfx.hpp" 2 | #include "../matrix.hpp" 3 | 4 | // MATRIX DECLARATION: 5 | // Parameter 1 = width of NeoPixel matrix 6 | // Parameter 2 = height of matrix 7 | // Parameter 3 = matrix layout flags, add together as needed: 8 | // MATRIX_TOP, MATRIX_BOTTOM, MATRIX_LEFT, MATRIX_RIGHT: 9 | // Position of the FIRST LED in the matrix; pick two, e.g. 10 | // MATRIX_TOP + MATRIX_LEFT for the top-left corner. 11 | // MATRIX_ROWS, MATRIX_COLUMNS: LEDs are arranged in horizontal 12 | // rows or in vertical columns, respectively; pick one or the other. 13 | // MATRIX_PROGRESSIVE, MATRIX_ZIGZAG: all rows/columns proceed 14 | // in the same order, or alternate lines reverse direction; pick one. 15 | // See example below for these values in action. 16 | 17 | int main() { 18 | PixelBone_Matrix matrix(16,8, 19 | MATRIX_TOP + MATRIX_LEFT + 20 | MATRIX_ROWS + MATRIX_ZIGZAG); 21 | 22 | matrix.setTextWrap(false); 23 | matrix.setTextColor(PixelBone_Pixel::Color(128, 128, 128)); 24 | 25 | int x = 0; 26 | while (1) { 27 | matrix.fillScreen(0); 28 | matrix.setCursor(x, 0); 29 | matrix.print("Howdy"); 30 | 31 | if (--x < -36) 32 | x = matrix.width(); 33 | 34 | matrix.show(); 35 | usleep(100000); 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /examples/python-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Draw images with PIL and send them to the display. 3 | # Dual scrolling example with fixed time on each side and 4 | # the date scrolling around. 5 | # 6 | import Image, ImageFont, ImageDraw 7 | import socket 8 | import time, datetime 9 | from colorsys import hsv_to_rgb 10 | 11 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 12 | dest = ("localhost", 9999) 13 | 14 | #print im.format, im.size, im.mode 15 | # use a truetype font 16 | font = ImageFont.truetype("spincycle.ttf", 18) 17 | font_sm = ImageFont.truetype("pf_tempesta_seven.ttf", 8) 18 | 19 | i = 0 20 | width = 256 21 | disp = Image.new("RGB", (256,16), "black") 22 | im = Image.new("RGB", (width,16), "black") 23 | im_draw = ImageDraw.Draw(im) 24 | disp_draw = ImageDraw.Draw(disp) 25 | 26 | def rainbow(i): 27 | rgb = [int(x*256) for x in hsv_to_rgb(i/256.0,0.8,0.8)] 28 | return (rgb[0],rgb[1],rgb[2]) 29 | 30 | 31 | while True: 32 | im.paste("black", (0,0,width,16)) 33 | now = datetime.datetime.now() 34 | d = now.strftime("%a %d %b %Y") 35 | t = now.strftime("%H:%M") 36 | 37 | # Draw the date 38 | im_draw.text((0, -2), d, font=font, fill=rainbow(i)) 39 | 40 | # Make it scroll 41 | disp.paste(im.crop((0,0,i,16)), (256-i,0)) 42 | disp.paste(im.crop((i+1,0,255,16)), (0,0)) 43 | 44 | # draw the time on each face 45 | for x in range(0,7): 46 | disp_draw.text((4+x*32, 8-3), t, font=font_sm) 47 | 48 | # Send it to the drawing server 49 | sock.sendto(chr(1) + disp.tostring(), dest) 50 | i = (i+1) % width 51 | time.sleep(0.025) 52 | -------------------------------------------------------------------------------- /examples/rainbow.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use warnings; 3 | use strict; 4 | use IO::Socket; 5 | use Time::HiRes 'usleep'; 6 | 7 | # Make a smooth gradient pattern 8 | my $host = '192.168.7.2:9999'; 9 | 10 | my $sock = IO::Socket::INET->new( 11 | PeerAddr => $host, 12 | Proto => 'udp', 13 | ) or die "Socket failed: $!\n"; 14 | 15 | 16 | my $width = 64; 17 | my $height = 210; 18 | my $offset = 0; 19 | 20 | while (1) 21 | { 22 | $offset++; 23 | my $s = chr(1); 24 | my $bright = 0x30; 25 | 26 | for(my $y = 0 ; $y < $height ; $y++) 27 | { 28 | for(my $x = 0; $x < $width ; $x++) 29 | { 30 | my $r = (($x + $offset) % $width) * $bright / $width; 31 | my $g = 0; 32 | my $b = (($height - $y - 1 + $offset) % $height) * $bright / $height; 33 | 34 | $s .= chr($r); 35 | $s .= chr($g); 36 | $s .= chr($b); 37 | } 38 | } 39 | 40 | $sock->send($s); 41 | usleep(20000); 42 | } 43 | -------------------------------------------------------------------------------- /examples/rgb-test.cpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Test the ledscape library by pulsing RGB on the first three LEDS. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | //#include 12 | #include "../pixel.hpp" 13 | 14 | // Gamma Correction Curve 15 | const uint8_t dim_curve[] = { 16 | 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 17 | 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 18 | 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19 | 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 20 | 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 21 | 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 22 | 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 23 | 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 24 | 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 25 | 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 26 | 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 27 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 28 | 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 29 | 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 30 | 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 31 | 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 32 | 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 33 | 255, 34 | }; 35 | 36 | void HSBtoRGB(int hue, int sat, int val, uint8_t out[]) { 37 | /* convert hue, saturation and brightness ( HSB/HSV ) to RGB 38 | The dim_curve is used only on brightness/value and on saturation 39 | (inverted). 40 | This looks the most natural. 41 | */ 42 | 43 | val = dim_curve[val]; 44 | sat = 255 - dim_curve[255 - sat]; 45 | 46 | int r; 47 | int g; 48 | int b; 49 | int base; 50 | 51 | if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. 52 | r = g = b = val; 53 | } else { 54 | base = ((255 - sat) * val) >> 8; 55 | 56 | switch ((hue % 360) / 60) { 57 | case 0: 58 | r = val; 59 | g = (((val - base) * hue) / 60) + base; 60 | b = base; 61 | break; 62 | 63 | case 1: 64 | r = (((val - base) * (60 - (hue % 60))) / 60) + base; 65 | g = val; 66 | b = base; 67 | break; 68 | 69 | case 2: 70 | r = base; 71 | g = val; 72 | b = (((val - base) * (hue % 60)) / 60) + base; 73 | break; 74 | 75 | case 3: 76 | r = base; 77 | g = (((val - base) * (60 - (hue % 60))) / 60) + base; 78 | b = val; 79 | break; 80 | 81 | case 4: 82 | r = (((val - base) * (hue % 60)) / 60) + base; 83 | g = base; 84 | b = val; 85 | break; 86 | 87 | case 5: 88 | r = val; 89 | g = base; 90 | b = (((val - base) * (60 - (hue % 60))) / 60) + base; 91 | break; 92 | } 93 | 94 | out[0] = r; 95 | out[1] = g; 96 | out[2] = b; 97 | } 98 | } 99 | 100 | int main(void) { 101 | const int num_pixels = 512; 102 | PixelBone_Pixel *const strip = new PixelBone_Pixel(num_pixels); 103 | time_t last_time = time(NULL); 104 | unsigned last_i = 0; 105 | unsigned i = 0; 106 | uint8_t rgb[3]; 107 | 108 | while (1) { 109 | for (unsigned p = 0; p < num_pixels; p++) { 110 | HSBtoRGB(((i + (p * 360) / num_pixels) % 360), 100, 219, rgb); 111 | 112 | strip->setPixelColor(p, rgb[0], rgb[1], rgb[2]); 113 | } 114 | 115 | // wait for the previous frame to finish; 116 | const uint32_t response = strip->wait(); 117 | time_t now = time(NULL); 118 | 119 | if (now != last_time) { 120 | printf("%d fps. starting %d previous %d \n", i - last_i, i, response); 121 | last_i = i; 122 | last_time = now; 123 | } 124 | 125 | strip->show(); 126 | 127 | // Alternate frame buffers on each draw command 128 | strip->moveToNextBuffer(); 129 | i++; 130 | } 131 | 132 | delete strip; 133 | 134 | return EXIT_SUCCESS; 135 | } 136 | -------------------------------------------------------------------------------- /examples/scroll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | //#include 9 | #include "../pixel.hpp" 10 | 11 | int main(void) { 12 | const uint32_t num_pixels = 384; 13 | PixelBone_Pixel *const strip = new PixelBone_Pixel(num_pixels); 14 | while (1) { 15 | for (uint32_t p = 0; p < num_pixels; p++) { 16 | strip->clear(); 17 | strip->setPixelColor(p, PixelBone_Pixel::Color(128, 128, 128)); 18 | strip->show(); 19 | } 20 | } 21 | 22 | delete strip; 23 | return EXIT_SUCCESS; 24 | } 25 | -------------------------------------------------------------------------------- /examples/tile-test.cpp: -------------------------------------------------------------------------------- 1 | #include "../gfx.hpp" 2 | #include "../matrix.hpp" 3 | 4 | // MATRIX DECLARATION: 5 | // Parameter 1 = width of NeoPixel matrix 6 | // Parameter 2 = height of matrix 7 | // Parameter 3 = number of matrices arranged horizontally 8 | // Parameter 4 = number of matrices arranged vertically 9 | // Parameter 5 = matrix layout flags, add together as needed: 10 | // MATRIX_TOP, MATRIX_BOTTOM, MATRIX_LEFT, MATRIX_RIGHT: 11 | // Position of the FIRST LED in the matrix; pick two, e.g. 12 | // MATRIX_TOP + MATRIX_LEFT for the top-left corner. 13 | // MATRIX_ROWS, MATRIX_COLUMNS: LEDs are arranged in horizontal 14 | // rows or in vertical columns, respectively; pick one or the other. 15 | // MATRIX_PROGRESSIVE, MATRIX_ZIGZAG: all rows/columns proceed 16 | // in the same order, or alternate lines reverse direction; pick one. 17 | // TILE_TOP, TILE_BOTTOM, TILE_LEFT, TILE_RIGHT: 18 | // Position of the FIRST MATRIX (tile) in the OVERALL DISPLAY; pick 19 | // two, e.g. TILE_TOP + TILE_LEFT for the top-left corner. 20 | // TILE_ROWS, TILE_COLUMNS: the matrices in the OVERALL DISPLAY 21 | // are arranged in horizontal rows or in vertical columns, respectively; 22 | // pick one or the other. 23 | // TILE_PROGRESSIVE, TILE_ZIGZAG: the ROWS/COLUMS OF MATRICES 24 | // (tiles) in the OVERALL DISPLAY proceed in the same order for every 25 | // line, or alternate lines reverse direction; pick one. When using 26 | // zig-zag order, the orientation of the matrices in alternate rows 27 | // will be rotated 180 degrees (this is normal -- simplifies wiring). 28 | // See example below for these values in action. 29 | 30 | int main() { 31 | PixelBone_Matrix matrix(16,8,2,1, 32 | TILE_TOP + TILE_LEFT + TILE_ROWS + TILE_PROGRESSIVE + 33 | MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS + MATRIX_ZIGZAG); 34 | 35 | matrix.setTextWrap(false); 36 | matrix.setTextColor(PixelBone_Pixel::Color(128, 128, 128)); 37 | 38 | int x = 0; 39 | while (1) { 40 | matrix.fillScreen(0); 41 | matrix.setCursor(x, 0); 42 | matrix.print("Howdy"); 43 | 44 | if (--x < -36) 45 | x = matrix.width(); 46 | 47 | matrix.show(); 48 | usleep(100000); 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /gamma.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAMMA_H_ 2 | #define _GAMMA_H_ 3 | #include 4 | 5 | #ifndef PROGMEM 6 | #define PROGMEM 7 | #endif 8 | 9 | static const uint8_t PROGMEM 10 | gamma5[] = { 11 | 0x00,0x01,0x02,0x03,0x05,0x07,0x09,0x0b, 12 | 0x0e,0x11,0x14,0x18,0x1d,0x22,0x28,0x2e, 13 | 0x36,0x3d,0x46,0x4f,0x59,0x64,0x6f,0x7c, 14 | 0x89,0x97,0xa6,0xb6,0xc7,0xd9,0xeb,0xff }, 15 | gamma6[] = { 16 | 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x08, 17 | 0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x12,0x13, 18 | 0x15,0x17,0x19,0x1b,0x1d,0x20,0x22,0x25, 19 | 0x27,0x2a,0x2d,0x30,0x33,0x37,0x3a,0x3e, 20 | 0x41,0x45,0x49,0x4d,0x52,0x56,0x5b,0x5f, 21 | 0x64,0x69,0x6e,0x74,0x79,0x7f,0x85,0x8b, 22 | 0x91,0x97,0x9d,0xa4,0xab,0xb2,0xb9,0xc0, 23 | 0xc7,0xcf,0xd6,0xde,0xe6,0xee,0xf7,0xff }; 24 | 25 | #endif // _GAMMA_H_ 26 | -------------------------------------------------------------------------------- /gfx.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | This is the core graphics library for all our displays, providing a common 4 | set of graphics primitives (points, lines, circles, etc.). It needs to be 5 | paired with a hardware-specific library for each display device we carry 6 | (to handle the lower-level functions). 7 | 8 | Adafruit invests time and resources providing this open source code, please 9 | support Adafruit & open-source hardware by purchasing products from Adafruit! 10 | 11 | Copyright (c) 2013 Adafruit Industries 12 | Copyrigth (c) 2014 Katherine Whitlock 13 | All rights reserved. 14 | 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions are met: 17 | 18 | - Redistributions of source code must retain the above copyright notice, 19 | this list of conditions and the following disclaimer. 20 | - Redistributions in binary form must reproduce the above copyright notice, 21 | this list of conditions and the following disclaimer in the documentation 22 | and/or other materials provided with the distribution. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 28 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #include "gfx.hpp" 38 | #include 39 | #include "glcdfont.c" 40 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 41 | 42 | PixelBone_GFX::PixelBone_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) { 43 | _width = WIDTH; 44 | _height = HEIGHT; 45 | rotation = 0; 46 | cursor_y = cursor_x = 0; 47 | textsize = 1; 48 | textcolor = textbgcolor = 0xFFFFFFFF; 49 | wrap = true; 50 | } 51 | 52 | // Draw a circle outline 53 | void PixelBone_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, 54 | uint32_t color) { 55 | int16_t f = 1 - r; 56 | int16_t ddF_x = 1; 57 | int16_t ddF_y = -2 * r; 58 | int16_t x = 0; 59 | int16_t y = r; 60 | 61 | drawPixel(x0, y0 + r, color); 62 | drawPixel(x0, y0 - r, color); 63 | drawPixel(x0 + r, y0, color); 64 | drawPixel(x0 - r, y0, color); 65 | 66 | while (x < y) { 67 | if (f >= 0) { 68 | y--; 69 | ddF_y += 2; 70 | f += ddF_y; 71 | } 72 | x++; 73 | ddF_x += 2; 74 | f += ddF_x; 75 | 76 | drawPixel(x0 + x, y0 + y, color); 77 | drawPixel(x0 - x, y0 + y, color); 78 | drawPixel(x0 + x, y0 - y, color); 79 | drawPixel(x0 - x, y0 - y, color); 80 | drawPixel(x0 + y, y0 + x, color); 81 | drawPixel(x0 - y, y0 + x, color); 82 | drawPixel(x0 + y, y0 - x, color); 83 | drawPixel(x0 - y, y0 - x, color); 84 | } 85 | } 86 | 87 | void PixelBone_GFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, 88 | uint8_t cornername, uint32_t color) { 89 | int16_t f = 1 - r; 90 | int16_t ddF_x = 1; 91 | int16_t ddF_y = -2 * r; 92 | int16_t x = 0; 93 | int16_t y = r; 94 | 95 | while (x < y) { 96 | if (f >= 0) { 97 | y--; 98 | ddF_y += 2; 99 | f += ddF_y; 100 | } 101 | x++; 102 | ddF_x += 2; 103 | f += ddF_x; 104 | if (cornername & 0x4) { 105 | drawPixel(x0 + x, y0 + y, color); 106 | drawPixel(x0 + y, y0 + x, color); 107 | } 108 | if (cornername & 0x2) { 109 | drawPixel(x0 + x, y0 - y, color); 110 | drawPixel(x0 + y, y0 - x, color); 111 | } 112 | if (cornername & 0x8) { 113 | drawPixel(x0 - y, y0 + x, color); 114 | drawPixel(x0 - x, y0 + y, color); 115 | } 116 | if (cornername & 0x1) { 117 | drawPixel(x0 - y, y0 - x, color); 118 | drawPixel(x0 - x, y0 - y, color); 119 | } 120 | } 121 | } 122 | 123 | void PixelBone_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, 124 | uint32_t color) { 125 | drawFastVLine(x0, y0 - r, 2 * r + 1, color); 126 | fillCircleHelper(x0, y0, r, 3, 0, color); 127 | } 128 | 129 | // Used to do circles and roundrects 130 | void PixelBone_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, 131 | uint8_t cornername, int16_t delta, 132 | uint32_t color) { 133 | 134 | int16_t f = 1 - r; 135 | int16_t ddF_x = 1; 136 | int16_t ddF_y = -2 * r; 137 | int16_t x = 0; 138 | int16_t y = r; 139 | 140 | while (x < y) { 141 | if (f >= 0) { 142 | y--; 143 | ddF_y += 2; 144 | f += ddF_y; 145 | } 146 | x++; 147 | ddF_x += 2; 148 | f += ddF_x; 149 | 150 | if (cornername & 0x1) { 151 | drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color); 152 | drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color); 153 | } 154 | if (cornername & 0x2) { 155 | drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color); 156 | drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color); 157 | } 158 | } 159 | } 160 | 161 | // Bresenham's algorithm - thx wikpedia 162 | void PixelBone_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 163 | uint32_t color) { 164 | int16_t steep = std::abs(y1 - y0) > std::abs(x1 - x0); 165 | if (steep) { 166 | swap(x0, y0); 167 | swap(x1, y1); 168 | } 169 | 170 | if (x0 > x1) { 171 | swap(x0, x1); 172 | swap(y0, y1); 173 | } 174 | 175 | int16_t dx, dy; 176 | dx = x1 - x0; 177 | dy = std::abs(y1 - y0); 178 | 179 | int16_t err = dx / 2; 180 | int16_t ystep; 181 | 182 | if (y0 < y1) { 183 | ystep = 1; 184 | } else { 185 | ystep = -1; 186 | } 187 | 188 | for (; x0 <= x1; x0++) { 189 | if (steep) { 190 | drawPixel(y0, x0, color); 191 | } else { 192 | drawPixel(x0, y0, color); 193 | } 194 | err -= dy; 195 | if (err < 0) { 196 | y0 += ystep; 197 | err += dx; 198 | } 199 | } 200 | } 201 | 202 | // Draw a rectangle 203 | void PixelBone_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, 204 | uint32_t color) { 205 | drawFastHLine(x, y, w, color); 206 | drawFastHLine(x, y + h - 1, w, color); 207 | drawFastVLine(x, y, h, color); 208 | drawFastVLine(x + w - 1, y, h, color); 209 | } 210 | 211 | void PixelBone_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h, 212 | uint32_t color) { 213 | // Update in subclasses if desired! 214 | drawLine(x, y, x, y + h - 1, color); 215 | } 216 | 217 | void PixelBone_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w, 218 | uint32_t color) { 219 | // Update in subclasses if desired! 220 | drawLine(x, y, x + w - 1, y, color); 221 | } 222 | 223 | void PixelBone_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 224 | uint32_t color) { 225 | // Update in subclasses if desired! 226 | for (int16_t i = x; i < x + w; i++) { 227 | drawFastVLine(i, y, h, color); 228 | } 229 | } 230 | 231 | void PixelBone_GFX::fillScreen(uint32_t color) { 232 | fillRect(0, 0, _width, _height, color); 233 | } 234 | 235 | // Draw a rounded rectangle 236 | void PixelBone_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, 237 | int16_t r, uint32_t color) { 238 | // smarter version 239 | drawFastHLine(x + r, y, w - 2 * r, color); // Top 240 | drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom 241 | drawFastVLine(x, y + r, h - 2 * r, color); // Left 242 | drawFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right 243 | // draw four corners 244 | drawCircleHelper(x + r, y + r, r, 1, color); 245 | drawCircleHelper(x + w - r - 1, y + r, r, 2, color); 246 | drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); 247 | drawCircleHelper(x + r, y + h - r - 1, r, 8, color); 248 | } 249 | 250 | // Fill a rounded rectangle 251 | void PixelBone_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, 252 | int16_t r, uint32_t color) { 253 | // smarter version 254 | fillRect(x + r, y, w - 2 * r, h, color); 255 | 256 | // draw four corners 257 | fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); 258 | fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); 259 | } 260 | 261 | // Draw a triangle 262 | void PixelBone_GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 263 | int16_t x2, int16_t y2, uint32_t color) { 264 | drawLine(x0, y0, x1, y1, color); 265 | drawLine(x1, y1, x2, y2, color); 266 | drawLine(x2, y2, x0, y0, color); 267 | } 268 | 269 | // Fill a triangle 270 | void PixelBone_GFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 271 | int16_t x2, int16_t y2, uint32_t color) { 272 | 273 | int16_t a, b, y, last; 274 | 275 | // Sort coordinates by Y order (y2 >= y1 >= y0) 276 | if (y0 > y1) { 277 | swap(y0, y1); 278 | swap(x0, x1); 279 | } 280 | if (y1 > y2) { 281 | swap(y2, y1); 282 | swap(x2, x1); 283 | } 284 | if (y0 > y1) { 285 | swap(y0, y1); 286 | swap(x0, x1); 287 | } 288 | 289 | if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing 290 | a = b = x0; 291 | if (x1 < a) 292 | a = x1; 293 | else if (x1 > b) 294 | b = x1; 295 | if (x2 < a) 296 | a = x2; 297 | else if (x2 > b) 298 | b = x2; 299 | drawFastHLine(a, y0, b - a + 1, color); 300 | return; 301 | } 302 | 303 | int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0, 304 | dx12 = x2 - x1, dy12 = y2 - y1, sa = 0, sb = 0; 305 | 306 | // For upper part of triangle, find scanline crossings for segments 307 | // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 308 | // is included here (and second loop will be skipped, avoiding a /0 309 | // error there), otherwise scanline y1 is skipped here and handled 310 | // in the second loop...which also avoids a /0 error here if y0=y1 311 | // (flat-topped triangle). 312 | if (y1 == y2) 313 | last = y1; // Include y1 scanline 314 | else 315 | last = y1 - 1; // Skip it 316 | 317 | for (y = y0; y <= last; y++) { 318 | a = x0 + sa / dy01; 319 | b = x0 + sb / dy02; 320 | sa += dx01; 321 | sb += dx02; 322 | /* longhand: 323 | a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); 324 | b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 325 | */ 326 | if (a > b) 327 | swap(a, b); 328 | drawFastHLine(a, y, b - a + 1, color); 329 | } 330 | 331 | // For lower part of triangle, find scanline crossings for segments 332 | // 0-2 and 1-2. This loop is skipped if y1=y2. 333 | sa = dx12 * (y - y1); 334 | sb = dx02 * (y - y0); 335 | for (; y <= y2; y++) { 336 | a = x1 + sa / dy12; 337 | b = x0 + sb / dy02; 338 | sa += dx12; 339 | sb += dx02; 340 | /* longhand: 341 | a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); 342 | b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 343 | */ 344 | if (a > b) 345 | swap(a, b); 346 | drawFastHLine(a, y, b - a + 1, color); 347 | } 348 | } 349 | 350 | void PixelBone_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, 351 | int16_t w, int16_t h, uint32_t color) { 352 | 353 | int16_t i, j, byteWidth = (w + 7) / 8; 354 | 355 | for (j = 0; j < h; j++) { 356 | for (i = 0; i < w; i++) { 357 | if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) { 358 | drawPixel(x + i, y + j, color); 359 | } 360 | } 361 | } 362 | } 363 | 364 | void PixelBone_GFX::print(const std::string &s) { print(s.c_str()); } 365 | 366 | void PixelBone_GFX::print(const char str[]) { write(str); } 367 | 368 | void PixelBone_GFX::write(const char *str) { 369 | while (*str) 370 | write(*str++); 371 | } 372 | 373 | /* default implementation: may be overridden */ 374 | void PixelBone_GFX::write(const uint8_t *buffer, size_t size) { 375 | while (size--) 376 | write(*buffer++); 377 | } 378 | 379 | void PixelBone_GFX::write(uint8_t c) { 380 | if (c == '\n') { 381 | cursor_y += textsize * 8; 382 | cursor_x = 0; 383 | } else if (c == '\r') { 384 | // skip em 385 | } else { 386 | drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); 387 | cursor_x += textsize * 6; 388 | if (wrap && (cursor_x > (_width - textsize * 6))) { 389 | cursor_y += textsize * 8; 390 | cursor_x = 0; 391 | } 392 | } 393 | } 394 | 395 | // Draw a character 396 | void PixelBone_GFX::drawChar(int16_t x, int16_t y, unsigned char c, 397 | uint32_t color, uint32_t bg, uint8_t size) { 398 | 399 | if ((x >= _width) || // Clip right 400 | (y >= _height) || // Clip bottom 401 | ((x + 6 * size - 1) < 0) || // Clip left 402 | ((y + 8 * size - 1) < 0)) // Clip top 403 | return; 404 | 405 | for (int8_t i = 0; i < 6; i++) { 406 | uint8_t line; 407 | if (i == 5) 408 | line = 0x0; 409 | else 410 | line = pgm_read_byte(font + (c * 5) + i); 411 | for (int8_t j = 0; j < 8; j++) { 412 | if (line & 0x1) { 413 | if (size == 1) // default size 414 | drawPixel(x + i, y + j, color); 415 | else { // big size 416 | fillRect(x + (i * size), y + (j * size), size, size, color); 417 | } 418 | } else if (bg != color) { 419 | if (size == 1) // default size 420 | drawPixel(x + i, y + j, bg); 421 | else { // big size 422 | fillRect(x + i * size, y + j * size, size, size, bg); 423 | } 424 | } 425 | line >>= 1; 426 | } 427 | } 428 | } 429 | 430 | void PixelBone_GFX::setCursor(int16_t x, int16_t y) { 431 | cursor_x = x; 432 | cursor_y = y; 433 | } 434 | 435 | void PixelBone_GFX::setTextSize(uint8_t s) { textsize = (s > 0) ? s : 1; } 436 | 437 | void PixelBone_GFX::setTextColor(uint32_t c) { 438 | // For 'transparent' background, we'll set the bg 439 | // to the same as fg instead of using a flag 440 | textcolor = textbgcolor = c; 441 | } 442 | 443 | void PixelBone_GFX::setTextColor(uint32_t c, uint32_t b) { 444 | textcolor = c; 445 | textbgcolor = b; 446 | } 447 | 448 | void PixelBone_GFX::setTextWrap(bool w) { wrap = w; } 449 | 450 | uint8_t PixelBone_GFX::getRotation(void) { return rotation; } 451 | 452 | void PixelBone_GFX::setRotation(uint8_t x) { 453 | rotation = (x & 3); 454 | switch (rotation) { 455 | case 0: 456 | case 2: 457 | _width = WIDTH; 458 | _height = HEIGHT; 459 | break; 460 | case 1: 461 | case 3: 462 | _width = HEIGHT; 463 | _height = WIDTH; 464 | break; 465 | } 466 | } 467 | 468 | // Return the size of the display (per current rotation) 469 | int16_t PixelBone_GFX::width(void) { return _width; } 470 | 471 | int16_t PixelBone_GFX::height(void) { return _height; } 472 | 473 | void PixelBone_GFX::invertDisplay(bool i) { 474 | // Do nothing, must be subclassed if supported 475 | } 476 | -------------------------------------------------------------------------------- /gfx.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #ifndef _GFX_HPP_ 3 | #define _GFX_HPP_ 4 | 5 | #include 6 | 7 | #define swap(a, b) \ 8 | { \ 9 | int16_t t = a; \ 10 | a = b; \ 11 | b = t; \ 12 | } 13 | 14 | class PixelBone_GFX { 15 | 16 | public: 17 | PixelBone_GFX(int16_t w, int16_t h); // Constructor 18 | 19 | // This MUST be defined by the subclass: 20 | virtual void drawPixel(int16_t x, int16_t y, uint32_t color) = 0; 21 | 22 | // These MAY be overridden by the subclass to provide device-specific 23 | // optimized code. Otherwise 'generic' versions are used. 24 | virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 25 | uint32_t color); 26 | virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint32_t color); 27 | virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint32_t color); 28 | virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, 29 | uint32_t color); 30 | virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 31 | uint32_t color); 32 | virtual void fillScreen(uint32_t color); 33 | virtual void invertDisplay(bool i); 34 | 35 | // These exist only with Adafruit_GFX (no subclass overrides) 36 | void drawCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color); 37 | void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, 38 | uint32_t color); 39 | void fillCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color); 40 | void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, 41 | int16_t delta, uint32_t color); 42 | void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, 43 | int16_t y2, uint32_t color); 44 | void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, 45 | int16_t y2, uint32_t color); 46 | void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, 47 | int16_t radius, uint32_t color); 48 | void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, 49 | int16_t radius, uint32_t color); 50 | void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, 51 | int16_t h, uint32_t color); 52 | void drawChar(int16_t x, int16_t y, unsigned char c, uint32_t color, 53 | uint32_t bg, uint8_t size); 54 | void setCursor(int16_t x, int16_t y); 55 | void setTextColor(uint32_t color); 56 | void setTextColor(uint32_t color, uint32_t bg); 57 | void setTextSize(uint8_t s); 58 | void setTextWrap(bool w); 59 | void setRotation(uint8_t r); 60 | 61 | void print(const std::string &s); 62 | void print(const char str[]); 63 | void write(const char *str); 64 | void write(const uint8_t *buffer, size_t size); 65 | virtual void write(uint8_t); 66 | 67 | int16_t height(void); 68 | int16_t width(void); 69 | uint8_t getRotation(void); 70 | 71 | protected: 72 | const int16_t WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes 73 | int16_t _width, _height; // Display w/h as modified by current rotation 74 | int16_t cursor_x, cursor_y; 75 | uint32_t textcolor, textbgcolor; 76 | uint8_t textsize; 77 | uint8_t rotation; 78 | bool wrap; // If set, 'wrap' text at right edge of display 79 | }; 80 | 81 | #endif // _GFX_HPP_ 82 | -------------------------------------------------------------------------------- /glcdfont.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef FONT5X7_H 3 | #define FONT5X7_H 4 | 5 | #define PROGMEM 6 | 7 | // Standard ASCII 5x7 font 8 | 9 | static const unsigned char font[] PROGMEM = { 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 11 | 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 12 | 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 13 | 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 14 | 0x18, 0x3C, 0x7E, 0x3C, 0x18, 15 | 0x1C, 0x57, 0x7D, 0x57, 0x1C, 16 | 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 17 | 0x00, 0x18, 0x3C, 0x18, 0x00, 18 | 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 19 | 0x00, 0x18, 0x24, 0x18, 0x00, 20 | 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 21 | 0x30, 0x48, 0x3A, 0x06, 0x0E, 22 | 0x26, 0x29, 0x79, 0x29, 0x26, 23 | 0x40, 0x7F, 0x05, 0x05, 0x07, 24 | 0x40, 0x7F, 0x05, 0x25, 0x3F, 25 | 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 26 | 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 27 | 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 28 | 0x14, 0x22, 0x7F, 0x22, 0x14, 29 | 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 30 | 0x06, 0x09, 0x7F, 0x01, 0x7F, 31 | 0x00, 0x66, 0x89, 0x95, 0x6A, 32 | 0x60, 0x60, 0x60, 0x60, 0x60, 33 | 0x94, 0xA2, 0xFF, 0xA2, 0x94, 34 | 0x08, 0x04, 0x7E, 0x04, 0x08, 35 | 0x10, 0x20, 0x7E, 0x20, 0x10, 36 | 0x08, 0x08, 0x2A, 0x1C, 0x08, 37 | 0x08, 0x1C, 0x2A, 0x08, 0x08, 38 | 0x1E, 0x10, 0x10, 0x10, 0x10, 39 | 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 40 | 0x30, 0x38, 0x3E, 0x38, 0x30, 41 | 0x06, 0x0E, 0x3E, 0x0E, 0x06, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x5F, 0x00, 0x00, 44 | 0x00, 0x07, 0x00, 0x07, 0x00, 45 | 0x14, 0x7F, 0x14, 0x7F, 0x14, 46 | 0x24, 0x2A, 0x7F, 0x2A, 0x12, 47 | 0x23, 0x13, 0x08, 0x64, 0x62, 48 | 0x36, 0x49, 0x56, 0x20, 0x50, 49 | 0x00, 0x08, 0x07, 0x03, 0x00, 50 | 0x00, 0x1C, 0x22, 0x41, 0x00, 51 | 0x00, 0x41, 0x22, 0x1C, 0x00, 52 | 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 53 | 0x08, 0x08, 0x3E, 0x08, 0x08, 54 | 0x00, 0x80, 0x70, 0x30, 0x00, 55 | 0x08, 0x08, 0x08, 0x08, 0x08, 56 | 0x00, 0x00, 0x60, 0x60, 0x00, 57 | 0x20, 0x10, 0x08, 0x04, 0x02, 58 | 0x3E, 0x51, 0x49, 0x45, 0x3E, 59 | 0x00, 0x42, 0x7F, 0x40, 0x00, 60 | 0x72, 0x49, 0x49, 0x49, 0x46, 61 | 0x21, 0x41, 0x49, 0x4D, 0x33, 62 | 0x18, 0x14, 0x12, 0x7F, 0x10, 63 | 0x27, 0x45, 0x45, 0x45, 0x39, 64 | 0x3C, 0x4A, 0x49, 0x49, 0x31, 65 | 0x41, 0x21, 0x11, 0x09, 0x07, 66 | 0x36, 0x49, 0x49, 0x49, 0x36, 67 | 0x46, 0x49, 0x49, 0x29, 0x1E, 68 | 0x00, 0x00, 0x14, 0x00, 0x00, 69 | 0x00, 0x40, 0x34, 0x00, 0x00, 70 | 0x00, 0x08, 0x14, 0x22, 0x41, 71 | 0x14, 0x14, 0x14, 0x14, 0x14, 72 | 0x00, 0x41, 0x22, 0x14, 0x08, 73 | 0x02, 0x01, 0x59, 0x09, 0x06, 74 | 0x3E, 0x41, 0x5D, 0x59, 0x4E, 75 | 0x7C, 0x12, 0x11, 0x12, 0x7C, 76 | 0x7F, 0x49, 0x49, 0x49, 0x36, 77 | 0x3E, 0x41, 0x41, 0x41, 0x22, 78 | 0x7F, 0x41, 0x41, 0x41, 0x3E, 79 | 0x7F, 0x49, 0x49, 0x49, 0x41, 80 | 0x7F, 0x09, 0x09, 0x09, 0x01, 81 | 0x3E, 0x41, 0x41, 0x51, 0x73, 82 | 0x7F, 0x08, 0x08, 0x08, 0x7F, 83 | 0x00, 0x41, 0x7F, 0x41, 0x00, 84 | 0x20, 0x40, 0x41, 0x3F, 0x01, 85 | 0x7F, 0x08, 0x14, 0x22, 0x41, 86 | 0x7F, 0x40, 0x40, 0x40, 0x40, 87 | 0x7F, 0x02, 0x1C, 0x02, 0x7F, 88 | 0x7F, 0x04, 0x08, 0x10, 0x7F, 89 | 0x3E, 0x41, 0x41, 0x41, 0x3E, 90 | 0x7F, 0x09, 0x09, 0x09, 0x06, 91 | 0x3E, 0x41, 0x51, 0x21, 0x5E, 92 | 0x7F, 0x09, 0x19, 0x29, 0x46, 93 | 0x26, 0x49, 0x49, 0x49, 0x32, 94 | 0x03, 0x01, 0x7F, 0x01, 0x03, 95 | 0x3F, 0x40, 0x40, 0x40, 0x3F, 96 | 0x1F, 0x20, 0x40, 0x20, 0x1F, 97 | 0x3F, 0x40, 0x38, 0x40, 0x3F, 98 | 0x63, 0x14, 0x08, 0x14, 0x63, 99 | 0x03, 0x04, 0x78, 0x04, 0x03, 100 | 0x61, 0x59, 0x49, 0x4D, 0x43, 101 | 0x00, 0x7F, 0x41, 0x41, 0x41, 102 | 0x02, 0x04, 0x08, 0x10, 0x20, 103 | 0x00, 0x41, 0x41, 0x41, 0x7F, 104 | 0x04, 0x02, 0x01, 0x02, 0x04, 105 | 0x40, 0x40, 0x40, 0x40, 0x40, 106 | 0x00, 0x03, 0x07, 0x08, 0x00, 107 | 0x20, 0x54, 0x54, 0x78, 0x40, 108 | 0x7F, 0x28, 0x44, 0x44, 0x38, 109 | 0x38, 0x44, 0x44, 0x44, 0x28, 110 | 0x38, 0x44, 0x44, 0x28, 0x7F, 111 | 0x38, 0x54, 0x54, 0x54, 0x18, 112 | 0x00, 0x08, 0x7E, 0x09, 0x02, 113 | 0x18, 0xA4, 0xA4, 0x9C, 0x78, 114 | 0x7F, 0x08, 0x04, 0x04, 0x78, 115 | 0x00, 0x44, 0x7D, 0x40, 0x00, 116 | 0x20, 0x40, 0x40, 0x3D, 0x00, 117 | 0x7F, 0x10, 0x28, 0x44, 0x00, 118 | 0x00, 0x41, 0x7F, 0x40, 0x00, 119 | 0x7C, 0x04, 0x78, 0x04, 0x78, 120 | 0x7C, 0x08, 0x04, 0x04, 0x78, 121 | 0x38, 0x44, 0x44, 0x44, 0x38, 122 | 0xFC, 0x18, 0x24, 0x24, 0x18, 123 | 0x18, 0x24, 0x24, 0x18, 0xFC, 124 | 0x7C, 0x08, 0x04, 0x04, 0x08, 125 | 0x48, 0x54, 0x54, 0x54, 0x24, 126 | 0x04, 0x04, 0x3F, 0x44, 0x24, 127 | 0x3C, 0x40, 0x40, 0x20, 0x7C, 128 | 0x1C, 0x20, 0x40, 0x20, 0x1C, 129 | 0x3C, 0x40, 0x30, 0x40, 0x3C, 130 | 0x44, 0x28, 0x10, 0x28, 0x44, 131 | 0x4C, 0x90, 0x90, 0x90, 0x7C, 132 | 0x44, 0x64, 0x54, 0x4C, 0x44, 133 | 0x00, 0x08, 0x36, 0x41, 0x00, 134 | 0x00, 0x00, 0x77, 0x00, 0x00, 135 | 0x00, 0x41, 0x36, 0x08, 0x00, 136 | 0x02, 0x01, 0x02, 0x04, 0x02, 137 | 0x3C, 0x26, 0x23, 0x26, 0x3C, 138 | 0x1E, 0xA1, 0xA1, 0x61, 0x12, 139 | 0x3A, 0x40, 0x40, 0x20, 0x7A, 140 | 0x38, 0x54, 0x54, 0x55, 0x59, 141 | 0x21, 0x55, 0x55, 0x79, 0x41, 142 | 0x21, 0x54, 0x54, 0x78, 0x41, 143 | 0x21, 0x55, 0x54, 0x78, 0x40, 144 | 0x20, 0x54, 0x55, 0x79, 0x40, 145 | 0x0C, 0x1E, 0x52, 0x72, 0x12, 146 | 0x39, 0x55, 0x55, 0x55, 0x59, 147 | 0x39, 0x54, 0x54, 0x54, 0x59, 148 | 0x39, 0x55, 0x54, 0x54, 0x58, 149 | 0x00, 0x00, 0x45, 0x7C, 0x41, 150 | 0x00, 0x02, 0x45, 0x7D, 0x42, 151 | 0x00, 0x01, 0x45, 0x7C, 0x40, 152 | 0xF0, 0x29, 0x24, 0x29, 0xF0, 153 | 0xF0, 0x28, 0x25, 0x28, 0xF0, 154 | 0x7C, 0x54, 0x55, 0x45, 0x00, 155 | 0x20, 0x54, 0x54, 0x7C, 0x54, 156 | 0x7C, 0x0A, 0x09, 0x7F, 0x49, 157 | 0x32, 0x49, 0x49, 0x49, 0x32, 158 | 0x32, 0x48, 0x48, 0x48, 0x32, 159 | 0x32, 0x4A, 0x48, 0x48, 0x30, 160 | 0x3A, 0x41, 0x41, 0x21, 0x7A, 161 | 0x3A, 0x42, 0x40, 0x20, 0x78, 162 | 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 163 | 0x39, 0x44, 0x44, 0x44, 0x39, 164 | 0x3D, 0x40, 0x40, 0x40, 0x3D, 165 | 0x3C, 0x24, 0xFF, 0x24, 0x24, 166 | 0x48, 0x7E, 0x49, 0x43, 0x66, 167 | 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 168 | 0xFF, 0x09, 0x29, 0xF6, 0x20, 169 | 0xC0, 0x88, 0x7E, 0x09, 0x03, 170 | 0x20, 0x54, 0x54, 0x79, 0x41, 171 | 0x00, 0x00, 0x44, 0x7D, 0x41, 172 | 0x30, 0x48, 0x48, 0x4A, 0x32, 173 | 0x38, 0x40, 0x40, 0x22, 0x7A, 174 | 0x00, 0x7A, 0x0A, 0x0A, 0x72, 175 | 0x7D, 0x0D, 0x19, 0x31, 0x7D, 176 | 0x26, 0x29, 0x29, 0x2F, 0x28, 177 | 0x26, 0x29, 0x29, 0x29, 0x26, 178 | 0x30, 0x48, 0x4D, 0x40, 0x20, 179 | 0x38, 0x08, 0x08, 0x08, 0x08, 180 | 0x08, 0x08, 0x08, 0x08, 0x38, 181 | 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 182 | 0x2F, 0x10, 0x28, 0x34, 0xFA, 183 | 0x00, 0x00, 0x7B, 0x00, 0x00, 184 | 0x08, 0x14, 0x2A, 0x14, 0x22, 185 | 0x22, 0x14, 0x2A, 0x14, 0x08, 186 | 0xAA, 0x00, 0x55, 0x00, 0xAA, 187 | 0xAA, 0x55, 0xAA, 0x55, 0xAA, 188 | 0x00, 0x00, 0x00, 0xFF, 0x00, 189 | 0x10, 0x10, 0x10, 0xFF, 0x00, 190 | 0x14, 0x14, 0x14, 0xFF, 0x00, 191 | 0x10, 0x10, 0xFF, 0x00, 0xFF, 192 | 0x10, 0x10, 0xF0, 0x10, 0xF0, 193 | 0x14, 0x14, 0x14, 0xFC, 0x00, 194 | 0x14, 0x14, 0xF7, 0x00, 0xFF, 195 | 0x00, 0x00, 0xFF, 0x00, 0xFF, 196 | 0x14, 0x14, 0xF4, 0x04, 0xFC, 197 | 0x14, 0x14, 0x17, 0x10, 0x1F, 198 | 0x10, 0x10, 0x1F, 0x10, 0x1F, 199 | 0x14, 0x14, 0x14, 0x1F, 0x00, 200 | 0x10, 0x10, 0x10, 0xF0, 0x00, 201 | 0x00, 0x00, 0x00, 0x1F, 0x10, 202 | 0x10, 0x10, 0x10, 0x1F, 0x10, 203 | 0x10, 0x10, 0x10, 0xF0, 0x10, 204 | 0x00, 0x00, 0x00, 0xFF, 0x10, 205 | 0x10, 0x10, 0x10, 0x10, 0x10, 206 | 0x10, 0x10, 0x10, 0xFF, 0x10, 207 | 0x00, 0x00, 0x00, 0xFF, 0x14, 208 | 0x00, 0x00, 0xFF, 0x00, 0xFF, 209 | 0x00, 0x00, 0x1F, 0x10, 0x17, 210 | 0x00, 0x00, 0xFC, 0x04, 0xF4, 211 | 0x14, 0x14, 0x17, 0x10, 0x17, 212 | 0x14, 0x14, 0xF4, 0x04, 0xF4, 213 | 0x00, 0x00, 0xFF, 0x00, 0xF7, 214 | 0x14, 0x14, 0x14, 0x14, 0x14, 215 | 0x14, 0x14, 0xF7, 0x00, 0xF7, 216 | 0x14, 0x14, 0x14, 0x17, 0x14, 217 | 0x10, 0x10, 0x1F, 0x10, 0x1F, 218 | 0x14, 0x14, 0x14, 0xF4, 0x14, 219 | 0x10, 0x10, 0xF0, 0x10, 0xF0, 220 | 0x00, 0x00, 0x1F, 0x10, 0x1F, 221 | 0x00, 0x00, 0x00, 0x1F, 0x14, 222 | 0x00, 0x00, 0x00, 0xFC, 0x14, 223 | 0x00, 0x00, 0xF0, 0x10, 0xF0, 224 | 0x10, 0x10, 0xFF, 0x10, 0xFF, 225 | 0x14, 0x14, 0x14, 0xFF, 0x14, 226 | 0x10, 0x10, 0x10, 0x1F, 0x00, 227 | 0x00, 0x00, 0x00, 0xF0, 0x10, 228 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 229 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 230 | 0xFF, 0xFF, 0xFF, 0x00, 0x00, 231 | 0x00, 0x00, 0x00, 0xFF, 0xFF, 232 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 233 | 0x38, 0x44, 0x44, 0x38, 0x44, 234 | 0x7C, 0x2A, 0x2A, 0x3E, 0x14, 235 | 0x7E, 0x02, 0x02, 0x06, 0x06, 236 | 0x02, 0x7E, 0x02, 0x7E, 0x02, 237 | 0x63, 0x55, 0x49, 0x41, 0x63, 238 | 0x38, 0x44, 0x44, 0x3C, 0x04, 239 | 0x40, 0x7E, 0x20, 0x1E, 0x20, 240 | 0x06, 0x02, 0x7E, 0x02, 0x02, 241 | 0x99, 0xA5, 0xE7, 0xA5, 0x99, 242 | 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 243 | 0x4C, 0x72, 0x01, 0x72, 0x4C, 244 | 0x30, 0x4A, 0x4D, 0x4D, 0x30, 245 | 0x30, 0x48, 0x78, 0x48, 0x30, 246 | 0xBC, 0x62, 0x5A, 0x46, 0x3D, 247 | 0x3E, 0x49, 0x49, 0x49, 0x00, 248 | 0x7E, 0x01, 0x01, 0x01, 0x7E, 249 | 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 250 | 0x44, 0x44, 0x5F, 0x44, 0x44, 251 | 0x40, 0x51, 0x4A, 0x44, 0x40, 252 | 0x40, 0x44, 0x4A, 0x51, 0x40, 253 | 0x00, 0x00, 0xFF, 0x01, 0x03, 254 | 0xE0, 0x80, 0xFF, 0x00, 0x00, 255 | 0x08, 0x08, 0x6B, 0x6B, 0x08, 256 | 0x36, 0x12, 0x36, 0x24, 0x36, 257 | 0x06, 0x0F, 0x09, 0x0F, 0x06, 258 | 0x00, 0x00, 0x18, 0x18, 0x00, 259 | 0x00, 0x00, 0x10, 0x10, 0x00, 260 | 0x30, 0x40, 0xFF, 0x01, 0x01, 261 | 0x00, 0x1F, 0x01, 0x01, 0x1E, 262 | 0x00, 0x19, 0x1D, 0x17, 0x12, 263 | 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 264 | 0x00, 0x00, 0x00, 0x00, 0x00 265 | }; 266 | #endif // FONT5X7_H -------------------------------------------------------------------------------- /matrix.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | Arduino library to control single and tiled matrices of WS2811- and 3 | WS2812-based RGB LED devices such as the Adafruit NeoPixel Shield or 4 | displays assembled from NeoPixel strips, making them compatible with 5 | the PixelBone_GFX graphics library. Requires both the Adafruit_NeoPixel 6 | and PixelBone_GFX libraries. 7 | 8 | Written by Phil Burgess / Paint Your Dragon for Adafruit Industries. 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing products 12 | from Adafruit! 13 | 14 | ------------------------------------------------------------------------- 15 | This file is part of the Adafruit NeoMatrix library. 16 | 17 | NeoMatrix is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU Lesser General Public License as 19 | published by the Free Software Foundation, either version 3 of 20 | the License, or (at your option) any later version. 21 | 22 | NeoMatrix is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU Lesser General Public License for more details. 26 | 27 | You should have received a copy of the GNU Lesser General Public 28 | License along with NeoMatrix. If not, see 29 | . 30 | -------------------------------------------------------------------------*/ 31 | 32 | #include "matrix.hpp" 33 | #include "gamma.h" 34 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 35 | 36 | // Constructor for single matrix: 37 | PixelBone_Matrix::PixelBone_Matrix(int w, int h, uint8_t matrixType) 38 | : PixelBone_GFX(w, h), PixelBone_Pixel(w * h), type(matrixType), 39 | matrixWidth(w), matrixHeight(h), tilesX(0), tilesY(0), remapFn(NULL) {} 40 | 41 | // Constructor for tiled matrices: 42 | PixelBone_Matrix::PixelBone_Matrix(uint8_t mW, uint8_t mH, uint8_t tX, 43 | uint8_t tY, uint8_t matrixType) 44 | : PixelBone_GFX(mW * tX, mH * tY), PixelBone_Pixel(mW * mH * tX * tY), 45 | type(matrixType), matrixWidth(mW), matrixHeight(mH), tilesX(tX), 46 | tilesY(tY), remapFn(NULL) {} 47 | 48 | 49 | int PixelBone_Matrix::getOffset(int16_t x, int16_t y) { 50 | 51 | if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) 52 | return -1; 53 | 54 | int16_t t; 55 | switch (rotation) { 56 | case 1: 57 | t = x; 58 | x = WIDTH - 1 - y; 59 | y = t; 60 | break; 61 | case 2: 62 | x = WIDTH - 1 - x; 63 | y = HEIGHT - 1 - y; 64 | break; 65 | case 3: 66 | t = x; 67 | x = y; 68 | y = HEIGHT - 1 - t; 69 | break; 70 | } 71 | 72 | int tileOffset = 0, pixelOffset; 73 | 74 | if (remapFn) { // Custom X/Y remapping function 75 | pixelOffset = (*remapFn)(x, y); 76 | } else { // Standard single matrix or tiled matrices 77 | 78 | uint8_t corner = type & MATRIX_CORNER; 79 | uint16_t minor, major, majorScale; 80 | 81 | if (tilesX) { // Tiled display, multiple matrices 82 | uint16_t tile; 83 | 84 | minor = x / matrixWidth; // Tile # X/Y; presume row major to 85 | major = y / matrixHeight, // start (will swap later if needed) 86 | x = x - (minor * matrixWidth); // Pixel X/Y within tile 87 | y = y - (major * matrixHeight); // (-* is less math than modulo) 88 | 89 | // Determine corner of entry, flip axes if needed 90 | if (type & TILE_RIGHT) 91 | minor = tilesX - 1 - minor; 92 | if (type & TILE_BOTTOM) 93 | major = tilesY - 1 - major; 94 | 95 | // Determine actual major axis of tiling 96 | if ((type & TILE_AXIS) == TILE_ROWS) { 97 | majorScale = tilesX; 98 | } else { 99 | swap(major, minor); 100 | majorScale = tilesY; 101 | } 102 | 103 | // Determine tile number 104 | if ((type & TILE_SEQUENCE) == TILE_PROGRESSIVE) { 105 | // All tiles in same order 106 | tile = major * majorScale + minor; 107 | } else { 108 | // Zigzag; alternate rows change direction. On these rows, 109 | // this also flips the starting corner of the matrix for the 110 | // pixel math later. 111 | if (major & 1) { 112 | corner ^= MATRIX_CORNER; 113 | tile = (major + 1) * majorScale - 1 - minor; 114 | } else { 115 | tile = major * majorScale + minor; 116 | } 117 | } 118 | 119 | // Index of first pixel in tile 120 | tileOffset = tile * matrixWidth * matrixHeight; 121 | 122 | } // else no tiling (handle as single tile) 123 | 124 | // Find pixel number within tile 125 | minor = x; // Presume row major to start (will swap later if needed) 126 | major = y; 127 | 128 | // Determine corner of entry, flip axes if needed 129 | if (corner & MATRIX_RIGHT) 130 | minor = matrixWidth - 1 - minor; 131 | if (corner & MATRIX_BOTTOM) 132 | major = matrixHeight - 1 - major; 133 | 134 | // Determine actual major axis of matrix 135 | if ((type & MATRIX_AXIS) == MATRIX_ROWS) { 136 | majorScale = matrixWidth; 137 | } else { 138 | swap(major, minor); 139 | majorScale = matrixHeight; 140 | } 141 | 142 | // Determine pixel number within tile/matrix 143 | if ((type & MATRIX_SEQUENCE) == MATRIX_PROGRESSIVE) { 144 | // All lines in same order 145 | pixelOffset = major * majorScale + minor; 146 | } else { 147 | // Zigzag; alternate rows change direction. 148 | if (major & 1) 149 | pixelOffset = (major + 1) * majorScale - 1 - minor; 150 | else 151 | pixelOffset = major * majorScale + minor; 152 | } 153 | } 154 | int offset = (tileOffset + pixelOffset); 155 | return offset; 156 | } 157 | 158 | void PixelBone_Matrix::drawPixel(int16_t x, int16_t y, uint32_t color) { 159 | setPixelColor(getOffset(x,y), color); 160 | } 161 | 162 | uint16_t PixelBone_Matrix::getPixelColor(int16_t x, int16_t y) { 163 | // uint32_t color = expandColor(PixelBone_Pixel::getPixelColor(getOffset(x,y))); 164 | // uint8_t r = (uint8_t) (color & 0xFF); // first 8 bits 165 | // uint8_t g = (uint8_t) ((color >> 8) & 0xFF); // second 8 bits 166 | // uint8_t b = (uint8_t) ((color >> 16) & 0xFF); // third 8 bits 167 | 168 | pixel_t *const p = PixelBone_Pixel::getPixel(getOffset(x,y)); 169 | // printf("Red color: 0x%x\n", p->r); 170 | // printf("Green color: 0x%x\n", p->g); 171 | // printf("Blue color: 0x%x\n", p->b); 172 | 173 | return PixelBone_Matrix::Color(p->r, p->g, p->b); 174 | } 175 | 176 | void PixelBone_Matrix::fillScreen(uint32_t color) { 177 | uint32_t n = numPixels(); 178 | 179 | for (uint32_t i = 0; i < n; i++) 180 | setPixelColor(i, color); 181 | } 182 | 183 | void PixelBone_Matrix::setRemapFunction(uint16_t (*fn)(uint16_t, uint16_t)) { 184 | remapFn = fn; 185 | } 186 | -------------------------------------------------------------------------------- /matrix.hpp: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------------- 3 | This file is part of the Adafruit NeoMatrix library. 4 | 5 | NeoMatrix is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, either version 3 of 8 | the License, or (at your option) any later version. 9 | 10 | NeoMatrix is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with NeoMatrix. If not, see 17 | . 18 | --------------------------------------------------------------------*/ 19 | 20 | #ifndef _MATRIX_HPP_ 21 | #define _MATRIX_HPP_ 22 | 23 | #include "gfx.hpp" 24 | #include "pixel.hpp" 25 | 26 | // Matrix layout information is passed in the 'matrixType' parameter for 27 | // each constructor (the parameter immediately following is the LED type 28 | // from NeoPixel.h). 29 | 30 | // These define the layout for a single 'unified' matrix (e.g. one made 31 | // from NeoPixel strips, or a single NeoPixel shield), or for the pixels 32 | // within each matrix of a tiled display (e.g. multiple NeoPixel shields). 33 | 34 | #define MATRIX_TOP 0x00 // Pixel 0 is at top of matrix 35 | #define MATRIX_BOTTOM 0x01 // Pixel 0 is at bottom of matrix 36 | #define MATRIX_LEFT 0x00 // Pixel 0 is at left of matrix 37 | #define MATRIX_RIGHT 0x02 // Pixel 0 is at right of matrix 38 | #define MATRIX_CORNER 0x03 // Bitmask for pixel 0 matrix corner 39 | #define MATRIX_ROWS 0x00 // Matrix is row major (horizontal) 40 | #define MATRIX_COLUMNS 0x04 // Matrix is column major (vertical) 41 | #define MATRIX_AXIS 0x04 // Bitmask for row/column layout 42 | #define MATRIX_PROGRESSIVE 0x00 // Same pixel order across each line 43 | #define MATRIX_ZIGZAG 0x08 // Pixel order reverses between lines 44 | #define MATRIX_SEQUENCE 0x08 // Bitmask for pixel line order 45 | 46 | // These apply only to tiled displays (multiple matrices): 47 | 48 | #define TILE_TOP 0x00 // First tile is at top of matrix 49 | #define TILE_BOTTOM 0x10 // First tile is at bottom of matrix 50 | #define TILE_LEFT 0x00 // First tile is at left of matrix 51 | #define TILE_RIGHT 0x20 // First tile is at right of matrix 52 | #define TILE_CORNER 0x30 // Bitmask for first tile corner 53 | #define TILE_ROWS 0x00 // Tiles ordered in rows 54 | #define TILE_COLUMNS 0x40 // Tiles ordered in columns 55 | #define TILE_AXIS 0x40 // Bitmask for tile H/V orientation 56 | #define TILE_PROGRESSIVE 0x00 // Same tile order across each line 57 | #define TILE_ZIGZAG 0x80 // Tile order reverses between lines 58 | #define TILE_SEQUENCE 0x80 // Bitmask for tile line order 59 | 60 | class PixelBone_Matrix : public PixelBone_GFX, public PixelBone_Pixel { 61 | 62 | public: 63 | // Constructor for single matrix: 64 | PixelBone_Matrix(int w, int h, 65 | uint8_t matrixType = MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS); 66 | 67 | // Constructor for tiled matrices: 68 | PixelBone_Matrix(uint8_t matrixW, uint8_t matrixH, uint8_t tX, uint8_t tY, 69 | uint8_t matrixType = MATRIX_TOP + MATRIX_LEFT + MATRIX_ROWS + 70 | TILE_TOP + TILE_LEFT + TILE_ROWS); 71 | 72 | void drawPixel(int16_t x, int16_t y, uint32_t color); 73 | uint16_t getPixelColor(int16_t x, int16_t y); 74 | void fillScreen(uint32_t color); 75 | void setRemapFunction(uint16_t (*fn)(uint16_t, uint16_t)); 76 | 77 | 78 | private: 79 | const uint8_t type; 80 | const uint8_t matrixWidth, matrixHeight, tilesX, tilesY; 81 | uint16_t (*remapFn)(uint16_t x, uint16_t y); 82 | int getOffset(int16_t x, int16_t y); 83 | }; 84 | 85 | #endif // _MATRIX_HPP_ 86 | -------------------------------------------------------------------------------- /matrix.i: -------------------------------------------------------------------------------- 1 | %module matrix 2 | %{ 3 | /* Includes the header in the wrapper code */ 4 | #include "matrix.hpp" 5 | %} 6 | 7 | #define __attribute__(x) 8 | /* Parse the header file to generate wrappers */ 9 | %include "stdint.i" 10 | %include "gfx.hpp" 11 | %include "pixel.hpp" 12 | %include "matrix.hpp" 13 | -------------------------------------------------------------------------------- /network/bbb-network-setup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | DIR="`dirname $0`" 3 | cd "$DIR" 4 | 5 | route add default gw 192.168.7.1 6 | echo 'nameserver 8.8.8.8' > /etc/resolv.conf 7 | echo >&2 "setting date" 8 | ntpdate -s pool.ntp.org 9 | date 10 | -------------------------------------------------------------------------------- /network/ledscape.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=LEDScape UDP Receiver 3 | 4 | [Service] 5 | WorkingDirectory=/home/root/LEDscape/ 6 | ExecStart=/home/root/LEDscape/run-ledscape 7 | KillMode=process 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | -------------------------------------------------------------------------------- /network/opc-rx.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * OPC image packet receiver. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "util.h" 20 | #include "ledscape.h" 21 | 22 | typedef struct { 23 | uint8_t channel; 24 | uint8_t command; 25 | uint8_t len_hi; 26 | uint8_t len_lo; 27 | } opc_cmd_t; 28 | 29 | static int tcp_socket(const int port) { 30 | const int sock = socket(AF_INET, SOCK_STREAM, 0); 31 | struct sockaddr_in addr = { .sin_family = AF_INET, 32 | .sin_port = htons(port), 33 | .sin_addr.s_addr = INADDR_ANY, }; 34 | 35 | if (sock < 0) 36 | return -1; 37 | if (bind(sock, (const struct sockaddr *)&addr, sizeof(addr)) < 0) 38 | return -1; 39 | if (listen(sock, 5) == -1) 40 | return -1; 41 | 42 | return sock; 43 | } 44 | 45 | int main(int argc, char **argv) { 46 | int port = 7890; 47 | int led_count = 256; 48 | 49 | extern char *optarg; 50 | int opt; 51 | while ((opt = getopt(argc, argv, "p:c:d:")) != -1) { 52 | switch (opt) { 53 | case 'p': 54 | port = atoi(optarg); 55 | break; 56 | case 'c': 57 | led_count = atoi(optarg); 58 | break; 59 | case 'd': { 60 | int width = 0, height = 0; 61 | 62 | if (sscanf(optarg, "%dx%d", &width, &height) == 2) { 63 | led_count = width * height; 64 | } else { 65 | printf("Invalid argument for -d; expected NxN; actual: %s", optarg); 66 | exit(EXIT_FAILURE); 67 | } 68 | } break; 69 | default: 70 | fprintf(stderr, 71 | "Usage: %s [-p ] [-c | -d x]\n", 72 | argv[0]); 73 | exit(EXIT_FAILURE); 74 | } 75 | } 76 | 77 | const int sock = tcp_socket(port); 78 | if (sock < 0) 79 | die("socket port %d failed: %s\n", port, strerror(errno)); 80 | 81 | const size_t image_size = led_count * 3; 82 | 83 | // largest possible UDP packet 84 | uint8_t buf[65536]; 85 | if (sizeof(buf) < image_size + 1) 86 | die("%u too large for UDP\n", image_size); 87 | 88 | fprintf(stderr, "OpenPixelControl LEDScape Receiver started on TCP port %d " 89 | "for %d pixels.\n", 90 | port, led_count); 91 | fprintf(stderr, "NOTE: This is a preliminary implementation of OPC for " 92 | "LEDscape and does not support multiple clients or updating " 93 | "multiple channels.\n"); 94 | fprintf(stderr, "Use udp-rx in cases where those features are needed.\n"); 95 | 96 | ledscape_t *const leds = ledscape_init(led_count); 97 | 98 | const unsigned report_interval = 10; 99 | unsigned last_report = 0; 100 | unsigned long delta_sum = 0; 101 | unsigned frames = 0; 102 | 103 | uint32_t *const fb = calloc(image_size, 4); 104 | 105 | int fd; 106 | while ((fd = accept(sock, NULL, NULL)) >= 0) { 107 | while (1) { 108 | opc_cmd_t cmd; 109 | ssize_t rlen = read(fd, &cmd, sizeof(cmd)); 110 | if (rlen < 0) 111 | die("recv failed: %s\n", strerror(errno)); 112 | if (rlen == 0) { 113 | close(fd); 114 | break; 115 | } 116 | 117 | const size_t cmd_len = cmd.len_hi << 8 | cmd.len_lo; 118 | warn("received %zu bytes: %d %zu\n", rlen, cmd.command, cmd_len); 119 | 120 | size_t offset = 0; 121 | while (offset < cmd_len) { 122 | rlen = read(fd, buf + offset, cmd_len - offset); 123 | if (rlen < 0) 124 | die("recv failed: %s\n", strerror(errno)); 125 | if (rlen == 0) 126 | break; 127 | offset += rlen; 128 | } 129 | 130 | if (cmd.command != 0) 131 | continue; 132 | 133 | struct timeval start_tv, stop_tv, delta_tv; 134 | gettimeofday(&start_tv, NULL); 135 | 136 | const unsigned frame_num = 0; 137 | 138 | for (unsigned int i = 0; i < image_size; i++) { 139 | uint8_t *const out = (void *)&fb[i]; 140 | const uint8_t *const in = &buf[3 * i]; 141 | out[0] = in[0]; 142 | out[1] = in[1]; 143 | out[2] = in[2]; 144 | } 145 | 146 | ledscape_draw(leds, fb); 147 | 148 | gettimeofday(&stop_tv, NULL); 149 | timersub(&stop_tv, &start_tv, &delta_tv); 150 | 151 | frames++; 152 | delta_sum += delta_tv.tv_usec; 153 | if (stop_tv.tv_sec - last_report < report_interval) 154 | continue; 155 | last_report = stop_tv.tv_sec; 156 | 157 | const unsigned delta_avg = delta_sum / frames; 158 | printf("%6u usec avg, max %.2f fps, actual %.2f fps (over %u frames)\n", 159 | delta_avg, report_interval * 1.0e6 / delta_avg, 160 | frames * 1.0 / report_interval, frames); 161 | 162 | frames = delta_sum = 0; 163 | } 164 | } 165 | 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /network/run-ledscape: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | DIRNAME="`dirname "$0"`" 3 | cd "$DIRNAME" 4 | 5 | modprobe uio_pruss 6 | exec ./udp-rx 7 | -------------------------------------------------------------------------------- /network/udp-rx.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * UDP image packet receiver. 3 | * 4 | * Based on the HackRockCity LED Display code: 5 | * https://github.com/agwn/pyramidTransmitter/blob/master/LEDDisplay.pde 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "ledscape.h" 17 | #include "pru.h" 18 | 19 | int main(int argc, char **argv) { 20 | int port = 9999; 21 | int num_pixels = 256; 22 | 23 | extern char *optarg; 24 | int opt; 25 | while ((opt = getopt(argc, argv, "p:c:d:")) != -1) { 26 | switch (opt) { 27 | case 'p': 28 | port = atoi(optarg); 29 | break; 30 | case 'c': 31 | num_pixels = atoi(optarg); 32 | break; 33 | case 'd': { 34 | int width = 0, height = 0; 35 | 36 | if (sscanf(optarg, "%dx%d", &width, &height) == 2) { 37 | num_pixels = width * height; 38 | } else { 39 | printf("Invalid argument for -d; expected NxN; actual: %s", optarg); 40 | exit(EXIT_FAILURE); 41 | } 42 | } break; 43 | default: 44 | fprintf(stderr, 45 | "Usage: %s [-p ] [-c | -d x]\n", 46 | argv[0]); 47 | exit(EXIT_FAILURE); 48 | } 49 | } 50 | 51 | const int sock = socket(AF_INET, SOCK_DGRAM, 0); 52 | struct sockaddr_in addr = { .sin_family = AF_INET, 53 | .sin_addr.s_addr = INADDR_ANY, 54 | .sin_port = htons(port), }; 55 | 56 | if (sock < 0) 57 | die("socket failed: %s\n", strerror(errno)); 58 | 59 | if (bind(sock, (const struct sockaddr *)&addr, sizeof(addr)) < 0) 60 | die("bind port %d failed: %s\n", port, strerror(errno)); 61 | 62 | ledscape_t *const leds = ledscape_init(num_pixels); 63 | 64 | fprintf(stderr, "Started LEDscape UDP receiver on port %d for %d pixels\n", 65 | port, num_pixels); 66 | 67 | unsigned frame_num = 0; 68 | 69 | uint8_t buf[num_pixels * 4]; 70 | 71 | time_t last_time = time(NULL); 72 | int fps_counter = 0; 73 | while (1) { 74 | const ssize_t rc = recv(sock, buf, sizeof(buf), 0); 75 | if (rc < 0) { 76 | printf("recv failed: %s\n", strerror(errno)); 77 | continue; 78 | } 79 | 80 | ledscape_frame_t *const frame = ledscape_frame(leds, frame_num); 81 | 82 | for (unsigned x = 0; x < num_pixels; x++) { 83 | const uint8_t r = buf[x * 3 + 0]; 84 | const uint8_t g = buf[x * 3 + 1]; 85 | const uint8_t b = buf[x * 3 + 2]; 86 | ledscape_set_color(frame, 0, x, r, g, b); 87 | } 88 | 89 | ledscape_wait(leds); 90 | ledscape_draw(leds, frame_num); 91 | 92 | time_t now = time(NULL); 93 | 94 | if (now != last_time) { 95 | printf("%d fps\n", fps_counter); 96 | last_time = now; 97 | fps_counter = 0; 98 | } 99 | fps_counter++; 100 | 101 | frame_num = (frame_num + 1) % 2; 102 | } 103 | 104 | ledscape_close(leds); 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /pixel.cpp: -------------------------------------------------------------------------------- 1 | #include "pixel.hpp" 2 | #include 3 | #include 4 | 5 | /* GPIO pins used */ 6 | static const uint8_t gpios0 = 2; 7 | 8 | PixelBone_Pixel::PixelBone_Pixel(uint16_t pixel_count) 9 | : pru0(pru_init(0)), num_pixels(pixel_count), 10 | buffer_size(pixel_count * sizeof(pixel_t)) { 11 | if (2 * buffer_size > pru0->ddr_size) 12 | die("Pixel data needs at least 2 * %zu, only %zu in DDR\n", buffer_size, 13 | pru0->ddr_size); 14 | 15 | ws281x = (ws281x_command_t *)pru0->data_ram; 16 | *(ws281x) = ws281x_command_t((unsigned)pixel_count); 17 | 18 | // Configure all of our output pins. 19 | pru_gpio(0, gpios0, 1, 0); 20 | 21 | // Initiate the PRU0 program 22 | pru_exec(pru0, "./ws281x.bin"); 23 | 24 | // Watch for a done response that indicates a proper startup 25 | // TODO: timeout if it fails 26 | std::cout << "waiting for response from pru0... "; 27 | while (!ws281x->response) 28 | ; 29 | std::cout << "OK" << std::endl; 30 | }; 31 | 32 | PixelBone_Pixel::~PixelBone_Pixel() { 33 | ws281x->command = 0xFF; 34 | pru_close(pru0); 35 | } 36 | 37 | void PixelBone_Pixel::show(void) { 38 | ws281x->pixels_dma = pru0->ddr_addr + buffer_size * current_buffer_num; 39 | 40 | // Wait for any current command to have been acknowledged 41 | while (ws281x->command) 42 | ; 43 | 44 | // Send the start command 45 | ws281x->command = 1; 46 | } 47 | 48 | void PixelBone_Pixel::moveToNextBuffer() { 49 | ++current_buffer_num %= 2; 50 | }; 51 | 52 | uint32_t PixelBone_Pixel::numPixels() const { return num_pixels; } 53 | 54 | /** Retrieve one of the two frame buffers. */ 55 | pixel_t *PixelBone_Pixel::getCurrentBuffer() const { 56 | return (pixel_t *)((uint8_t *)pru0->ddr + buffer_size * current_buffer_num); 57 | } 58 | 59 | pixel_t *PixelBone_Pixel::getPixel(uint32_t n) const { 60 | return &getCurrentBuffer()[n]; 61 | } 62 | 63 | // Convert separate R,G,B into packed 32-bit RGB color. 64 | // Packed format is always RGB, regardless of LED strand color order. 65 | uint32_t PixelBone_Pixel::Color(uint8_t r, uint8_t g, uint8_t b) { 66 | return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 67 | } 68 | 69 | uint32_t PixelBone_Pixel::h2rgb(uint32_t v1, uint32_t v2, uint32_t hue) { 70 | if (hue < 60) 71 | return v1 * 60 + (v2 - v1) * hue; 72 | if (hue < 180) 73 | return v2 * 60; 74 | if (hue < 240) 75 | return v1 * 60 + (v2 - v1) * (240 - hue); 76 | 77 | return v1 * 60; 78 | } 79 | 80 | /** 81 | * Convert HSL (Hue, Saturation, Lightness) to RGB (Red, Green, Blue) 82 | * 83 | * hue: 0 to 359 - position on the color wheel, 0=red, 60=orange, 84 | * 120=yellow, 180=green, 240=blue, 300=violet 85 | * 86 | * saturation: 0 to 100 - how bright or dull the color, 100=full, 0=gray 87 | * 88 | * lightness: 0 to 100 - how light the color is, 100=white, 50=color, 0=black 89 | */ 90 | 91 | uint32_t PixelBone_Pixel::HSL(uint32_t hue, uint32_t saturation,uint32_t lightness) { 92 | uint32_t red, green, blue; 93 | uint32_t var1, var2; 94 | 95 | if (hue > 359) hue = hue % 360; 96 | if (saturation > 100) saturation = 100; 97 | if (lightness > 100) lightness = 100; 98 | 99 | // algorithm from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19 100 | if (saturation == 0) { 101 | red = green = blue = lightness * 255 / 100; 102 | } else { 103 | if (lightness < 50) { 104 | var2 = lightness * (100 + saturation); 105 | } else { 106 | var2 = ((lightness + saturation) * 100) - (saturation * lightness); 107 | } 108 | var1 = lightness * 200 - var2; 109 | red = h2rgb(var1, var2, (hue < 240) ? hue + 120 : hue - 240) * 255 / 600000; 110 | green = h2rgb(var1, var2, hue) * 255 / 600000; 111 | blue = h2rgb(var1, var2, (hue >= 120) ? hue - 120 : hue + 240) * 255 / 600000; 112 | } 113 | return (red << 16) | (green << 8) | blue; 114 | } 115 | 116 | // Query color from previously-set pixel (returns packed 32-bit RGB value) 117 | uint32_t PixelBone_Pixel::getPixelColor(uint32_t n) const { 118 | if (n < num_pixels) { 119 | pixel_t *const p = getPixel(n); 120 | return Color(p->r, p->g, p->b); 121 | } 122 | return 0; // Pixel # is out of bounds 123 | } 124 | 125 | // Set pixel color from separate R,G,B components: 126 | void PixelBone_Pixel::setPixelColor(uint32_t n, uint8_t r, uint8_t g, 127 | uint8_t b) { 128 | if (n < num_pixels) { 129 | // if(brightness) { // See notes in setBrightness() 130 | // r = (r * brightness) >> 8; 131 | // g = (g * brightness) >> 8; 132 | // b = (b * brightness) >> 8; 133 | // } 134 | pixel_t *const p = getPixel(n); 135 | p->r = r; 136 | p->g = g; 137 | p->b = b; 138 | } 139 | } 140 | 141 | // Set pixel color from 'packed' 32-bit RGB color: 142 | void PixelBone_Pixel::setPixelColor(uint32_t n, uint32_t c) { 143 | if (n < num_pixels) { 144 | uint8_t r = (uint8_t)(c >> 16); 145 | uint8_t g = (uint8_t)(c >> 8); 146 | uint8_t b = (uint8_t)c; 147 | setPixelColor(n, r, g, b); 148 | } 149 | } 150 | 151 | void PixelBone_Pixel::setPixel(uint32_t n, pixel_t p) { 152 | memcpy(getPixel(n), &p, sizeof(pixel_t)); 153 | // setPixelColor(n, p.r, p.g, p.b); 154 | } 155 | 156 | uint32_t PixelBone_Pixel::wait() { 157 | while (1) { 158 | uint32_t response = ws281x->response; 159 | if (response) { 160 | ws281x->response = 0; 161 | return response; 162 | } 163 | } 164 | } 165 | 166 | void PixelBone_Pixel::clear() { 167 | for (uint16_t i = 0; i < num_pixels; i++) { 168 | this->setPixelColor(i, 0, 0, 0); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /pixel.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * LED Library for the BeagleBone (Black). 3 | * 4 | * Drives up to 32 ws281x LED strips using the PRU to have no CPU overhead. 5 | * Allows easy double buffering of frames. 6 | */ 7 | 8 | #ifndef _pixelbone_hpp_ 9 | #define _pixelbone_hpp_ 10 | #include "pru.h" 11 | 12 | /** LEDscape pixel format is BRGA. 13 | * 14 | * data is laid out with BRGA format, since that is how it will 15 | * be translated during the clock out from the PRU. 16 | */ 17 | struct pixel_t { 18 | uint8_t b; 19 | uint8_t r; 20 | uint8_t g; 21 | uint8_t a; 22 | pixel_t(uint8_t _r, uint8_t _g, uint8_t _b) : b(_b), r(_r), g(_g) {}; 23 | } __attribute__((__packed__)); 24 | 25 | /** Command structure shared with the PRU. 26 | * 27 | * This is mapped into the PRU data RAM and points to the 28 | * frame buffer in the shared DDR segment. 29 | * 30 | * Changing this requires changes in ws281x.p 31 | */ 32 | struct ws281x_command_t { 33 | // in the DDR shared with the PRU 34 | uintptr_t pixels_dma; 35 | 36 | // Length in pixels of the longest LED strip. 37 | unsigned num_pixels; 38 | 39 | // write 1 to start, 0xFF to abort. will be cleared when started 40 | volatile unsigned command; 41 | 42 | // will have a non-zero response written when done 43 | volatile unsigned response; 44 | ws281x_command_t(unsigned _num_pixels) 45 | : pixels_dma(0), num_pixels(_num_pixels), command(0), response(0) {}; 46 | 47 | } __attribute__((__packed__)); 48 | 49 | class PixelBone_Pixel { 50 | pru_t *pru0; 51 | uint32_t num_pixels; 52 | ws281x_command_t *ws281x; 53 | size_t buffer_size; 54 | uint8_t current_buffer_num; 55 | uint8_t brightness; 56 | 57 | public: 58 | PixelBone_Pixel(uint16_t pixel_count); 59 | ~PixelBone_Pixel(); 60 | void show(void); 61 | void clear(void); 62 | void setPixelColor(uint32_t n, uint8_t r, uint8_t g, uint8_t b); 63 | void setPixelColor(uint32_t n, uint32_t c); 64 | void setPixel(uint32_t n, pixel_t c); 65 | void moveToNextBuffer(); 66 | uint32_t wait(); 67 | uint32_t numPixels() const; 68 | pixel_t *getCurrentBuffer() const; 69 | pixel_t *getPixel(uint32_t n) const; 70 | uint32_t getPixelColor(uint32_t n) const; 71 | static uint32_t Color(uint8_t red, uint8_t green, uint8_t blue); 72 | static uint32_t HSL(uint32_t hue, uint32_t saturation, uint32_t brightness); 73 | 74 | private: 75 | static uint32_t h2rgb(uint32_t v1, uint32_t v2, uint32_t hue); 76 | }; 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /pixel.i: -------------------------------------------------------------------------------- 1 | %module pixel 2 | %{ 3 | /* Includes the header in the wrapper code */ 4 | #include "pixel.hpp" 5 | %} 6 | 7 | #define __attribute__(x) 8 | 9 | /* Parse the header file to generate wrappers */ 10 | %include "pixel.hpp" 11 | -------------------------------------------------------------------------------- /pru.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Userspace interface to the BeagleBone PRU. 3 | * 4 | * Wraps the prussdrv library in a sane interface. 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "pru.h" 18 | 19 | static unsigned int proc_read(const char *const fname) { 20 | FILE *const f = fopen(fname, "r"); 21 | if (!f) 22 | die("%s: Unable to open: %s", fname, strerror(errno)); 23 | unsigned int x; 24 | fscanf(f, "%x", &x); 25 | fclose(f); 26 | return x; 27 | } 28 | 29 | pru_t *pru_init(const unsigned short pru_num) { 30 | prussdrv_init(); 31 | 32 | int ret = prussdrv_open(PRU_EVTOUT_0); 33 | if (ret) 34 | die("prussdrv_open open failed\n"); 35 | 36 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 37 | prussdrv_pruintc_init(&pruss_intc_initdata); 38 | 39 | void *pru_data_mem; 40 | prussdrv_map_prumem(pru_num == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, 41 | &pru_data_mem); 42 | 43 | const int mem_fd = open("/dev/mem", O_RDWR); 44 | if (mem_fd < 0) 45 | die("Failed to open /dev/mem: %s\n", strerror(errno)); 46 | 47 | const uintptr_t ddr_addr = proc_read("/sys/class/uio/uio0/maps/map1/addr"); 48 | const uintptr_t ddr_size = proc_read("/sys/class/uio/uio0/maps/map1/size"); 49 | 50 | const uintptr_t ddr_start = 0x10000000; 51 | const uintptr_t ddr_offset = ddr_addr - ddr_start; 52 | const size_t ddr_filelen = ddr_size + ddr_start; 53 | 54 | /* map the memory */ 55 | uint8_t *const ddr_mem = mmap(0, ddr_filelen, PROT_WRITE | PROT_READ, 56 | MAP_SHARED, mem_fd, ddr_offset); 57 | if (ddr_mem == MAP_FAILED) 58 | die("Failed to mmap offset %" PRIxPTR " @ %zu bytes: %s\n", ddr_offset, 59 | ddr_filelen, strerror(errno)); 60 | 61 | close(mem_fd); 62 | 63 | pru_t *const pru = calloc(1, sizeof(*pru)); 64 | if (!pru) 65 | die("calloc failed: %s", strerror(errno)); 66 | 67 | *pru = (pru_t) { .pru_num = pru_num, 68 | .data_ram = pru_data_mem, 69 | .data_ram_size = 8192, // how to determine? 70 | .ddr_addr = ddr_addr, 71 | .ddr = (void *)(ddr_mem + ddr_start), 72 | .ddr_size = ddr_size, }; 73 | 74 | printf("%s: PRU %d: data %p @ %zu bytes, DMA %p / %" PRIxPTR 75 | " @ %zu bytes\n", 76 | __func__, pru_num, pru->data_ram, pru->data_ram_size, pru->ddr, 77 | pru->ddr_addr, pru->ddr_size); 78 | 79 | return pru; 80 | } 81 | 82 | void pru_exec(pru_t *const pru, const char *const program) { 83 | char *program_unconst = (char *)(uintptr_t)program; 84 | if (prussdrv_exec_program(pru->pru_num, program_unconst) < 0) 85 | die("%s failed", program); 86 | } 87 | 88 | void pru_close(pru_t *const pru) { 89 | // \todo unmap memory 90 | prussdrv_pru_wait_event(PRU_EVTOUT_0); 91 | prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); 92 | prussdrv_pru_disable(pru->pru_num); 93 | prussdrv_exit(); 94 | } 95 | 96 | int pru_gpio(const unsigned gpio, const unsigned pin, const unsigned direction, 97 | const unsigned initial_value) { 98 | const unsigned pin_num = gpio * 32 + pin; 99 | const char *export_name = "/sys/class/gpio/export"; 100 | FILE *const export = fopen(export_name, "w"); 101 | if (!export) 102 | die("%s: Unable to open? %s\n", export_name, strerror(errno)); 103 | 104 | fprintf(export, "%d\n", pin_num); 105 | fclose(export); 106 | 107 | char value_name[64]; 108 | snprintf(value_name, sizeof(value_name), "/sys/class/gpio/gpio%u/value", 109 | pin_num); 110 | 111 | FILE *const value = fopen(value_name, "w"); 112 | if (!value) 113 | die("%s: Unable to open? %s\n", value_name, strerror(errno)); 114 | 115 | fprintf(value, "%d\n", initial_value); 116 | fclose(value); 117 | 118 | char dir_name[64]; 119 | snprintf(dir_name, sizeof(dir_name), "/sys/class/gpio/gpio%u/direction", 120 | pin_num); 121 | 122 | FILE *const dir = fopen(dir_name, "w"); 123 | if (!dir) 124 | die("%s: Unable to open? %s\n", dir_name, strerror(errno)); 125 | 126 | fprintf(dir, "%s\n", direction ? "out" : "in"); 127 | fclose(dir); 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /pru.h: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Simplified interface to the ARM PRU. 3 | * 4 | */ 5 | #ifndef _pru_h_ 6 | #define _pru_h_ 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | #include 14 | #include "util.h" 15 | 16 | /** Mapping of the PRU memory spaces. 17 | * 18 | * The PRU has a small, fast local data RAM that is mapped into ARM memory, 19 | * as well as slower access to the DDR RAM of the ARM. 20 | */ 21 | typedef struct { 22 | unsigned pru_num; 23 | 24 | void *data_ram; // PRU data ram in ARM space 25 | size_t data_ram_size; // size in bytes of the PRU's data RAM 26 | 27 | void *ddr; // PRU DMA address (in ARM space) 28 | uintptr_t ddr_addr; // PRU DMA address (in PRU space) 29 | size_t ddr_size; // Size in bytes of the shared space 30 | } pru_t; 31 | 32 | extern pru_t *pru_init(const unsigned short pru_num); 33 | 34 | extern void pru_exec(pru_t *const pru, const char *const program); 35 | 36 | extern void pru_close(pru_t *const pru); 37 | 38 | /** Configure a GPIO pin. 39 | * 40 | * Since the device tree won't do it for us, we need to do it via 41 | * /sys/class/gpio to set the direction and initial value for 42 | * all of the pins that we use. 43 | * 44 | * Direction 0 == in, 1 == out. 45 | */ 46 | extern int pru_gpio(unsigned gpio, unsigned pin, unsigned direction, 47 | const unsigned initial_value); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | #endif 53 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | setup.py file for SWIG example 5 | """ 6 | 7 | from distutils.core import setup, Extension 8 | 9 | 10 | matrix_module = Extension('_matrix', 11 | sources=['matrix_wrap.cxx', 'matrix.cpp', 12 | 'gfx.cpp', 'pixel.cpp', 'pru.c', 'util.c', 13 | 'glcdfont.c'], 14 | library_dirs=['/usr/local/lib'], 15 | libraries=['prussdrv'], 16 | ) 17 | 18 | setup (name = 'matrix', 19 | version = '0.1', 20 | author = "SWIG Docs", 21 | description = """Simple swig example from docs""", 22 | ext_modules = [matrix_module], 23 | py_modules = ["matrix"], 24 | ) 25 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Various utility functions 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "util.h" 20 | 21 | /** Write all the bytes to a fd, even if there is a brief interruption. 22 | * \return number of bytes written or -1 on any fatal error. 23 | */ 24 | ssize_t write_all(const int fd, const void *const buf_ptr, const size_t len) { 25 | const uint8_t *const buf = buf_ptr; 26 | size_t offset = 0; 27 | 28 | while (offset < len) { 29 | const ssize_t rc = write(fd, buf + offset, len - offset); 30 | if (rc < 0) { 31 | if (errno == EAGAIN) 32 | continue; 33 | return -1; 34 | } 35 | 36 | if (rc == 0) 37 | return -1; 38 | 39 | offset += rc; 40 | } 41 | 42 | return len; 43 | } 44 | 45 | int serial_open(const char *const dev) { 46 | const int fd = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY, 0666); 47 | if (fd < 0) 48 | return -1; 49 | 50 | // Disable modem control signals 51 | struct termios attr; 52 | tcgetattr(fd, &attr); 53 | attr.c_cflag |= CLOCAL | CREAD; 54 | attr.c_oflag &= ~OPOST; 55 | tcsetattr(fd, TCSANOW, &attr); 56 | 57 | return fd; 58 | } 59 | 60 | void hexdump(FILE *const outfile, const void *const buf, const size_t len) { 61 | const uint8_t *const p = buf; 62 | 63 | for (size_t i = 0; i < len; i++) { 64 | if (i % 8 == 0) 65 | fprintf(outfile, "%s%04zu:", i == 0 ? "" : "\n", i); 66 | fprintf(outfile, " %02x", p[i]); 67 | } 68 | 69 | fprintf(outfile, "\n"); 70 | } 71 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Utility functions. 3 | */ 4 | #ifndef _util_h_ 5 | #define _util_h_ 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define warn(fmt, ...) \ 20 | do { \ 21 | fprintf(stderr, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__); \ 22 | } while (0) 23 | 24 | #define warn_once(fmt, ...) \ 25 | do { \ 26 | static unsigned __warned__; \ 27 | if (__warned__) \ 28 | break; \ 29 | __warned__ = 1; \ 30 | warn(fmt, ##__VA_ARGS__); \ 31 | } while (0) 32 | 33 | #define die(fmt, ...) \ 34 | do { \ 35 | warn(fmt, ##__VA_ARGS__); \ 36 | exit(EXIT_FAILURE); \ 37 | } while (0) 38 | 39 | extern void hexdump(FILE *const outfile, const void *const buf, 40 | const size_t len); 41 | 42 | extern int serial_open(const char *const dev); 43 | 44 | /** Write all the bytes to a fd, even if there is a brief interruption. 45 | * \return number of bytes written or -1 on any fatal error. 46 | */ 47 | extern ssize_t write_all(const int fd, const void *const buf_ptr, 48 | const size_t len); 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /ws281x.hp: -------------------------------------------------------------------------------- 1 | #ifndef _ws281x_HP_ 2 | #define _ws281x_HP_ 3 | 4 | 5 | #define AM33XX 6 | 7 | // *************************************** 8 | // * Global Macro definitions * 9 | // *************************************** 10 | 11 | #ifdef AM33XX 12 | 13 | // Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h 14 | #define PRU0_PRU1_INTERRUPT 17 15 | #define PRU0_ARM_INTERRUPT 19 16 | #define ARM_PRU0_INTERRUPT 21 17 | 18 | #define CONST_PRUDRAM C24 19 | #define CONST_SHAREDRAM C28 20 | #define CONST_L3RAM C30 21 | #define CONST_DDR C31 22 | 23 | // Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 24 | #define CTBIR_0 0x22020 25 | // Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 26 | #define CTBIR_1 0x22024 27 | 28 | // Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 29 | #define CTPPR_0 0x22028 30 | // Address for the Constant table Programmable Pointer Register 1(CTPPR_1) 31 | #define CTPPR_1 0x2202C 32 | 33 | #else 34 | 35 | // Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h 36 | #define PRU0_PRU1_INTERRUPT 32 37 | #define PRU0_ARM_INTERRUPT 34 38 | #define ARM_PRU0_INTERRUPT 36 39 | 40 | #define CONST_PRUDRAM C3 41 | #define CONST_HPI C15 42 | #define CONST_DSPL2 C28 43 | #define CONST_L3RAM C30 44 | #define CONST_DDR C31 45 | 46 | // Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 47 | #define CTPPR_0 0x7028 48 | // Address for the Constant table Programmable Pointer Register 1(CTPPR_1) 49 | #define CTPPR_1 0x702C 50 | 51 | #endif 52 | 53 | .macro LD32 54 | .mparam dst,src 55 | LBBO dst,src,#0x00,4 56 | .endm 57 | 58 | .macro LD16 59 | .mparam dst,src 60 | LBBO dst,src,#0x00,2 61 | .endm 62 | 63 | .macro LD8 64 | .mparam dst,src 65 | LBBO dst,src,#0x00,1 66 | .endm 67 | 68 | .macro ST32 69 | .mparam src,dst 70 | SBBO src,dst,#0x00,4 71 | .endm 72 | 73 | .macro ST16 74 | .mparam src,dst 75 | SBBO src,dst,#0x00,2 76 | .endm 77 | 78 | .macro ST8 79 | .mparam src,dst 80 | SBBO src,dst,#0x00,1 81 | .endm 82 | 83 | 84 | #define sp r0 85 | #define lr r23 86 | #define STACK_TOP (0x2000 - 4) 87 | #define STACK_BOTTOM (0x2000 - 0x200) 88 | 89 | .macro stack_init 90 | mov sp, STACK_BOTTOM 91 | .endm 92 | 93 | .macro push 94 | .mparam reg, cnt 95 | sbbo reg, sp, 0, 4*cnt 96 | add sp, sp, 4*cnt 97 | .endm 98 | 99 | .macro pop 100 | .mparam reg, cnt 101 | sub sp, sp, 4*cnt 102 | lbbo reg, sp, 0, 4*cnt 103 | .endm 104 | 105 | // *************************************** 106 | // * Global Structure Definitions * 107 | // *************************************** 108 | 109 | /** Mappings of the GPIO devices */ 110 | #define GPIO0 0x44E07000 111 | 112 | /** Offsets for the clear and set registers in the devices */ 113 | #define GPIO_CLEARDATAOUT 0x190 114 | #define GPIO_SETDATAOUT 0x194 115 | 116 | #define NOP mov r0, r0 117 | 118 | // *************************************** 119 | // * Global Register Assignments * 120 | // *************************************** 121 | 122 | 123 | #endif //_ws281x_HP_ 124 | -------------------------------------------------------------------------------- /ws281x.p: -------------------------------------------------------------------------------- 1 | // \file 2 | //* WS281x LED strip driver for the BeagleBone Black. 3 | //* 4 | //* Drives up to 32 strips using the PRU hardware. The ARM writes 5 | //* rendered frames into shared DDR memory and sets a flag to indicate 6 | //* how many pixels wide the image is. The PRU then bit bangs the signal 7 | //* out the 32 GPIO pins and sets a done flag. 8 | //* 9 | //* To stop, the ARM can write a 0xFF to the command, which will 10 | //* cause the PRU code to exit. 11 | //* 12 | //* At 800 KHz: 13 | //* 0 is 0.25 usec high, 1 usec low 14 | //* 1 is 0.60 usec high, 0.65 usec low 15 | //* Reset is 50 usec 16 | // 17 | // Pins are not contiguous. 18 | // 1 pins on GPIO0: 2 19 | // 20 | // each pixel is stored in 4 bytes in the order GRBA (4th byte is ignored) 21 | // 22 | // while len > 0: 23 | // for bit# = 24 down to 0: 24 | // delay 600 ns 25 | // read 1 registers of data, build zero map for gpio0 26 | // 27 | // Send start pulse on all pins on gpio0, gpio1 and gpio3 28 | // delay 250 ns 29 | // bring zero pins low 30 | // delay 300 ns 31 | // bring all pins low 32 | // increment address by 32 33 | 34 | //* 35 | //* So to clock this out: 36 | //* ____ 37 | //* | | |______| 38 | //* 0 250 600 1250 offset 39 | //* 250 350 650 delta 40 | //* 41 | //*/ 42 | 43 | 44 | .origin 0 45 | .entrypoint START 46 | 47 | #include "ws281x.hp" 48 | 49 | #define NOP mov r0, r0 50 | 51 | //=============================== 52 | // GPIO Pin Mapping 53 | 54 | // Pins in GPIO0 55 | #define gpio0_bit0 2 56 | 57 | #define GPIO0_LED_MASK (0\ 58 | |(1<