Initial Release

pull/1/head
graham sanderson 2021-01-20 11:16:37 -06:00
commit 9195b8e21a
88 zmienionych plików z 27244 dodań i 0 usunięć

3
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,3 @@
.idea
.vscode
cmake-*

22
CMakeLists.txt 100644
Wyświetl plik

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.12)
# Pull in PICO SDK (must be before project)
include(pico_sdk_import.cmake)
# We also need PICO EXTRAS
include(pico_extras_import.cmake)
project(pico_playground C CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Initialize the Pico SDK
pico_sdk_init()
add_subdirectory(audio)
add_subdirectory(apps)
add_subdirectory(net)
add_subdirectory(reset)
add_subdirectory(scanvideo)
add_subdirectory(sleep)
add_subdirectory(stdio)

21
LICENSE.TXT 100644
Wyświetl plik

@ -0,0 +1,21 @@
Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

70
README.md 100644
Wyświetl plik

@ -0,0 +1,70 @@
This repo is similar to [pico-examples](https://github.com/raspberrypi/pico-examples) but utilizing additional libraries
from [pico-extras](https://github.com/raspberrypi/pico-extras)
Note that most of these examples are neither fleshed out nor well documented. They mostly serve
the purpose of playing with/testing particular areas of functionality (mostly audio/video related)
Finally, you may wonder why many of these demos set the system clock to 48Mhz. The reason is that until we had physical
chips, we were running at a fixed 48Mhz system clock on FPGA. Most of these examples were written before the
RP2040 design was final and as such were all run against FPGA. As a result some of the examples do things in a way
that you wouldn't necessarily need to if you had more clock speed available (which you do), but on the plus side,
you have that much more time to do even more things!
## Full Applications
Name|Description
---|---
[popcorn](apps/popcorn)| This is a movie player for 30fps 320x240 movies with 44100 stereo sound, read in a custom format from SD card... it can even play backwards :-) TODO: add a link to big buck bunny in the right format TODO: add converter
[usb_sound_card](apps/usb_sound_card)| A no frills but functional USB sound card... hooked up via our old (pre TinyUSB) USB device stack. Keeping it around as it works nicely!
## Audio
Name|Description
---|---
[sine_wave_i2s](audio/sine_wave)| A simple sine wave audio output using I2S.
[sine_wave_pwm](audio/sine_wave)| A simple sine wave audio output using PWM.
[sine_wave_spdif](audio/sine_wave)| A simple sine wave audio output using S/PDIF.
## Scanout Video
In _scanout_ video, every pixel is driven by the PIO every frame, and a framebuffer is not (necessarily) used (which
is useful when you only have 264K of RAM).
Name|Description
---|---
[demo1](scanvideo/demo1)| So named because it was the first demo program written that used video.. it is a bit dated now and hails from a time where there was _much_ less RAM on the RP2040
[flash_stream](scanvideo/flash_stream)| Streams video data out of flash fast enough to drive 640x480x60fps bitmap display
[hscroll_dma_tiles](scanvideo/hscroll_dma_tiles)| A horizontal scrolling test app which uses a second video plane (PIO) to overlay sprites
[mandelbrot](scanvideo/mandelbrot)| A mandelbrot generator using a 320x240x16 framebuffer
[mario_tiles](scanvideo/mario_tiles)| Confusingly named as a reference to Super Mario Kart's tiled psuedo-3D rendering. This is similar to [hscroll_dma_tiles](scanvideo/hscroll_dma_tiles) except the whole tiled scrolling area is now rotated and zoomed.
[scanvideo_minimal](scanvideo/scanvideo_minimal)| A very basic video output generator which generates a test pattern
[render](scanvideo/render)| A very dated rendering library used by [demo1](scanvideo/demo1) - avoid!
[sprite](scanvideo/sprite)| A small sprite library used by [sprite_demo](scanvideo/scanvideo_minimal)
[sprite_demo](scanvideo/sprite_demo)| Some bouncing Eben heads
[textmode](scanvideo/textmode)| Shows off chained DMA to generate scanlines out of glyph fragments via DMA/PIO
## Sleep
Examples of using low power mode; these use `pico_sleep` from pico_extras which is not yet stable.
Name|Description
---|---
[hello_dormant](sleep/hello_dormant)| Demonstrates dormant mode
[hello_sleep](sleep/hello_sleep)| Demonstrates low power sleep and waking from RTC
## Stdio
Examples of adding additional stdio support. Note the interface for stdio drivers is not yet considered stable
even though it is in the Pico SDK
Name|Description
---|---
[stdio_pio](stdio/pio)| Demonstrates adding a custom STDIO driver using a PIO UART
## Networking
Name|Description
---|---
[usb_host_webserver](net/usb_host_webserver)| A simple web server implemented as

Wyświetl plik

@ -0,0 +1,2 @@
add_subdirectory(popcorn)
add_subdirectory(usb_sound_card)

Wyświetl plik

@ -0,0 +1,46 @@
if (PICO_ON_DEVICE)
if (TARGET pico_scanvideo_dpi AND TARGET pico_sd_card)
add_executable(popcorn
popcorn.c
atlantis.c
lcd12.c
lcd18.c
)
add_compile_definitions(popcorn
PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS=164
# seems fine without 16 (maybe need for overlay)
PICO_SCANVIDEO_SCANLINE_BUFFER_COUNT=16
#PICO_DEBUG_MALLOC
PICO_AUDIO_I2S_DMA_IRQ=1
PICO_AUDIO_I2S_PIO=0
PICO_STACK_SIZE=0x400
__HEAP_SIZE=0x500
PICO_USE_STACK_GUARDS=1
PICO_SCANVIDEO_ADJUST_BUS_PRIORITY=1
PICO_SCANVIDEO_ENABLE_VIDEO_CLOCK_DOWN=1
# VIDEO_TIME_CRITICAL_CODE_SECTION=.core0.video
PLATYPUS_565
VIDEO_565
VIDEO_DBI
PICO_SCANVIDEO_LINKED_SCANLINE_BUFFERS=1 # we do two rows at a time
)
if (PICO_BOARD STREQUAL "vgaboard")
add_compile_definitions(popcorn PRIVATE
PICO_DEFAULT_UART=0
PICO_DEFAULT_UART_TX_PIN=28
PICO_DEFAULT_UART_RX_PIN=29
)
endif()
target_link_libraries(popcorn
pico_multicore
pico_stdlib
platypus
pico_scanvideo_dpi
pico_sd_card
pico_audio_i2s)
pico_add_extra_outputs(popcorn)
endif()
endif()

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,38 @@
#ifndef SOFTWARE_FONT_H
#define SOFTWARE_FONT_H
#include "pico.h"
typedef struct {
uint16_t bitmap_index;
uint16_t adv_w;
int8_t box_w, box_h, ofs_x, ofs_y;
} __attribute__((packed)) lv_font_fmt_txt_glyph_dsc_t;
typedef struct {
uint16_t range_start, range_length, glyph_id_start;//, list_length;
// void *unicode_list, *glyph_id_ofs_list;
enum {
LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY,
LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL
} type;
} lv_font_fmt_txt_cmap_t;
typedef struct {
const uint8_t *glyph_bitmap;
const lv_font_fmt_txt_glyph_dsc_t *glyph_dsc;
const lv_font_fmt_txt_cmap_t *cmaps;
uint8_t cmap_num, bpp, kern_scale, kern_classes;
void *kern_dsc;
} lv_font_fmt_txt_dsc_t;
typedef struct {
lv_font_fmt_txt_dsc_t *dsc;
uint8_t line_height, base_line;
} lv_font_t;
extern const lv_font_t lcd12;
extern const lv_font_t lcd18;
#define LV_ATTRIBUTE_LARGE_CONST
#endif //SOFTWARE_FONT_H

Wyświetl plik

@ -0,0 +1,177 @@
#include "font.h"
/*******************************************************************************
* FrozenCrystal
* Size: 12 px
* Bpp: 4
* Opts:
******************************************************************************/
#ifndef LCD12
#define LCD12 1
#endif
#if LCD12
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
/* U+2E "." */
0x93,
/* U+30 "0" */
0xc, 0xbb, 0x93, 0x47, 0x0, 0x84, 0x58, 0x0,
0xc4, 0x75, 0x31, 0x90, 0x51, 0x73, 0x90, 0xc4,
0x0, 0xe0, 0xc0, 0x1, 0xc0, 0xab, 0xbb, 0x70,
/* U+31 "1" */
0xc9, 0x40, 0x88, 0x8, 0x40, 0x74, 0x6, 0x0,
0xd0, 0xf, 0x0, 0xa0,
/* U+32 "2" */
0xc, 0xbb, 0x93, 0x0, 0x0, 0x84, 0x0, 0x0,
0xc3, 0x3, 0x33, 0xa0, 0x59, 0x88, 0x30, 0xc4,
0x0, 0x0, 0xc0, 0x0, 0x0, 0xab, 0xbb, 0x50,
/* U+33 "3" */
0xc, 0xbb, 0x93, 0x0, 0x0, 0x84, 0x0, 0x0,
0xc3, 0x3, 0x33, 0xa0, 0x8, 0x88, 0xc0, 0x0,
0x0, 0xd0, 0x0, 0x1, 0xc0, 0x9b, 0xba, 0xa0,
/* U+34 "4" */
0x26, 0x0, 0x43, 0x49, 0x0, 0x84, 0x58, 0x0,
0xc4, 0x77, 0x33, 0xb0, 0x7, 0x88, 0xc0, 0x0,
0x0, 0xd0, 0x0, 0x1, 0xc0, 0x0, 0x1, 0xa0,
/* U+35 "5" */
0x29, 0xbb, 0x54, 0x90, 0x0, 0x58, 0x0, 0x7,
0x73, 0x32, 0x7, 0x88, 0xc0, 0x0, 0xd, 0x0,
0x1, 0xc9, 0xbb, 0xaa,
/* U+36 "6" */
0xc, 0xbb, 0xb3, 0x47, 0x0, 0x0, 0x58, 0x0,
0x0, 0x78, 0x33, 0x20, 0x58, 0x88, 0xc0, 0xc4,
0x0, 0xe0, 0xc0, 0x1, 0xc0, 0xab, 0xbb, 0x70,
/* U+37 "7" */
0xcb, 0xb9, 0x30, 0x0, 0x84, 0x0, 0xc, 0x30,
0x0, 0x90, 0x0, 0x9, 0x0, 0x0, 0xd0, 0x0,
0x1c, 0x0, 0x1, 0x90,
/* U+38 "8" */
0xc, 0xbb, 0x93, 0x47, 0x0, 0x84, 0x58, 0x0,
0xc4, 0x78, 0x33, 0xb0, 0x58, 0x88, 0xc0, 0xc4,
0x0, 0xe0, 0xc0, 0x1, 0xc0, 0xab, 0xbb, 0x70,
/* U+39 "9" */
0xb, 0xbb, 0xa3, 0x48, 0x0, 0x84, 0x48, 0x0,
0xa4, 0x88, 0x33, 0xb1, 0x7, 0x88, 0xa0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xc0, 0x9b, 0xbb, 0x70,
/* U+3A ":" */
0x12, 0x35, 0x0, 0x0, 0x93
};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 55, .box_h = 1, .box_w = 2, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 25, .adv_w = 77, .box_h = 8, .box_w = 3, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 37, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 61, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 85, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 109, .adv_w = 107, .box_h = 8, .box_w = 5, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 129, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 153, .adv_w = 107, .box_h = 8, .box_w = 5, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 173, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 197, .adv_w = 107, .box_h = 8, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 221, .adv_w = 55, .box_h = 5, .box_w = 2, .ofs_x = 1, .ofs_y = 0}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
//static const uint8_t glyph_id_ofs_list_0[] = {
// 0, 0, 1, 2, 3, 4, 5, 6,
// 7, 8, 9, 10, 11
//};
//
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
.range_start = 46, .range_length = 13, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL,
.glyph_id_start = 1,
}
};
/*-----------------
* KERNING
*----------------*/
///*Pair left and right glyphs for kerning*/
//static const uint8_t kern_pair_glyph_ids[] =
// {
// 1, 3,
// 1, 6,
// 12, 3
// };
//
///* Kerning between the respective left and right glyphs
// * 4.4 format which needs to scaled with `kern_scale`*/
//static const int8_t kern_pair_values[] =
// {
// -21, -21, -21
// };
///*Collect the kern pair's data in one place*/
//static const lv_font_fmt_txt_kern_pair_t kern_pairs =
// {
// .glyph_ids = kern_pair_glyph_ids,
// .values = kern_pair_values,
// .pair_cnt = 3,
// .glyph_ids_size = 0
// };
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
/*Store all the custom data of the font*/
static lv_font_fmt_txt_dsc_t font_dsc = {
.glyph_bitmap = gylph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.cmap_num = 1,
.bpp = 4,
// .kern_scale = 16,
// .kern_dsc = &kern_pairs,
// .kern_classes = 0
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
const lv_font_t lcd12 = {
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
// .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
// .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.line_height = 9, /*The maximum line height required by the font*/
.base_line = 1, /*Baseline measured from the bottom of the line*/
};
#endif /*#if LCD12*/

Wyświetl plik

@ -0,0 +1,212 @@
#include "font.h"
/*******************************************************************************
* Size: 18 px
* Bpp: 4
* Opts:
******************************************************************************/
#ifndef LCD18
#define LCD18 1
#endif
#if LCD18
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = {
/* U+2E "." */
0x3, 0x11, 0xf7,
/* U+30 "0" */
0x1, 0x9b, 0xbb, 0xb8, 0x30, 0x3a, 0xcc, 0xcb,
0xb8, 0x7, 0xe0, 0x0, 0xe, 0x70, 0x8c, 0x0,
0x0, 0xf4, 0xa, 0xc0, 0x0, 0xf, 0x40, 0xa3,
0x7, 0x20, 0xb1, 0x5, 0x2, 0xc5, 0x8, 0x0,
0xf4, 0x0, 0x7, 0xe0, 0xf, 0x40, 0x0, 0x8c,
0x2, 0xf3, 0x0, 0xa, 0xc0, 0x4f, 0x33, 0x33,
0x96, 0x3, 0xbe, 0xff, 0xff, 0x40,
/* U+31 "1" */
0x19, 0xb8, 0x51, 0x8c, 0x9b, 0x0, 0xc, 0xa0,
0x0, 0xc8, 0x0, 0xe, 0x70, 0x0, 0x93, 0x0,
0x6, 0x20, 0x3, 0xf1, 0x0, 0x4f, 0x0, 0x7,
0xe0, 0x0, 0x8c, 0x0, 0x5, 0x90,
/* U+32 "2" */
0x1, 0x9b, 0xbb, 0xb8, 0x30, 0x18, 0xcc, 0xcb,
0xb8, 0x0, 0x0, 0x0, 0xf, 0x60, 0x0, 0x0,
0x0, 0xf4, 0x0, 0x0, 0x0, 0x1f, 0x40, 0x5,
0x77, 0x76, 0xc0, 0x5, 0xbc, 0xcc, 0xb1, 0x0,
0xf4, 0x0, 0x0, 0x0, 0xf, 0x40, 0x0, 0x0,
0x2, 0xf3, 0x0, 0x0, 0x0, 0x4f, 0x33, 0x33,
0x30, 0x3, 0xbe, 0xff, 0xff, 0x40,
/* U+33 "3" */
0x1, 0x9b, 0xbb, 0xb8, 0x30, 0x18, 0xcc, 0xcb,
0xb8, 0x0, 0x0, 0x0, 0xf, 0x60, 0x0, 0x0,
0x0, 0xf4, 0x0, 0x0, 0x0, 0x1f, 0x40, 0x5,
0x77, 0x76, 0xc0, 0x0, 0xbc, 0xcc, 0xb8, 0x0,
0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0x0, 0x8c,
0x0, 0x0, 0x0, 0xa, 0xb0, 0x2, 0x33, 0x33,
0xc8, 0x3, 0xff, 0xff, 0xfb, 0x50,
/* U+34 "4" */
0x17, 0x0, 0x0, 0x43, 0x4e, 0x0, 0x0, 0xb8,
0x7e, 0x0, 0x0, 0xe7, 0x8c, 0x0, 0x0, 0xf4,
0xac, 0x0, 0x0, 0xf4, 0xa8, 0x77, 0x77, 0xc1,
0xb, 0xcc, 0xcc, 0xa0, 0x0, 0x0, 0x7, 0xe0,
0x0, 0x0, 0x8, 0xc0, 0x0, 0x0, 0xa, 0xc0,
0x0, 0x0, 0xc, 0x80, 0x0, 0x0, 0x8, 0x50,
/* U+35 "5" */
0x1, 0x7c, 0xbb, 0xb4, 0x4, 0xe9, 0xcc, 0xb0,
0x7, 0xe0, 0x0, 0x0, 0x8, 0xc0, 0x0, 0x0,
0xa, 0xc0, 0x0, 0x0, 0xa, 0x87, 0x77, 0x71,
0x0, 0xbc, 0xcc, 0xc9, 0x0, 0x0, 0x0, 0x7d,
0x0, 0x0, 0x0, 0x8c, 0x0, 0x0, 0x0, 0xab,
0x2, 0x33, 0x33, 0xc8, 0x3f, 0xff, 0xff, 0xb5,
/* U+36 "6" */
0x1, 0x9b, 0xbb, 0xbb, 0x40, 0x3a, 0xcc, 0xcc,
0x92, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x8c, 0x0,
0x0, 0x0, 0xa, 0xc0, 0x0, 0x0, 0x0, 0xa8,
0x77, 0x77, 0x10, 0x5, 0xbc, 0xcc, 0xca, 0x0,
0xf4, 0x0, 0x7, 0xe0, 0xf, 0x40, 0x0, 0x8c,
0x2, 0xf3, 0x0, 0xa, 0xc0, 0x4f, 0x33, 0x33,
0x96, 0x3, 0xbe, 0xff, 0xff, 0x40,
/* U+37 "7" */
0x19, 0xbb, 0xbb, 0x83, 0x18, 0xcc, 0xcb, 0xb8,
0x0, 0x0, 0x0, 0xf6, 0x0, 0x0, 0x0, 0xf4,
0x0, 0x0, 0x1, 0xf4, 0x0, 0x0, 0x0, 0xc0,
0x0, 0x0, 0x0, 0x70, 0x0, 0x0, 0x7, 0xd0,
0x0, 0x0, 0x8, 0xc0, 0x0, 0x0, 0xa, 0xb0,
0x0, 0x0, 0xc, 0x80, 0x0, 0x0, 0x9, 0x50,
/* U+38 "8" */
0x1, 0x9b, 0xbb, 0xb8, 0x30, 0x3a, 0xcc, 0xcb,
0xb8, 0x7, 0xe0, 0x0, 0xe, 0x70, 0x8c, 0x0,
0x0, 0xf4, 0xa, 0xc0, 0x0, 0xf, 0x40, 0xa8,
0x77, 0x77, 0xc1, 0x5, 0xbc, 0xcc, 0xca, 0x0,
0xf4, 0x0, 0x7, 0xe0, 0xf, 0x40, 0x0, 0x8c,
0x2, 0xf3, 0x0, 0xa, 0xc0, 0x4f, 0x33, 0x33,
0x96, 0x3, 0xbe, 0xff, 0xff, 0x40,
/* U+39 "9" */
0x0, 0x9b, 0xbb, 0xb7, 0x40, 0x3a, 0xcc, 0xcc,
0xb8, 0x5, 0xf0, 0x0, 0xc, 0x80, 0x8c, 0x0,
0x0, 0xf5, 0x8, 0xc0, 0x0, 0xf, 0x40, 0x98,
0x77, 0x77, 0xb3, 0x0, 0xbc, 0xcc, 0xc7, 0x0,
0x0, 0x0, 0x5, 0xf0, 0x0, 0x0, 0x0, 0x8c,
0x0, 0x0, 0x0, 0x8, 0xc0, 0x2, 0x33, 0x33,
0x98, 0x3, 0xff, 0xff, 0xff, 0x40,
/* U+3A ":" */
0x3, 0x60, 0x7, 0xb1, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x3, 0x10, 0x1f, 0x70
};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 83, .box_h = 2, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 57, .adv_w = 115, .box_h = 12, .box_w = 5, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 87, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 141, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 195, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 243, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 291, .adv_w = 161, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 345, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 393, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 447, .adv_w = 161, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 501, .adv_w = 83, .box_h = 7, .box_w = 4, .ofs_x = 1, .ofs_y = 0}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
//static const uint8_t glyph_id_ofs_list_0[] = {
// 0, 0, 1, 2, 3, 4, 5, 6,
// 7, 8, 9, 10, 11
//};
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
.range_start = 46, .range_length = 13, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL,
.glyph_id_start = 1,
}
};
/*-----------------
* KERNING
*----------------*/
/*Pair left and right glyphs for kerning*/
//static const uint8_t kern_pair_glyph_ids[] =
// {
// 1, 3,
// 1, 6,
// 12, 3
// };
///* Kerning between the respective left and right glyphs
// * 4.4 format which needs to scaled with `kern_scale`*/
//static const int8_t kern_pair_values[] =
// {
// -32, -32, -32
// };
//
///*Collect the kern pair's data in one place*/
//static const lv_font_fmt_txt_kern_pair_t kern_pairs =
// {
// .glyph_ids = kern_pair_glyph_ids,
// .values = kern_pair_values,
// .pair_cnt = 3,
// .glyph_ids_size = 0
// };
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
/*Store all the custom data of the font*/
static lv_font_fmt_txt_dsc_t font_dsc = {
.glyph_bitmap = gylph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.cmap_num = 1,
.bpp = 4,
// .kern_scale = 16,
// .kern_dsc = &kern_pairs,
// .kern_classes = 0
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
const lv_font_t lcd18 = {
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
// .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
// .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.line_height = 13, /*The maximum line height required by the font*/
.base_line = 1, /*Baseline measured from the bottom of the line*/
};
#endif /*#if LCD18*/

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,27 @@
if (TARGET usb_device)
PROJECT(usb_sound_card)
add_executable(usb_sound_card
usb_sound_card.c
)
target_compile_definitions(usb_sound_card PRIVATE
AUDIO_FREQ_MAX=48000
# ours are zero based, so say so
PICO_USBDEV_USE_ZERO_BASED_INTERFACES=1
# need large descriptor
PICO_USBDEV_MAX_DESCRIPTOR_SIZE=256
PICO_USBDEV_ISOCHRONOUS_BUFFER_STRIDE_TYPE=1
PICO_USBDEV_ENABLE_DEBUG_TRAgCE
PICO_AUDIO_I2S_MONO_OUTPUT=0
PICO_AUDIO_I2S_MONO_INPUT=0
)
target_link_libraries(usb_sound_card pico_stdlib usb_device pico_audio_i2s pico_multicore)
pico_add_extra_outputs(usb_sound_card)
endif()

Wyświetl plik

@ -0,0 +1,782 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2020.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2020 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
* \brief Common definitions and declarations for the library USB Audio 1.0 Class driver.
*
* Common definitions and declarations for the library USB Audio 1.0 Class driver.
*
* \note This file should not be included directly. It is automatically included as needed by the USB module driver
* dispatch header located in LUFA/Drivers/USB.h.
*/
/** \ingroup Group_USBClassAudio
* \defgroup Group_USBClassAudioCommon Common Class Definitions
*
* \section Sec_USBClassAudioCommon_ModDescription Module Description
* Constants, Types and Enum definitions that are common to both Device and Host modes for the USB
* Audio 1.0 Class.
*
* @{
*/
#ifndef _AUDIO_CLASS_COMMON_H_
#define _AUDIO_CLASS_COMMON_H_
/* Includes: */
#include "StdDescriptors.h"
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Macros: */
/** \name Audio Channel Masks */
/**@{*/
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_LEFT_FRONT (1 << 0)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_RIGHT_FRONT (1 << 1)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_CENTER_FRONT (1 << 2)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_LOW_FREQ_ENHANCE (1 << 3)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_LEFT_SURROUND (1 << 4)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_RIGHT_SURROUND (1 << 5)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_LEFT_OF_CENTER (1 << 6)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_RIGHT_OF_CENTER (1 << 7)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_SURROUND (1 << 8)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_SIDE_LEFT (1 << 9)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_SIDE_RIGHT (1 << 10)
/** Supported channel mask for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_CHANNEL_TOP (1 << 11)
/**@}*/
/** \name Audio Feature Masks */
/**@{*/
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_MUTE (1 << 0)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_VOLUME (1 << 1)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_BASS (1 << 2)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_MID (1 << 3)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_TREBLE (1 << 4)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_GRAPHIC_EQUALIZER (1 << 5)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_AUTOMATIC_GAIN (1 << 6)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_DELAY (1 << 7)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_BASS_BOOST (1 << 8)
/** Supported feature mask for an Audio class feature unit descriptor. See the Audio class specification for more details. */
#define AUDIO_FEATURE_BASS_LOUDNESS (1 << 9)
/**@}*/
/** \name Audio Terminal Types */
/**@{*/
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_UNDEFINED 0x0100
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_STREAMING 0x0101
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_VENDOR 0x01FF
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_UNDEFINED 0x0200
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_MIC 0x0201
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_DESKTOP_MIC 0x0202
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_PERSONAL_MIC 0x0203
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_OMNIDIR_MIC 0x0204
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_MIC_ARRAY 0x0205
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_PROCESSING_MIC 0x0206
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_IN_OUT_UNDEFINED 0x0300
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_SPEAKER 0x0301
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_HEADPHONES 0x0302
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_HEAD_MOUNTED 0x0303
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_DESKTOP 0x0304
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_ROOM 0x0305
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_COMMUNICATION 0x0306
/** Terminal type constant for an Audio class terminal descriptor. See the Audio class specification for more details. */
#define AUDIO_TERMINAL_OUT_LOWFREQ 0x0307
/**@}*/
/** Convenience macro to fill a 24-bit \ref USB_Audio_SampleFreq_t structure with the given sample rate as a 24-bit number.
*
* \param[in] freq Required audio sampling frequency in HZ
*/
#define AUDIO_SAMPLE_FREQ(freq) {.Byte1 = ((uint32_t)freq & 0xFF), .Byte2 = (((uint32_t)freq >> 8) & 0xFF), .Byte3 = (((uint32_t)freq >> 16) & 0xFF)}
/** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint
* accepts only filled endpoint packets of audio samples.
*/
#define AUDIO_EP_FULL_PACKETS_ONLY (1 << 7)
/** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint
* will accept partially filled endpoint packets of audio samples.
*/
#define AUDIO_EP_ACCEPTS_SMALL_PACKETS (0 << 7)
/** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint
* allows for sampling frequency adjustments to be made via control requests directed at the endpoint.
*/
#define AUDIO_EP_SAMPLE_FREQ_CONTROL (1 << 0)
/** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint
* allows for pitch adjustments to be made via control requests directed at the endpoint.
*/
#define AUDIO_EP_PITCH_CONTROL (1 << 1)
/* Enums: */
/** Enum for possible Class, Subclass and Protocol values of device and interface descriptors relating to the Audio
* device class.
*/
enum Audio_Descriptor_ClassSubclassProtocol_t
{
AUDIO_CSCP_AudioClass = 0x01, /**< Descriptor Class value indicating that the device or
* interface belongs to the USB Audio 1.0 class.
*/
AUDIO_CSCP_ControlSubclass = 0x01, /**< Descriptor Subclass value indicating that the device or
* interface belongs to the Audio Control subclass.
*/
AUDIO_CSCP_ControlProtocol = 0x00, /**< Descriptor Protocol value indicating that the device or
* interface belongs to the Audio Control protocol.
*/
AUDIO_CSCP_AudioStreamingSubclass = 0x02, /**< Descriptor Subclass value indicating that the device or
* interface belongs to the MIDI Streaming subclass.
*/
AUDIO_CSCP_MIDIStreamingSubclass = 0x03, /**< Descriptor Subclass value indicating that the device or
* interface belongs to the Audio streaming subclass.
*/
AUDIO_CSCP_StreamingProtocol = 0x00, /**< Descriptor Protocol value indicating that the device or
* interface belongs to the Streaming Audio protocol.
*/
};
/** Enum for the Audio class specific descriptor types. */
enum AUDIO_DescriptorTypes_t
{
AUDIO_DTYPE_CSInterface = 0x24, /**< Audio class specific Interface functional descriptor. */
AUDIO_DTYPE_CSEndpoint = 0x25, /**< Audio class specific Endpoint functional descriptor. */
};
/** Audio class specific interface description subtypes, for the Audio Control interface. */
enum Audio_CSInterface_AC_SubTypes_t
{
AUDIO_DSUBTYPE_CSInterface_Header = 0x01, /**< Audio class specific control interface header. */
AUDIO_DSUBTYPE_CSInterface_InputTerminal = 0x02, /**< Audio class specific control interface Input Terminal. */
AUDIO_DSUBTYPE_CSInterface_OutputTerminal = 0x03, /**< Audio class specific control interface Output Terminal. */
AUDIO_DSUBTYPE_CSInterface_Mixer = 0x04, /**< Audio class specific control interface Mixer Unit. */
AUDIO_DSUBTYPE_CSInterface_Selector = 0x05, /**< Audio class specific control interface Selector Unit. */
AUDIO_DSUBTYPE_CSInterface_Feature = 0x06, /**< Audio class specific control interface Feature Unit. */
AUDIO_DSUBTYPE_CSInterface_Processing = 0x07, /**< Audio class specific control interface Processing Unit. */
AUDIO_DSUBTYPE_CSInterface_Extension = 0x08, /**< Audio class specific control interface Extension Unit. */
};
/** Audio class specific interface description subtypes, for the Audio Streaming interface. */
enum Audio_CSInterface_AS_SubTypes_t
{
AUDIO_DSUBTYPE_CSInterface_General = 0x01, /**< Audio class specific streaming interface general descriptor. */
AUDIO_DSUBTYPE_CSInterface_FormatType = 0x02, /**< Audio class specific streaming interface format type descriptor. */
AUDIO_DSUBTYPE_CSInterface_FormatSpecific = 0x03, /**< Audio class specific streaming interface format information descriptor. */
};
/** Audio class specific endpoint description subtypes, for the Audio Streaming interface. */
enum Audio_CSEndpoint_SubTypes_t
{
AUDIO_DSUBTYPE_CSEndpoint_General = 0x01, /**< Audio class specific endpoint general descriptor. */
};
/** Enum for the Audio class specific control requests that can be issued by the USB bus host. */
enum Audio_ClassRequests_t
{
AUDIO_REQ_SetCurrent = 0x01, /**< Audio class-specific request to set the current value of a parameter within the device. */
AUDIO_REQ_SetMinimum = 0x02, /**< Audio class-specific request to set the minimum value of a parameter within the device. */
AUDIO_REQ_SetMaximum = 0x03, /**< Audio class-specific request to set the maximum value of a parameter within the device. */
AUDIO_REQ_SetResolution = 0x04, /**< Audio class-specific request to set the resolution value of a parameter within the device. */
AUDIO_REQ_SetMemory = 0x05, /**< Audio class-specific request to set the memory value of a parameter within the device. */
AUDIO_REQ_GetCurrent = 0x81, /**< Audio class-specific request to get the current value of a parameter within the device. */
AUDIO_REQ_GetMinimum = 0x82, /**< Audio class-specific request to get the minimum value of a parameter within the device. */
AUDIO_REQ_GetMaximum = 0x83, /**< Audio class-specific request to get the maximum value of a parameter within the device. */
AUDIO_REQ_GetResolution = 0x84, /**< Audio class-specific request to get the resolution value of a parameter within the device. */
AUDIO_REQ_GetMemory = 0x85, /**< Audio class-specific request to get the memory value of a parameter within the device. */
AUDIO_REQ_GetStatus = 0xFF, /**< Audio class-specific request to get the device status. */
};
/** Enum for Audio class specific Endpoint control modifiers which can be set and retrieved by a USB host, if the corresponding
* endpoint control is indicated to be supported in the Endpoint's Audio-class specific endpoint descriptor.
*/
enum Audio_EndpointControls_t
{
AUDIO_EPCONTROL_SamplingFreq = 0x01, /**< Sampling frequency adjustment of the endpoint. */
AUDIO_EPCONTROL_Pitch = 0x02, /**< Pitch adjustment of the endpoint. */
};
/* Type Defines: */
/** \brief Audio class-specific Input Terminal Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific input terminal descriptor. This indicates to the host that the device
* contains an input audio source, either from a physical terminal on the device, or a logical terminal (for example,
* a USB endpoint). See the USB Audio specification for more details.
*
* \see \ref USB_Audio_StdDescriptor_InputTerminal_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_InputTerminal.
*/
uint8_t TerminalID; /**< ID value of this terminal unit - must be a unique value within the device. */
uint16_t TerminalType; /**< Type of terminal, a \c TERMINAL_* mask. */
uint8_t AssociatedOutputTerminal; /**< ID of associated output terminal, for physically grouped terminals
* such as the speaker and microphone of a phone handset.
*/
uint8_t TotalChannels; /**< Total number of separate audio channels within this interface (right, left, etc.) */
uint16_t ChannelConfig; /**< \c CHANNEL_* masks indicating what channel layout is supported by this terminal. */
uint8_t ChannelStrIndex; /**< Index of a string descriptor describing this channel within the device. */
uint8_t TerminalStrIndex; /**< Index of a string descriptor describing this descriptor within the device. */
} ATTR_PACKED USB_Audio_Descriptor_InputTerminal_t;
/** \brief Audio class-specific Input Terminal Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific input terminal descriptor. This indicates to the host that the device
* contains an input audio source, either from a physical terminal on the device, or a logical terminal (for example,
* a USB endpoint). See the USB Audio specification for more details.
*
* \see \ref USB_Audio_Descriptor_InputTerminal_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bDescriptorSubtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_InputTerminal.
*/
uint8_t bTerminalID; /**< ID value of this terminal unit - must be a unique value within the device. */
uint16_t wTerminalType; /**< Type of terminal, a \c TERMINAL_* mask. */
uint8_t bAssocTerminal; /**< ID of associated output terminal, for physically grouped terminals
* such as the speaker and microphone of a phone handset.
*/
uint8_t bNrChannels; /**< Total number of separate audio channels within this interface (right, left, etc.) */
uint16_t wChannelConfig; /**< \c CHANNEL_* masks indicating what channel layout is supported by this terminal. */
uint8_t iChannelNames; /**< Index of a string descriptor describing this channel within the device. */
uint8_t iTerminal; /**< Index of a string descriptor describing this descriptor within the device. */
} ATTR_PACKED USB_Audio_StdDescriptor_InputTerminal_t;
/** \brief Audio class-specific Output Terminal Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific output terminal descriptor. This indicates to the host that the device
* contains an output audio sink, either to a physical terminal on the device, or a logical terminal (for example,
* a USB endpoint). See the USB Audio specification for more details.
*
* \see \ref USB_Audio_StdDescriptor_OutputTerminal_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_OutputTerminal.
*/
uint8_t TerminalID; /**< ID value of this terminal unit - must be a unique value within the device. */
uint16_t TerminalType; /**< Type of terminal, a \c TERMINAL_* mask. */
uint8_t AssociatedInputTerminal; /**< ID of associated input terminal, for physically grouped terminals
* such as the speaker and microphone of a phone handset.
*/
uint8_t SourceID; /**< ID value of the unit this terminal's audio is sourced from. */
uint8_t TerminalStrIndex; /**< Index of a string descriptor describing this descriptor within the device. */
} ATTR_PACKED USB_Audio_Descriptor_OutputTerminal_t;
/** \brief Audio class-specific Output Terminal Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific output terminal descriptor. This indicates to the host that the device
* contains an output audio sink, either to a physical terminal on the device, or a logical terminal (for example,
* a USB endpoint). See the USB Audio specification for more details.
*
* \see \ref USB_Audio_Descriptor_OutputTerminal_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_OutputTerminal.
*/
uint8_t bDescriptorSubtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSInterface_AC_SubTypes_t enum.
*/
uint8_t bTerminalID; /**< ID value of this terminal unit - must be a unique value within the device. */
uint16_t wTerminalType; /**< Type of terminal, a \c TERMINAL_* mask. */
uint8_t bAssocTerminal; /**< ID of associated input terminal, for physically grouped terminals
* such as the speaker and microphone of a phone handset.
*/
uint8_t bSourceID; /**< ID value of the unit this terminal's audio is sourced from. */
uint8_t iTerminal; /**< Index of a string descriptor describing this descriptor within the device. */
} ATTR_PACKED USB_Audio_StdDescriptor_OutputTerminal_t;
/** \brief Audio class-specific Interface Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific interface descriptor. This follows a regular interface descriptor to
* supply extra information about the audio device's layout to the host. See the USB Audio specification for more
* details.
*
* \see \ref USB_Audio_StdDescriptor_Interface_AC_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSInterface_AS_SubTypes_t enum.
*/
uint16_t ACSpecification; /**< Binary Coded Decimal value, indicating the supported Audio Class specification version.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint16_t TotalLength; /**< Total length of the Audio class-specific descriptors, including this descriptor. */
uint8_t InCollection; /**< Total number of Audio Streaming interfaces linked to this Audio Control interface (must be 1). */
uint8_t InterfaceNumber; /**< Interface number of the associated Audio Streaming interface. */
} ATTR_PACKED USB_Audio_Descriptor_Interface_AC_t;
/** \brief Audio class-specific Interface Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific interface descriptor. This follows a regular interface descriptor to
* supply extra information about the audio device's layout to the host. See the USB Audio specification for more
* details.
*
* \see \ref USB_Audio_Descriptor_Interface_AC_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bDescriptorSubtype;/**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSInterface_AS_SubTypes_t enum.
*/
uint16_t bcdADC; /**< Binary coded decimal value, indicating the supported Audio Class specification version.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint16_t wTotalLength; /**< Total length of the Audio class-specific descriptors, including this descriptor. */
uint8_t bInCollection; /**< Total number of Audio Streaming interfaces linked to this Audio Control interface (must be 1). */
uint8_t bInterfaceNumbers; /**< Interface number of the associated Audio Streaming interface. */
} ATTR_PACKED USB_Audio_StdDescriptor_Interface_AC_t;
/** \brief Audio class-specific Feature Unit Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific Feature Unit descriptor. This indicates to the host what features
* are present in the device's audio stream for basic control, such as per-channel volume. See the USB Audio
* specification for more details.
*
* \see \ref USB_Audio_StdDescriptor_FeatureUnit_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_Feature.
*/
uint8_t UnitID; /**< ID value of this feature unit - must be a unique value within the device. */
uint8_t SourceID; /**< Source ID value of the audio source input into this feature unit. */
uint8_t ControlSize; /**< Size of each element in the \c ChannelControls array. */
uint8_t ChannelControls[3]; /**< Feature masks for the control channel, and each separate audio channel. */
uint8_t FeatureUnitStrIndex; /**< Index of a string descriptor describing this descriptor within the device. */
} ATTR_PACKED USB_Audio_Descriptor_FeatureUnit_t;
/** \brief Audio class-specific Feature Unit Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific Feature Unit descriptor. This indicates to the host what features
* are present in the device's audio stream for basic control, such as per-channel volume. See the USB Audio
* specification for more details.
*
* \see \ref USB_Audio_Descriptor_FeatureUnit_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bDescriptorSubtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_Feature.
*/
uint8_t bUnitID; /**< ID value of this feature unit - must be a unique value within the device. */
uint8_t bSourceID; /**< Source ID value of the audio source input into this feature unit. */
uint8_t bControlSize; /**< Size of each element in the \c ChannelControls array. */
uint8_t bmaControls[3]; /**< Feature masks for the control channel, and each separate audio channel. */
uint8_t iFeature; /**< Index of a string descriptor describing this descriptor within the device. */
} ATTR_PACKED USB_Audio_StdDescriptor_FeatureUnit_t;
/** \brief Audio class-specific Streaming Audio Interface Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific streaming interface descriptor. This indicates to the host
* how audio streams within the device are formatted. See the USB Audio specification for more details.
*
* \see \ref USB_Audio_StdDescriptor_Interface_AS_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSInterface_AS_SubTypes_t enum.
*/
uint8_t TerminalLink; /**< ID value of the output terminal this descriptor is describing. */
uint8_t FrameDelay; /**< Delay in frames resulting from the complete sample processing from input to output. */
uint16_t AudioFormat; /**< Format of the audio stream, see Audio Device Formats specification. */
} ATTR_PACKED USB_Audio_Descriptor_Interface_AS_t;
/** \brief Audio class-specific Streaming Audio Interface Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific streaming interface descriptor. This indicates to the host
* how audio streams within the device are formatted. See the USB Audio specification for more details.
*
* \see \ref USB_Audio_Descriptor_Interface_AS_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bDescriptorSubtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSInterface_AS_SubTypes_t enum.
*/
uint8_t bTerminalLink; /**< ID value of the output terminal this descriptor is describing. */
uint8_t bDelay; /**< Delay in frames resulting from the complete sample processing from input to output. */
uint16_t wFormatTag; /**< Format of the audio stream, see Audio Device Formats specification. */
} ATTR_PACKED USB_Audio_StdDescriptor_Interface_AS_t;
/** \brief Audio class-specific Format Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific audio format descriptor. This is used to give the host full details
* about the number of channels, the sample resolution, acceptable sample frequencies and encoding method used
* in the device's audio streams. See the USB Audio specification for more details.
*
* \attention This descriptor <b>must</b> be followed by one or more \ref USB_Audio_SampleFreq_t elements containing
* the continuous or discrete sample frequencies.
*
* \see \ref USB_Audio_StdDescriptor_Format_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_FormatType.
*/
uint8_t FormatType; /**< Format of the audio stream, see Audio Device Formats specification. */
uint8_t Channels; /**< Total number of discrete channels in the stream. */
uint8_t SubFrameSize; /**< Size in bytes of each channel's sample data in the stream. */
uint8_t BitResolution; /**< Bits of resolution of each channel's samples in the stream. */
uint8_t TotalDiscreteSampleRates; /**< Total number of discrete sample frequencies supported by the device. When
* zero, this must be followed by the lower and upper continuous sampling
* frequencies supported by the device; otherwise, this must be followed
* by the given number of discrete sampling frequencies supported.
*/
} ATTR_PACKED USB_Audio_Descriptor_Format_t;
/** \brief 24-Bit Audio Frequency Structure.
*
* Type define for a 24-bit audio sample frequency structure. As GCC does not contain a built in 24-bit datatype,
* this this structure is used to build up the value instead. Fill this structure with the \ref AUDIO_SAMPLE_FREQ() macro.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t Byte1; /**< Lowest 8 bits of the 24-bit value. */
uint8_t Byte2; /**< Middle 8 bits of the 24-bit value. */
uint8_t Byte3; /**< Upper 8 bits of the 24-bit value. */
} ATTR_PACKED USB_Audio_SampleFreq_t;
/** \brief Audio class-specific Format Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific audio format descriptor. This is used to give the host full details
* about the number of channels, the sample resolution, acceptable sample frequencies and encoding method used
* in the device's audio streams. See the USB Audio specification for more details.
*
* \attention This descriptor <b>must</b> be followed by one or more 24-bit integer elements containing the continuous
* or discrete sample frequencies.
*
* \see \ref USB_Audio_Descriptor_Format_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Sub type value used to distinguish between audio class-specific descriptors,
* must be \ref AUDIO_DSUBTYPE_CSInterface_FormatType.
*/
uint8_t bDescriptorSubtype;/**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSInterface_AS_SubTypes_t enum.
*/
uint8_t bFormatType; /**< Format of the audio stream, see Audio Device Formats specification. */
uint8_t bNrChannels; /**< Total number of discrete channels in the stream. */
uint8_t bSubFrameSize; /**< Size in bytes of each channel's sample data in the stream. */
uint8_t bBitResolution; /**< Bits of resolution of each channel's samples in the stream. */
uint8_t bSampleFrequencyType; /**< Total number of sample frequencies supported by the device. When
* zero, this must be followed by the lower and upper continuous sampling
* frequencies supported by the device; otherwise, this must be followed
* by the given number of discrete sampling frequencies supported.
*/
} ATTR_PACKED USB_Audio_StdDescriptor_Format_t;
/** \brief Audio class-specific Streaming Endpoint Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific endpoint descriptor. This contains a regular endpoint
* descriptor with a few Audio-class-specific extensions. See the USB Audio specification for more details.
*
* \see \ref USB_Audio_StdDescriptor_StreamEndpoint_Std_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Endpoint_t Endpoint; /**< Standard endpoint descriptor describing the audio endpoint. */
uint8_t Refresh; /**< Always set to zero for Audio class devices. */
uint8_t SyncEndpointNumber; /**< Endpoint address to send synchronization information to, if needed (zero otherwise). */
} ATTR_PACKED USB_Audio_Descriptor_StreamEndpoint_Std_t;
/** \brief Audio class-specific Streaming Endpoint Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific endpoint descriptor. This contains a regular endpoint
* descriptor with a few Audio-class-specific extensions. See the USB Audio specification for more details.
*
* \see \ref USB_Audio_Descriptor_StreamEndpoint_Std_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a
* value given by the specific class.
*/
uint8_t bEndpointAddress; /**< Logical address of the endpoint within the device for the current
* configuration, including direction mask.
*/
uint8_t bmAttributes; /**< Endpoint attributes, comprised of a mask of the endpoint type (\c EP_TYPE_*)
* and attributes (\c ENDPOINT_ATTR_*) masks.
*/
uint16_t wMaxPacketSize; /**< Size of the endpoint bank, in bytes. This indicates the maximum packet size
* that the endpoint can receive at a time.
*/
uint8_t bInterval; /**< Polling interval in milliseconds for the endpoint if it is an INTERRUPT or
* ISOCHRONOUS type.
*/
uint8_t bRefresh; /**< Always set to zero for Audio class devices. */
uint8_t bSynchAddress; /**< Endpoint address to send synchronization information to, if needed (zero otherwise). */
} ATTR_PACKED USB_Audio_StdDescriptor_StreamEndpoint_Std_t;
/** \brief Audio class-specific Extended Endpoint Descriptor (LUFA naming conventions).
*
* Type define for an Audio class-specific extended endpoint descriptor. This contains extra information
* on the usage of endpoints used to stream audio in and out of the USB Audio device, and follows an Audio
* class-specific extended endpoint descriptor. See the USB Audio specification for more details.
*
* \see \ref USB_Audio_StdDescriptor_StreamEndpoint_Spc_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Regular descriptor header containing the descriptor's type and length. */
uint8_t Subtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSEndpoint_SubTypes_t enum.
*/
uint8_t Attributes; /**< Audio class-specific endpoint attributes, such as \ref AUDIO_EP_FULL_PACKETS_ONLY. */
uint8_t LockDelayUnits; /**< Units used for the LockDelay field, see Audio class specification. */
uint16_t LockDelay; /**< Time required to internally lock endpoint's internal clock recovery circuitry. */
} ATTR_PACKED USB_Audio_Descriptor_StreamEndpoint_Spc_t;
/** \brief Audio class-specific Extended Endpoint Descriptor (USB-IF naming conventions).
*
* Type define for an Audio class-specific extended endpoint descriptor. This contains extra information
* on the usage of endpoints used to stream audio in and out of the USB Audio device, and follows an Audio
* class-specific extended endpoint descriptor. See the USB Audio specification for more details.
*
* \see \ref USB_Audio_Descriptor_StreamEndpoint_Spc_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bDescriptorSubtype; /**< Sub type value used to distinguish between audio class-specific descriptors,
* a value from the \ref Audio_CSEndpoint_SubTypes_t enum.
*/
uint8_t bmAttributes; /**< Audio class-specific endpoint attributes, such as \ref AUDIO_EP_FULL_PACKETS_ONLY. */
uint8_t bLockDelayUnits; /**< Units used for the LockDelay field, see Audio class specification. */
uint16_t wLockDelay; /**< Time required to internally lock endpoint's internal clock recovery circuitry. */
} ATTR_PACKED USB_Audio_StdDescriptor_StreamEndpoint_Spc_t;
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

Wyświetl plik

@ -0,0 +1,24 @@
LUFA Library
Copyright (C) Dean Camera, 2020.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose is hereby granted without
fee, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.

Wyświetl plik

@ -0,0 +1,765 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2020.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2020 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaims all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
* \brief Common standard USB Descriptor definitions for all architectures.
* \copydetails Group_StdDescriptors
*
* \note This file should not be included directly. It is automatically included as needed by the USB driver
* dispatch header located in LUFA/Drivers/USB/USB.h.
*/
/** \ingroup Group_USB
* \defgroup Group_StdDescriptors USB Descriptors
* \brief Standard USB Descriptor definitions.
*
* Standard USB device descriptor defines and retrieval routines, for USB devices. This module contains
* structures and macros for the easy creation of standard USB descriptors in USB device projects.
*
* @{
*/
#ifndef __USBDESCRIPTORS_H__
#define __USBDESCRIPTORS_H__
/* Includes: */
#define ATTR_PACKED __packed
#define CPU_TO_LE16(x) (x)
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** Indicates that a given descriptor does not exist in the device. This can be used inside descriptors
* for string descriptor indexes, or may be use as a return value for GetDescriptor when the specified
* descriptor does not exist.
*/
#define NO_DESCRIPTOR 0
/** Macro to calculate the power value for the configuration descriptor, from a given number of milliamperes.
*
* \param[in] mA Maximum number of milliamps the device consumes when the given configuration is selected.
*/
#define USB_CONFIG_POWER_MA(mA) ((mA) >> 1)
/** Macro to calculate the Unicode length of a string with a given number of Unicode characters.
* Should be used in string descriptor's headers for giving the string descriptor's byte length.
*
* \param[in] UnicodeChars Number of Unicode characters in the string text.
*/
#define USB_STRING_LEN(UnicodeChars) (sizeof(USB_Descriptor_Header_t) + ((UnicodeChars) << 1))
/** Convenience macro to easily create \ref USB_Descriptor_String_t instances from a wide character string.
*
* \note This macro is for little-endian systems only.
*
* \param[in] String String to initialize a USB String Descriptor structure with.
*/
#define USB_STRING_DESCRIPTOR(String) { .Header = {.Size = sizeof(USB_Descriptor_Header_t) + (sizeof(String) - 2), .Type = DTYPE_String}, .UnicodeString = String }
/** Convenience macro to easily create \ref USB_Descriptor_String_t instances from an array of characters.
*
* \param[in] ... Characters to initialize a USB String Descriptor structure with.
*/
#define USB_STRING_DESCRIPTOR_ARRAY(...) { .Header = {.Size = sizeof(USB_Descriptor_Header_t) + sizeof((uint16_t[]){__VA_ARGS__}), .Type = DTYPE_String}, .UnicodeString = {__VA_ARGS__} }
/** Macro to encode a given major/minor/revision version number into Binary Coded Decimal format for descriptor
* fields requiring BCD encoding, such as the USB version number in the standard device descriptor.
*
* \note This value is automatically converted into Little Endian, suitable for direct use inside device
* descriptors on all architectures without endianness conversion macros.
*
* \param[in] Major Major version number to encode.
* \param[in] Minor Minor version number to encode.
* \param[in] Revision Revision version number to encode.
*/
#define VERSION_BCD(Major, Minor, Revision) \
CPU_TO_LE16( ((Major & 0xFF) << 8) | \
((Minor & 0x0F) << 4) | \
(Revision & 0x0F) )
/** String language ID for the English language. Should be used in \ref USB_Descriptor_String_t descriptors
* to indicate that the English language is supported by the device in its string descriptors.
*/
#define LANGUAGE_ID_ENG 0x0409
/** \name USB Configuration Descriptor Attribute Masks */
/**@{*/
/** Mask for the reserved bit in the Configuration Descriptor's \c ConfigAttributes field, which must be always
* set on all USB devices for historical purposes.
*/
#define USB_CONFIG_ATTR_RESERVED 0x80
/** Can be masked with other configuration descriptor attributes for a \ref USB_Descriptor_Configuration_Header_t
* descriptor's \c ConfigAttributes value to indicate that the specified configuration can draw its power
* from the device's own power source, instead of drawing it from the USB host.
*
* Note that the host will probe this dynamically - the device should report its current power state via the
* \ref USB_Device_CurrentlySelfPowered global variable.
*/
#define USB_CONFIG_ATTR_SELFPOWERED 0x40
/** Can be masked with other configuration descriptor attributes for a \ref USB_Descriptor_Configuration_Header_t
* descriptor's \c ConfigAttributes value to indicate that the specified configuration supports the
* remote wakeup feature of the USB standard, allowing a suspended USB device to wake up the host upon
* request.
*
* If set, the host will dynamically enable and disable remote wakeup support, indicated via the
* \ref USB_Device_RemoteWakeupEnabled global variable. To initiate a remote wakeup of the host (when allowed)
* see \ref USB_Device_RemoteWakeupEnabled().
*/
#define USB_CONFIG_ATTR_REMOTEWAKEUP 0x20
/**@}*/
/** \name Endpoint Descriptor Attribute Masks */
/**@{*/
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is not synchronized.
*
* \see The USB specification for more details on the possible Endpoint attributes.
*/
#define ENDPOINT_ATTR_NO_SYNC (0 << 2)
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is asynchronous.
*
* \see The USB specification for more details on the possible Endpoint attributes.
*/
#define ENDPOINT_ATTR_ASYNC (1 << 2)
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is adaptive.
*
* \see The USB specification for more details on the possible Endpoint attributes.
*/
#define ENDPOINT_ATTR_ADAPTIVE (2 << 2)
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is synchronized.
*
* \see The USB specification for more details on the possible Endpoint attributes.
*/
#define ENDPOINT_ATTR_SYNC (3 << 2)
/**@}*/
/** \name Endpoint Descriptor Usage Masks */
/**@{*/
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is used for data transfers.
*
* \see The USB specification for more details on the possible Endpoint usage attributes.
*/
#define ENDPOINT_USAGE_DATA (0 << 4)
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is used for feedback.
*
* \see The USB specification for more details on the possible Endpoint usage attributes.
*/
#define ENDPOINT_USAGE_FEEDBACK (1 << 4)
/** Can be masked with other endpoint descriptor attributes for a \ref USB_Descriptor_Endpoint_t descriptor's
* \c Attributes value to indicate that the specified endpoint is used for implicit feedback.
*
* \see The USB specification for more details on the possible Endpoint usage attributes.
*/
#define ENDPOINT_USAGE_IMPLICIT_FEEDBACK (2 << 4)
/**@}*/
/* Enums: */
/** Enum for the possible standard descriptor types, as given in each descriptor's header. */
enum USB_DescriptorTypes_t
{
DTYPE_Device = 0x01, /**< Indicates that the descriptor is a device descriptor. */
DTYPE_Configuration = 0x02, /**< Indicates that the descriptor is a configuration descriptor. */
DTYPE_String = 0x03, /**< Indicates that the descriptor is a string descriptor. */
DTYPE_Interface = 0x04, /**< Indicates that the descriptor is an interface descriptor. */
DTYPE_Endpoint = 0x05, /**< Indicates that the descriptor is an endpoint descriptor. */
DTYPE_DeviceQualifier = 0x06, /**< Indicates that the descriptor is a device qualifier descriptor. */
DTYPE_Other = 0x07, /**< Indicates that the descriptor is of other type. */
DTYPE_InterfacePower = 0x08, /**< Indicates that the descriptor is an interface power descriptor. */
DTYPE_InterfaceAssociation = 0x0B, /**< Indicates that the descriptor is an interface association descriptor. */
};
/** Enum for possible Class, Subclass and Protocol values of device and interface descriptors. */
enum USB_Descriptor_ClassSubclassProtocol_t
{
USB_CSCP_NoDeviceClass = 0x00, /**< Descriptor Class value indicating that the device does not belong
* to a particular class at the device level.
*/
USB_CSCP_NoDeviceSubclass = 0x00, /**< Descriptor Subclass value indicating that the device does not belong
* to a particular subclass at the device level.
*/
USB_CSCP_NoDeviceProtocol = 0x00, /**< Descriptor Protocol value indicating that the device does not belong
* to a particular protocol at the device level.
*/
USB_CSCP_VendorSpecificClass = 0xFF, /**< Descriptor Class value indicating that the device/interface belongs
* to a vendor specific class.
*/
USB_CSCP_VendorSpecificSubclass = 0xFF, /**< Descriptor Subclass value indicating that the device/interface belongs
* to a vendor specific subclass.
*/
USB_CSCP_VendorSpecificProtocol = 0xFF, /**< Descriptor Protocol value indicating that the device/interface belongs
* to a vendor specific protocol.
*/
USB_CSCP_IADDeviceClass = 0xEF, /**< Descriptor Class value indicating that the device belongs to the
* Interface Association Descriptor class.
*/
USB_CSCP_IADDeviceSubclass = 0x02, /**< Descriptor Subclass value indicating that the device belongs to the
* Interface Association Descriptor subclass.
*/
USB_CSCP_IADDeviceProtocol = 0x01, /**< Descriptor Protocol value indicating that the device belongs to the
* Interface Association Descriptor protocol.
*/
};
/* Type Defines: */
/** \brief Standard USB Descriptor Header (LUFA naming conventions).
*
* Type define for all descriptors' standard header, indicating the descriptor's length and type. This structure
* uses LUFA-specific element names to make each element's purpose clearer.
*
* \see \ref USB_StdDescriptor_Header_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t Size; /**< Size of the descriptor, in bytes. */
uint8_t Type; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
} ATTR_PACKED USB_Descriptor_Header_t;
/** \brief Standard USB Descriptor Header (USB-IF naming conventions).
*
* Type define for all descriptors' standard header, indicating the descriptor's length and type. This structure
* uses the relevant standard's given element names to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_Header_t for the version of this type with non-standard LUFA specific element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
} ATTR_PACKED USB_StdDescriptor_Header_t;
/** \brief Standard USB Device Descriptor (LUFA naming conventions).
*
* Type define for a standard Device Descriptor. This structure uses LUFA-specific element names to make each
* element's purpose clearer.
*
* \see \ref USB_StdDescriptor_Device_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
uint16_t USBSpecification; /**< BCD of the supported USB specification.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint8_t Class; /**< USB device class. */
uint8_t SubClass; /**< USB device subclass. */
uint8_t Protocol; /**< USB device protocol. */
uint8_t Endpoint0Size; /**< Size of the control (address 0) endpoint's bank in bytes. */
uint16_t VendorID; /**< Vendor ID for the USB product. */
uint16_t ProductID; /**< Unique product ID for the USB product. */
uint16_t ReleaseNumber; /**< Product release (version) number.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint8_t ManufacturerStrIndex; /**< String index for the manufacturer's name. The
* host will request this string via a separate
* control request for the string descriptor.
*
* \note If no string supplied, use \ref NO_DESCRIPTOR.
*/
uint8_t ProductStrIndex; /**< String index for the product name/details.
*
* \see ManufacturerStrIndex structure entry.
*/
uint8_t SerialNumStrIndex; /**< String index for the product's globally unique hexadecimal
* serial number, in uppercase Unicode ASCII.
*
* \note On some microcontroller models, there is an embedded serial number
* in the chip which can be used for the device serial number.
* To use this serial number, set this to \c USE_INTERNAL_SERIAL.
* On unsupported devices, this will evaluate to \ref NO_DESCRIPTOR
* and will cause the host to generate a pseudo-unique value for the
* device upon insertion.
*
* \see \c ManufacturerStrIndex structure entry.
*/
uint8_t NumberOfConfigurations; /**< Total number of configurations supported by
* the device.
*/
} ATTR_PACKED USB_Descriptor_Device_t;
/** \brief Standard USB Device Descriptor (USB-IF naming conventions).
*
* Type define for a standard Device Descriptor. This structure uses the relevant standard's given element names
* to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_Device_t for the version of this type with non-standard LUFA specific element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint16_t bcdUSB; /**< BCD of the supported USB specification.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint8_t bDeviceClass; /**< USB device class. */
uint8_t bDeviceSubClass; /**< USB device subclass. */
uint8_t bDeviceProtocol; /**< USB device protocol. */
uint8_t bMaxPacketSize0; /**< Size of the control (address 0) endpoint's bank in bytes. */
uint16_t idVendor; /**< Vendor ID for the USB product. */
uint16_t idProduct; /**< Unique product ID for the USB product. */
uint16_t bcdDevice; /**< Product release (version) number.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint8_t iManufacturer; /**< String index for the manufacturer's name. The
* host will request this string via a separate
* control request for the string descriptor.
*
* \note If no string supplied, use \ref NO_DESCRIPTOR.
*/
uint8_t iProduct; /**< String index for the product name/details.
*
* \see ManufacturerStrIndex structure entry.
*/
uint8_t iSerialNumber; /**< String index for the product's globally unique hexadecimal
* serial number, in uppercase Unicode ASCII.
*
* \note On some microcontroller models, there is an embedded serial number
* in the chip which can be used for the device serial number.
* To use this serial number, set this to \c USE_INTERNAL_SERIAL.
* On unsupported devices, this will evaluate to \ref NO_DESCRIPTOR
* and will cause the host to generate a pseudo-unique value for the
* device upon insertion.
*
* \see \c ManufacturerStrIndex structure entry.
*/
uint8_t bNumConfigurations; /**< Total number of configurations supported by
* the device.
*/
} ATTR_PACKED USB_StdDescriptor_Device_t;
/** \brief Standard USB Device Qualifier Descriptor (LUFA naming conventions).
*
* Type define for a standard Device Qualifier Descriptor. This structure uses LUFA-specific element names
* to make each element's purpose clearer.
*
* \see \ref USB_StdDescriptor_DeviceQualifier_t for the version of this type with standard element names.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
uint16_t USBSpecification; /**< BCD of the supported USB specification.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint8_t Class; /**< USB device class. */
uint8_t SubClass; /**< USB device subclass. */
uint8_t Protocol; /**< USB device protocol. */
uint8_t Endpoint0Size; /**< Size of the control (address 0) endpoint's bank in bytes. */
uint8_t NumberOfConfigurations; /**< Total number of configurations supported by
* the device.
*/
uint8_t Reserved; /**< Reserved for future use, must be 0. */
} ATTR_PACKED USB_Descriptor_DeviceQualifier_t;
/** \brief Standard USB Device Qualifier Descriptor (USB-IF naming conventions).
*
* Type define for a standard Device Qualifier Descriptor. This structure uses the relevant standard's given element names
* to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_DeviceQualifier_t for the version of this type with non-standard LUFA specific element names.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint16_t bcdUSB; /**< BCD of the supported USB specification.
*
* \see \ref VERSION_BCD() utility macro.
*/
uint8_t bDeviceClass; /**< USB device class. */
uint8_t bDeviceSubClass; /**< USB device subclass. */
uint8_t bDeviceProtocol; /**< USB device protocol. */
uint8_t bMaxPacketSize0; /**< Size of the control (address 0) endpoint's bank in bytes. */
uint8_t bNumConfigurations; /**< Total number of configurations supported by
* the device.
*/
uint8_t bReserved; /**< Reserved for future use, must be 0. */
} ATTR_PACKED USB_StdDescriptor_DeviceQualifier_t;
/** \brief Standard USB Configuration Descriptor (LUFA naming conventions).
*
* Type define for a standard Configuration Descriptor header. This structure uses LUFA-specific element names
* to make each element's purpose clearer.
*
* \see \ref USB_StdDescriptor_Configuration_Header_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
uint16_t TotalConfigurationSize; /**< Size of the configuration descriptor header,
* and all sub descriptors inside the configuration.
*/
uint8_t TotalInterfaces; /**< Total number of interfaces in the configuration. */
uint8_t ConfigurationNumber; /**< Configuration index of the current configuration. */
uint8_t ConfigurationStrIndex; /**< Index of a string descriptor describing the configuration. */
uint8_t ConfigAttributes; /**< Configuration attributes, comprised of a mask of \c USB_CONFIG_ATTR_* masks.
* On all devices, this should include USB_CONFIG_ATTR_RESERVED at a minimum.
*/
uint8_t MaxPowerConsumption; /**< Maximum power consumption of the device while in the
* current configuration, calculated by the \ref USB_CONFIG_POWER_MA()
* macro.
*/
} ATTR_PACKED USB_Descriptor_Configuration_Header_t;
/** \brief Standard USB Configuration Descriptor (USB-IF naming conventions).
*
* Type define for a standard Configuration Descriptor header. This structure uses the relevant standard's given element names
* to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_Device_t for the version of this type with non-standard LUFA specific element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint16_t wTotalLength; /**< Size of the configuration descriptor header,
* and all sub descriptors inside the configuration.
*/
uint8_t bNumInterfaces; /**< Total number of interfaces in the configuration. */
uint8_t bConfigurationValue; /**< Configuration index of the current configuration. */
uint8_t iConfiguration; /**< Index of a string descriptor describing the configuration. */
uint8_t bmAttributes; /**< Configuration attributes, comprised of a mask of \c USB_CONFIG_ATTR_* masks.
* On all devices, this should include USB_CONFIG_ATTR_RESERVED at a minimum.
*/
uint8_t bMaxPower; /**< Maximum power consumption of the device while in the
* current configuration, calculated by the \ref USB_CONFIG_POWER_MA()
* macro.
*/
} ATTR_PACKED USB_StdDescriptor_Configuration_Header_t;
/** \brief Standard USB Interface Descriptor (LUFA naming conventions).
*
* Type define for a standard Interface Descriptor. This structure uses LUFA-specific element names
* to make each element's purpose clearer.
*
* \see \ref USB_StdDescriptor_Interface_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
uint8_t InterfaceNumber; /**< Index of the interface in the current configuration. */
uint8_t AlternateSetting; /**< Alternate setting for the interface number. The same
* interface number can have multiple alternate settings
* with different endpoint configurations, which can be
* selected by the host.
*/
uint8_t TotalEndpoints; /**< Total number of endpoints in the interface. */
uint8_t Class; /**< Interface class ID. */
uint8_t SubClass; /**< Interface subclass ID. */
uint8_t Protocol; /**< Interface protocol ID. */
uint8_t InterfaceStrIndex; /**< Index of the string descriptor describing the interface. */
} ATTR_PACKED USB_Descriptor_Interface_t;
/** \brief Standard USB Interface Descriptor (USB-IF naming conventions).
*
* Type define for a standard Interface Descriptor. This structure uses the relevant standard's given element names
* to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_Interface_t for the version of this type with non-standard LUFA specific element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bInterfaceNumber; /**< Index of the interface in the current configuration. */
uint8_t bAlternateSetting; /**< Alternate setting for the interface number. The same
* interface number can have multiple alternate settings
* with different endpoint configurations, which can be
* selected by the host.
*/
uint8_t bNumEndpoints; /**< Total number of endpoints in the interface. */
uint8_t bInterfaceClass; /**< Interface class ID. */
uint8_t bInterfaceSubClass; /**< Interface subclass ID. */
uint8_t bInterfaceProtocol; /**< Interface protocol ID. */
uint8_t iInterface; /**< Index of the string descriptor describing the
* interface.
*/
} ATTR_PACKED USB_StdDescriptor_Interface_t;
/** \brief Standard USB Interface Association Descriptor (LUFA naming conventions).
*
* Type define for a standard Interface Association Descriptor. This structure uses LUFA-specific element names
* to make each element's purpose clearer.
*
* This descriptor has been added as a supplement to the USB2.0 standard, in the ECN located at
* <a>http://www.usb.org/developers/docs/InterfaceAssociationDescriptor_ecn.pdf</a>. It allows composite
* devices with multiple interfaces related to the same function to have the multiple interfaces bound
* together at the point of enumeration, loading one generic driver for all the interfaces in the single
* function. Read the ECN for more information.
*
* \see \ref USB_StdDescriptor_Interface_Association_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
uint8_t FirstInterfaceIndex; /**< Index of the first associated interface. */
uint8_t TotalInterfaces; /**< Total number of associated interfaces. */
uint8_t Class; /**< Interface class ID. */
uint8_t SubClass; /**< Interface subclass ID. */
uint8_t Protocol; /**< Interface protocol ID. */
uint8_t IADStrIndex; /**< Index of the string descriptor describing the
* interface association.
*/
} ATTR_PACKED USB_Descriptor_Interface_Association_t;
/** \brief Standard USB Interface Association Descriptor (USB-IF naming conventions).
*
* Type define for a standard Interface Association Descriptor. This structure uses the relevant standard's given
* element names to ensure compatibility with the standard.
*
* This descriptor has been added as a supplement to the USB2.0 standard, in the ECN located at
* <a>http://www.usb.org/developers/docs/InterfaceAssociationDescriptor_ecn.pdf</a>. It allows composite
* devices with multiple interfaces related to the same function to have the multiple interfaces bound
* together at the point of enumeration, loading one generic driver for all the interfaces in the single
* function. Read the ECN for more information.
*
* \see \ref USB_Descriptor_Interface_Association_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class.
*/
uint8_t bFirstInterface; /**< Index of the first associated interface. */
uint8_t bInterfaceCount; /**< Total number of associated interfaces. */
uint8_t bFunctionClass; /**< Interface class ID. */
uint8_t bFunctionSubClass; /**< Interface subclass ID. */
uint8_t bFunctionProtocol; /**< Interface protocol ID. */
uint8_t iFunction; /**< Index of the string descriptor describing the
* interface association.
*/
} ATTR_PACKED USB_StdDescriptor_Interface_Association_t;
/** \brief Standard USB Endpoint Descriptor (LUFA naming conventions).
*
* Type define for a standard Endpoint Descriptor. This structure uses LUFA-specific element names
* to make each element's purpose clearer.
*
* \see \ref USB_StdDescriptor_Endpoint_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
uint8_t EndpointAddress; /**< Logical address of the endpoint within the device for the current
* configuration, including direction mask.
*/
uint8_t Attributes; /**< Endpoint attributes, comprised of a mask of the endpoint type (EP_TYPE_*)
* and attributes (ENDPOINT_ATTR_*) masks.
*/
uint16_t EndpointSize; /**< Size of the endpoint bank, in bytes. This indicates the maximum packet
* size that the endpoint can receive at a time.
*/
uint8_t PollingIntervalMS; /**< Polling interval in milliseconds for the endpoint if it is an INTERRUPT
* or ISOCHRONOUS type.
*/
} ATTR_PACKED USB_Descriptor_Endpoint_t;
/** \brief Standard USB Endpoint Descriptor (USB-IF naming conventions).
*
* Type define for a standard Endpoint Descriptor. This structure uses the relevant standard's given
* element names to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_Endpoint_t for the version of this type with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a
* value given by the specific class.
*/
uint8_t bEndpointAddress; /**< Logical address of the endpoint within the device for the current
* configuration, including direction mask.
*/
uint8_t bmAttributes; /**< Endpoint attributes, comprised of a mask of the endpoint type (EP_TYPE_*)
* and attributes (ENDPOINT_ATTR_*) masks.
*/
uint16_t wMaxPacketSize; /**< Size of the endpoint bank, in bytes. This indicates the maximum packet size
* that the endpoint can receive at a time.
*/
uint8_t bInterval; /**< Polling interval in milliseconds for the endpoint if it is an INTERRUPT or
* ISOCHRONOUS type.
*/
} ATTR_PACKED USB_StdDescriptor_Endpoint_t;
/** \brief Standard USB String Descriptor (LUFA naming conventions).
*
* Type define for a standard string descriptor. Unlike other standard descriptors, the length
* of the descriptor for placement in the descriptor header must be determined by the \ref USB_STRING_LEN()
* macro rather than by the size of the descriptor structure, as the length is not fixed.
*
* This structure should also be used for string index 0, which contains the supported language IDs for
* the device as an array.
*
* This structure uses LUFA-specific element names to make each element's purpose clearer.
*
* \see \ref USB_StdDescriptor_String_t for the version of this type with standard element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */
#if (((ARCH == ARCH_AVR8) || (ARCH == ARCH_XMEGA)) && !defined(__DOXYGEN__))
wchar_t UnicodeString[];
#else
uint16_t UnicodeString[]; /**< String data, as unicode characters (alternatively,
* string language IDs). If normal ASCII characters are
* to be used, they must be added as an array of characters
* rather than a normal C string so that they are widened to
* Unicode size.
*
* Under GCC, strings prefixed with the "L" character (before
* the opening string quotation mark) are considered to be
* Unicode strings, and may be used instead of an explicit
* array of ASCII characters on little endian devices with
* UTF-16-LE \c wchar_t encoding.
*/
#endif
} ATTR_PACKED USB_Descriptor_String_t;
/** \brief Standard USB String Descriptor (USB-IF naming conventions).
*
* Type define for a standard string descriptor. Unlike other standard descriptors, the length
* of the descriptor for placement in the descriptor header must be determined by the \ref USB_STRING_LEN()
* macro rather than by the size of the descriptor structure, as the length is not fixed.
*
* This structure should also be used for string index 0, which contains the supported language IDs for
* the device as an array.
*
* This structure uses the relevant standard's given element names to ensure compatibility with the standard.
*
* \see \ref USB_Descriptor_String_t for the version of this type with with non-standard LUFA specific
* element names.
*
* \note Regardless of CPU architecture, these values should be stored as little endian.
*/
typedef struct
{
uint8_t bLength; /**< Size of the descriptor, in bytes. */
uint8_t bDescriptorType; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t
* or a value given by the specific class.
*/
uint16_t bString[]; /**< String data, as unicode characters (alternatively, string language IDs).
* If normal ASCII characters are to be used, they must be added as an array
* of characters rather than a normal C string so that they are widened to
* Unicode size.
*
* Under GCC, strings prefixed with the "L" character (before the opening string
* quotation mark) are considered to be Unicode strings, and may be used instead
* of an explicit array of ASCII characters.
*/
} ATTR_PACKED USB_StdDescriptor_String_t;
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

Wyświetl plik

@ -0,0 +1,638 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/usb_device.h"
#include "pico/audio.h"
#include "pico/audio_i2s.h"
#include "pico/multicore.h"
#include "lufa/AudioClassCommon.h"
// todo forget why this is using core 1 for sound: presumably not necessary
// todo noop when muted
CU_REGISTER_DEBUG_PINS(audio_timing)
// ---- select at most one ---
//CU_SELECT_DEBUG_PINS(audio_timing)
// todo make descriptor strings should probably belong to the configs
static char *descriptor_strings[] =
{
"Raspberry Pi",
"Pico Examples Sound Card",
"0123456789AB"
};
// todo fix these
#define VENDOR_ID 0x2e8au
#define PRODUCT_ID 0xfeddu
#define AUDIO_OUT_ENDPOINT 0x01U
#define AUDIO_IN_ENDPOINT 0x82U
#undef AUDIO_SAMPLE_FREQ
#define AUDIO_SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
#define AUDIO_MAX_PACKET_SIZE(freq) (uint8_t)(((freq + 999) / 1000) * 4)
#define FEATURE_MUTE_CONTROL 1u
#define FEATURE_VOLUME_CONTROL 2u
#define ENDPOINT_FREQ_CONTROL 1u
struct audio_device_config {
struct usb_configuration_descriptor descriptor;
struct usb_interface_descriptor ac_interface;
struct __packed {
USB_Audio_StdDescriptor_Interface_AC_t core;
USB_Audio_StdDescriptor_InputTerminal_t input_terminal;
USB_Audio_StdDescriptor_FeatureUnit_t feature_unit;
USB_Audio_StdDescriptor_OutputTerminal_t output_terminal;
} ac_audio;
struct usb_interface_descriptor as_zero_interface;
struct usb_interface_descriptor as_op_interface;
struct __packed {
USB_Audio_StdDescriptor_Interface_AS_t streaming;
struct __packed {
USB_Audio_StdDescriptor_Format_t core;
USB_Audio_SampleFreq_t freqs[2];
} format;
} as_audio;
struct __packed {
struct usb_endpoint_descriptor_long core;
USB_Audio_StdDescriptor_StreamEndpoint_Spc_t audio;
} ep1;
struct usb_endpoint_descriptor_long ep2;
};
static const struct audio_device_config audio_device_config = {
.descriptor = {
.bLength = sizeof(audio_device_config.descriptor),
.bDescriptorType = DTYPE_Configuration,
.wTotalLength = sizeof(audio_device_config),
.bNumInterfaces = 2,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = 0x80,
.bMaxPower = 0x32,
},
.ac_interface = {
.bLength = sizeof(audio_device_config.ac_interface),
.bDescriptorType = DTYPE_Interface,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x00,
.bInterfaceClass = AUDIO_CSCP_AudioClass,
.bInterfaceSubClass = AUDIO_CSCP_ControlSubclass,
.bInterfaceProtocol = AUDIO_CSCP_ControlProtocol,
.iInterface = 0x00,
},
.ac_audio = {
.core = {
.bLength = sizeof(audio_device_config.ac_audio.core),
.bDescriptorType = AUDIO_DTYPE_CSInterface,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_Header,
.bcdADC = VERSION_BCD(1, 0, 0),
.wTotalLength = sizeof(audio_device_config.ac_audio),
.bInCollection = 1,
.bInterfaceNumbers = 1,
},
.input_terminal = {
.bLength = sizeof(audio_device_config.ac_audio.input_terminal),
.bDescriptorType = AUDIO_DTYPE_CSInterface,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
.bTerminalID = 1,
.wTerminalType = AUDIO_TERMINAL_STREAMING,
.bAssocTerminal = 0,
.bNrChannels = 2,
.wChannelConfig = AUDIO_CHANNEL_LEFT_FRONT | AUDIO_CHANNEL_RIGHT_FRONT,
.iChannelNames = 0,
.iTerminal = 0,
},
.feature_unit = {
.bLength = sizeof(audio_device_config.ac_audio.feature_unit),
.bDescriptorType = AUDIO_DTYPE_CSInterface,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_Feature,
.bUnitID = 2,
.bSourceID = 1,
.bControlSize = 1,
.bmaControls = {AUDIO_FEATURE_MUTE | AUDIO_FEATURE_VOLUME, 0, 0},
.iFeature = 0,
},
.output_terminal = {
.bLength = sizeof(audio_device_config.ac_audio.output_terminal),
.bDescriptorType = AUDIO_DTYPE_CSInterface,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
.bTerminalID = 3,
.wTerminalType = AUDIO_TERMINAL_OUT_SPEAKER,
.bAssocTerminal = 0,
.bSourceID = 2,
.iTerminal = 0,
},
},
.as_zero_interface = {
.bLength = sizeof(audio_device_config.as_zero_interface),
.bDescriptorType = DTYPE_Interface,
.bInterfaceNumber = 0x01,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x00,
.bInterfaceClass = AUDIO_CSCP_AudioClass,
.bInterfaceSubClass = AUDIO_CSCP_AudioStreamingSubclass,
.bInterfaceProtocol = AUDIO_CSCP_ControlProtocol,
.iInterface = 0x00,
},
.as_op_interface = {
.bLength = sizeof(audio_device_config.as_op_interface),
.bDescriptorType = DTYPE_Interface,
.bInterfaceNumber = 0x01,
.bAlternateSetting = 0x01,
.bNumEndpoints = 0x02,
.bInterfaceClass = AUDIO_CSCP_AudioClass,
.bInterfaceSubClass = AUDIO_CSCP_AudioStreamingSubclass,
.bInterfaceProtocol = AUDIO_CSCP_ControlProtocol,
.iInterface = 0x00,
},
.as_audio = {
.streaming = {
.bLength = sizeof(audio_device_config.as_audio.streaming),
.bDescriptorType = AUDIO_DTYPE_CSInterface,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_General,
.bTerminalLink = 1,
.bDelay = 1,
.wFormatTag = 1, // PCM
},
.format = {
.core = {
.bLength = sizeof(audio_device_config.as_audio.format),
.bDescriptorType = AUDIO_DTYPE_CSInterface,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_FormatType,
.bFormatType = 1,
.bNrChannels = 2,
.bSubFrameSize = 2,
.bBitResolution = 16,
.bSampleFrequencyType = count_of(audio_device_config.as_audio.format.freqs),
},
.freqs = {
AUDIO_SAMPLE_FREQ(44100),
AUDIO_SAMPLE_FREQ(48000)
},
},
},
.ep1 = {
.core = {
.bLength = sizeof(audio_device_config.ep1.core),
.bDescriptorType = DTYPE_Endpoint,
.bEndpointAddress = AUDIO_OUT_ENDPOINT,
.bmAttributes = 5,
.wMaxPacketSize = AUDIO_MAX_PACKET_SIZE(AUDIO_FREQ_MAX),
.bInterval = 1,
.bRefresh = 0,
.bSyncAddr = AUDIO_IN_ENDPOINT,
},
.audio = {
.bLength = sizeof(audio_device_config.ep1.audio),
.bDescriptorType = AUDIO_DTYPE_CSEndpoint,
.bDescriptorSubtype = AUDIO_DSUBTYPE_CSEndpoint_General,
.bmAttributes = 1,
.bLockDelayUnits = 0,
.wLockDelay = 0,
}
},
.ep2 = {
.bLength = sizeof(audio_device_config.ep2),
.bDescriptorType = 0x05,
.bEndpointAddress = AUDIO_IN_ENDPOINT,
.bmAttributes = 0x11,
.wMaxPacketSize = 3,
.bInterval = 0x01,
.bRefresh = 2,
.bSyncAddr = 0,
},
};
static struct usb_interface ac_interface;
static struct usb_interface as_op_interface;
static struct usb_endpoint ep_op_out, ep_op_sync;
static const struct usb_device_descriptor boot_device_descriptor = {
.bLength = 18,
.bDescriptorType = 0x01,
.bcdUSB = 0x0110,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = 0x40,
.idVendor = VENDOR_ID,
.idProduct = PRODUCT_ID,
.bcdDevice = 0x0200,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01,
};
const char *_get_descriptor_string(uint index) {
if (index <= count_of(descriptor_strings)) {
return descriptor_strings[index - 1];
} else {
return "";
}
}
static struct {
uint32_t freq;
int16_t volume;
int16_t vol_mul;
bool mute;
} audio_state = {
.freq = 44100,
};
static struct audio_buffer_pool *producer_pool;
static void _as_audio_packet(struct usb_endpoint *ep) {
assert(ep->current_transfer);
struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep);
DEBUG_PINS_SET(audio_timing, 1);
// todo deal with blocking correctly
struct audio_buffer *audio_buffer = take_audio_buffer(producer_pool, true);
DEBUG_PINS_CLR(audio_timing, 1);
assert(!(usb_buffer->data_len & 3u));
audio_buffer->sample_count = usb_buffer->data_len / 4;
assert(audio_buffer->sample_count);
assert(audio_buffer->max_sample_count >= audio_buffer->sample_count);
uint16_t vol_mul = audio_state.vol_mul;
int16_t *out = (int16_t *) audio_buffer->buffer->bytes;
int16_t *in = (int16_t *) usb_buffer->data;
for (int i = 0; i < audio_buffer->sample_count * 2; i++) {
out[i] = (int16_t) ((in[i] * vol_mul) >> 15u);
}
give_audio_buffer(producer_pool, audio_buffer);
// keep on truckin'
usb_grow_transfer(ep->current_transfer, 1);
usb_packet_done(ep);
}
static void _as_sync_packet(struct usb_endpoint *ep) {
assert(ep->current_transfer);
DEBUG_PINS_SET(audio_timing, 2);
DEBUG_PINS_CLR(audio_timing, 2);
struct usb_buffer *buffer = usb_current_in_packet_buffer(ep);
assert(buffer->data_max >= 3);
buffer->data_len = 3;
// todo lie thru our teeth for now
uint feedback = (audio_state.freq << 14u) / 1000u;
buffer->data[0] = feedback;
buffer->data[1] = feedback >> 8u;
buffer->data[2] = feedback >> 16u;
// keep on truckin'
usb_grow_transfer(ep->current_transfer, 1);
usb_packet_done(ep);
}
static const struct usb_transfer_type as_transfer_type = {
.on_packet = _as_audio_packet,
.initial_packet_count = 1,
};
static const struct usb_transfer_type as_sync_transfer_type = {
.on_packet = _as_sync_packet,
.initial_packet_count = 1,
};
static struct usb_transfer as_transfer;
static struct usb_transfer as_sync_transfer;
static bool do_get_current(struct usb_setup_packet *setup) {
usb_debug("AUDIO_REQ_GET_CUR\n");
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
switch (setup->wValue >> 8u) {
case FEATURE_MUTE_CONTROL: {
usb_start_tiny_control_in_transfer(audio_state.mute, 1);
return true;
}
case FEATURE_VOLUME_CONTROL: {
/* Current volume. See UAC Spec 1.0 p.77 */
usb_start_tiny_control_in_transfer(audio_state.volume, 2);
return true;
}
}
} else if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_ENDPOINT) {
if ((setup->wValue >> 8u) == ENDPOINT_FREQ_CONTROL) {
/* Current frequency */
usb_start_tiny_control_in_transfer(audio_state.freq, 3);
return true;
}
}
return false;
}
// todo this seemed like aood guess, but is not correct
uint16_t db_to_vol[91] = {
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002,
0x0002, 0x0002, 0x0003, 0x0003, 0x0004, 0x0004, 0x0005, 0x0005,
0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000d, 0x000e,
0x0010, 0x0012, 0x0014, 0x0017, 0x001a, 0x001d, 0x0020, 0x0024,
0x0029, 0x002e, 0x0033, 0x003a, 0x0041, 0x0049, 0x0052, 0x005c,
0x0067, 0x0074, 0x0082, 0x0092, 0x00a4, 0x00b8, 0x00ce, 0x00e7,
0x0104, 0x0124, 0x0147, 0x016f, 0x019c, 0x01ce, 0x0207, 0x0246,
0x028d, 0x02dd, 0x0337, 0x039b, 0x040c, 0x048a, 0x0518, 0x05b7,
0x066a, 0x0732, 0x0813, 0x090f, 0x0a2a, 0x0b68, 0x0ccc, 0x0e5c,
0x101d, 0x1214, 0x1449, 0x16c3, 0x198a, 0x1ca7, 0x2026, 0x2413,
0x287a, 0x2d6a, 0x32f5, 0x392c, 0x4026, 0x47fa, 0x50c3, 0x5a9d,
0x65ac, 0x7214, 0x7fff
};
// actually windows doesn't seem to like this in the middle, so set top range to 0db
#define CENTER_VOLUME_INDEX 91
#define ENCODE_DB(x) ((uint16_t)(int16_t)((x)*256))
#define MIN_VOLUME ENCODE_DB(-CENTER_VOLUME_INDEX)
#define DEFAULT_VOLUME ENCODE_DB(0)
#define MAX_VOLUME ENCODE_DB(count_of(db_to_vol)-CENTER_VOLUME_INDEX)
#define VOLUME_RESOLUTION ENCODE_DB(1)
static bool do_get_minimum(struct usb_setup_packet *setup) {
usb_debug("AUDIO_REQ_GET_MIN\n");
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
switch (setup->wValue >> 8u) {
case FEATURE_VOLUME_CONTROL: {
usb_start_tiny_control_in_transfer(MIN_VOLUME, 2);
return true;
}
}
}
return false;
}
static bool do_get_maximum(struct usb_setup_packet *setup) {
usb_debug("AUDIO_REQ_GET_MAX\n");
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
switch (setup->wValue >> 8u) {
case FEATURE_VOLUME_CONTROL: {
usb_start_tiny_control_in_transfer(MAX_VOLUME, 2);
return true;
}
}
}
return false;
}
static bool do_get_resolution(struct usb_setup_packet *setup) {
usb_debug("AUDIO_REQ_GET_RES\n");
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
switch (setup->wValue >> 8u) {
case FEATURE_VOLUME_CONTROL: {
usb_start_tiny_control_in_transfer(VOLUME_RESOLUTION, 2);
return true;
}
}
}
return false;
}
static struct audio_control_cmd {
uint8_t cmd;
uint8_t type;
uint8_t cs;
uint8_t cn;
uint8_t unit;
uint8_t len;
} audio_control_cmd_t;
static void _audio_reconfigure() {
switch (audio_state.freq) {
case 44100:
case 48000:
break;
default:
audio_state.freq = 44100;
}
// todo hack overwriting const
((struct audio_format *) producer_pool->format)->sample_freq = audio_state.freq;
}
static void audio_set_volume(int16_t volume) {
audio_state.volume = volume;
// todo interpolate
volume += CENTER_VOLUME_INDEX * 256;
if (volume < 0) volume = 0;
if (volume >= count_of(db_to_vol) * 256) volume = count_of(db_to_vol) * 256 - 1;
audio_state.vol_mul = db_to_vol[((uint16_t)volume) >> 8u];
// printf("VOL MUL %04x\n", audio_state.vol_mul);
}
static void audio_cmd_packet(struct usb_endpoint *ep) {
assert(audio_control_cmd_t.cmd == AUDIO_REQ_SetCurrent);
struct usb_buffer *buffer = usb_current_out_packet_buffer(ep);
audio_control_cmd_t.cmd = 0;
if (buffer->data_len >= audio_control_cmd_t.len) {
if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
switch (audio_control_cmd_t.cs) {
case FEATURE_MUTE_CONTROL: {
audio_state.mute = buffer->data[0];
usb_warn("Set Mute %d\n", buffer->data[0]);
break;
}
case FEATURE_VOLUME_CONTROL: {
audio_set_volume(*(int16_t *) buffer->data);
break;
}
}
} else if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_ENDPOINT) {
if (audio_control_cmd_t.cs == ENDPOINT_FREQ_CONTROL) {
uint32_t new_freq = (*(uint32_t *) buffer->data) & 0x00ffffffu;
usb_warn("Set freq %d\n", new_freq == 0xffffffu ? -1 : (int) new_freq);
if (audio_state.freq != new_freq) {
audio_state.freq = new_freq;
_audio_reconfigure();
}
}
}
}
usb_start_empty_control_in_transfer_null_completion();
// todo is there error handling?
}
static const struct usb_transfer_type _audio_cmd_transfer_type = {
.on_packet = audio_cmd_packet,
.initial_packet_count = 1,
};
static bool as_set_alternate(struct usb_interface *interface, uint alt) {
assert(interface == &as_op_interface);
usb_warn("SET ALTERNATE %d\n", alt);
return alt < 2;
}
static bool do_set_current(struct usb_setup_packet *setup) {
#ifndef NDEBUG
usb_warn("AUDIO_REQ_SET_CUR\n");
#endif
if (setup->wLength && setup->wLength < 64) {
audio_control_cmd_t.cmd = AUDIO_REQ_SetCurrent;
audio_control_cmd_t.type = setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK;
audio_control_cmd_t.len = (uint8_t) setup->wLength;
audio_control_cmd_t.unit = setup->wIndex >> 8u;
audio_control_cmd_t.cs = setup->wValue >> 8u;
audio_control_cmd_t.cn = (uint8_t) setup->wValue;
usb_start_control_out_transfer(&_audio_cmd_transfer_type);
return true;
}
return false;
}
static bool ac_setup_request_handler(__unused struct usb_interface *interface, struct usb_setup_packet *setup) {
setup = __builtin_assume_aligned(setup, 4);
if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) {
switch (setup->bRequest) {
case AUDIO_REQ_SetCurrent:
return do_set_current(setup);
case AUDIO_REQ_GetCurrent:
return do_get_current(setup);
case AUDIO_REQ_GetMinimum:
return do_get_minimum(setup);
case AUDIO_REQ_GetMaximum:
return do_get_maximum(setup);
case AUDIO_REQ_GetResolution:
return do_get_resolution(setup);
default:
break;
}
}
return false;
}
bool _as_setup_request_handler(__unused struct usb_endpoint *ep, struct usb_setup_packet *setup) {
setup = __builtin_assume_aligned(setup, 4);
if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) {
switch (setup->bRequest) {
case AUDIO_REQ_SetCurrent:
return do_set_current(setup);
case AUDIO_REQ_GetCurrent:
return do_get_current(setup);
case AUDIO_REQ_GetMinimum:
return do_get_minimum(setup);
case AUDIO_REQ_GetMaximum:
return do_get_maximum(setup);
case AUDIO_REQ_GetResolution:
return do_get_resolution(setup);
default:
break;
}
}
return false;
}
void usb_sound_card_init() {
//msd_interface.setup_request_handler = msd_setup_request_handler;
usb_interface_init(&ac_interface, &audio_device_config.ac_interface, NULL, 0, true);
ac_interface.setup_request_handler = ac_setup_request_handler;
static struct usb_endpoint *const op_endpoints[] = {
&ep_op_out, &ep_op_sync
};
usb_interface_init(&as_op_interface, &audio_device_config.as_op_interface, op_endpoints, count_of(op_endpoints),
true);
as_op_interface.set_alternate_handler = as_set_alternate;
ep_op_out.setup_request_handler = _as_setup_request_handler;
as_transfer.type = &as_transfer_type;
usb_set_default_transfer(&ep_op_out, &as_transfer);
as_sync_transfer.type = &as_sync_transfer_type;
usb_set_default_transfer(&ep_op_sync, &as_sync_transfer);
static struct usb_interface *const boot_device_interfaces[] = {
&ac_interface,
&as_op_interface,
};
__unused struct usb_device *device = usb_device_init(&boot_device_descriptor, &audio_device_config.descriptor,
boot_device_interfaces, count_of(boot_device_interfaces),
_get_descriptor_string);
assert(device);
audio_set_volume(DEFAULT_VOLUME);
_audio_reconfigure();
// device->on_configure = _on_configure;
usb_device_start();
}
static void core1_worker() {
audio_i2s_set_enabled(true);
}
int main(void) {
set_sys_clock_48mhz();
stdout_uart_init();
//gpio_debug_pins_init();
puts("USB SOUND CARD");
#ifndef NDEBUG
for(uint i=0;i<count_of(audio_device_config.as_audio.format.freqs);i++) {
uint freq = audio_device_config.as_audio.format.freqs[i].Byte1 |
(audio_device_config.as_audio.format.freqs[i].Byte2 << 8u) |
(audio_device_config.as_audio.format.freqs[i].Byte3 << 16u);
assert(freq <= AUDIO_FREQ_MAX);
}
#endif
// initialize for 48k we allow changing later
struct audio_format audio_format_48k = {
.format = AUDIO_BUFFER_FORMAT_PCM_S16,
.sample_freq = 48000,
.channel_count = 2,
};
struct audio_buffer_format producer_format = {
.format = &audio_format_48k,
.sample_stride = 4
};
producer_pool = audio_new_producer_pool(&producer_format, 8, 48); // todo correct size
bool __unused ok;
struct audio_i2s_config config = {
.data_pin = PICO_AUDIO_I2S_DATA_PIN,
.clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE,
.dma_channel = 0,
.pio_sm = 0,
};
const struct audio_format *output_format;
output_format = audio_i2s_setup(&audio_format_48k, &config);
if (!output_format) {
panic("PicoAudio: Unable to open audio device.\n");
}
ok = audio_i2s_connect_extra(producer_pool, false, 2, 96, NULL);
assert(ok);
usb_sound_card_init();
multicore_launch_core1(core1_worker);
printf("HAHA %04x %04x %04x %04x\n", MIN_VOLUME, DEFAULT_VOLUME, MAX_VOLUME, VOLUME_RESOLUTION);
// MSD is irq driven
while (1) __wfi();
}

Wyświetl plik

@ -0,0 +1 @@
add_subdirectory(sine_wave)

Wyświetl plik

@ -0,0 +1,60 @@
# only build I2S example if library is available
if (TARGET pico_audio_i2s)
add_executable(sine_wave_i2s
sine_wave.c
)
target_link_libraries(sine_wave_i2s PRIVATE
pico_stdlib
pico_audio_i2s
)
target_compile_definitions(sine_wave_i2s PRIVATE
# compile time configuration of I2S
PICO_AUDIO_I2S_MONO_INPUT=1
#define for our example code
USE_AUDIO_I2S=1
)
# create map/bin/hex file etc.
pico_add_extra_outputs(sine_wave_i2s)
endif ()
# only build PWM example if library is available
if (TARGET pico_audio_pwm)
add_executable(sine_wave_pwm
sine_wave.c
)
target_link_libraries(sine_wave_pwm PRIVATE
pico_stdlib
pico_audio_pwm
)
target_compile_definitions(sine_wave_pwm PRIVATE
#define for our example code
USE_AUDIO_PWM=1
)
# create map/bin/hex file etc.
pico_add_extra_outputs(sine_wave_pwm)
endif ()
# only build S/PDIF example if library is available
if (TARGET pico_audio_spdif)
add_executable(sine_wave_spdif
sine_wave.c
)
target_link_libraries(sine_wave_spdif PRIVATE
pico_stdlib
pico_audio_spdif
)
target_compile_definitions(sine_wave_spdif PRIVATE
# compile time configuration of S/PDIF
PICO_AUDIO_SPDIF_MONO_INPUT=1
#define for our example code
USE_AUDIO_SPDIF=1
)
# create map/bin/hex file etc.
pico_add_extra_outputs(sine_wave_spdif)
endif ()

Wyświetl plik

@ -0,0 +1,149 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <math.h>
#if PICO_ON_DEVICE
#include "hardware/clocks.h"
#include "hardware/structs/clocks.h"
#endif
#include "pico/stdlib.h"
#if USE_AUDIO_I2S
#include "pico/audio_i2s.h"
#elif USE_AUDIO_PWM
#include "pico/audio_pwm.h"
#elif USE_AUDIO_SPDIF
#include "pico/audio_spdif.h"
#endif
#define SINE_WAVE_TABLE_LEN 2048
#define SAMPLES_PER_BUFFER 256
static int16_t sine_wave_table[SINE_WAVE_TABLE_LEN];
struct audio_buffer_pool *init_audio() {
static audio_format_t audio_format = {
.format = AUDIO_BUFFER_FORMAT_PCM_S16,
#if USE_AUDIO_SPDIF
.sample_freq = 44100,
#else
.sample_freq = 24000,
#endif
.channel_count = 1,
};
static struct audio_buffer_format producer_format = {
.format = &audio_format,
.sample_stride = 2
};
struct audio_buffer_pool *producer_pool = audio_new_producer_pool(&producer_format, 3,
SAMPLES_PER_BUFFER); // todo correct size
bool __unused ok;
const struct audio_format *output_format;
#if USE_AUDIO_I2S
struct audio_i2s_config config = {
.data_pin = PICO_AUDIO_I2S_DATA_PIN,
.clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE,
.dma_channel = 0,
.pio_sm = 0,
};
output_format = audio_i2s_setup(&audio_format, &config);
if (!output_format) {
panic("PicoAudio: Unable to open audio device.\n");
}
ok = audio_i2s_connect(producer_pool);
assert(ok);
audio_i2s_set_enabled(true);
#elif USE_AUDIO_PWM
output_format = audio_pwm_setup(&audio_format, -1, &default_mono_channel_config);
if (!output_format) {
panic("PicoAudio: Unable to open audio device.\n");
}
ok = audio_pwm_default_connect(producer_pool, false);
assert(ok);
audio_pwm_set_enabled(true);
#elif USE_AUDIO_SPDIF
output_format = audio_spdif_setup(&audio_format, &audio_spdif_default_config);
if (!output_format) {
panic("PicoAudio: Unable to open audio device.\n");
}
//ok = audio_spdif_connect(producer_pool);
ok = audio_spdif_connect(producer_pool);
assert(ok);
audio_spdif_set_enabled(true);
#endif
return producer_pool;
}
int main() {
#if PICO_ON_DEVICE
#if USE_AUDIO_PWM
set_sys_clock_48mhz();
#endif
#endif
stdio_init_all();
for (int i = 0; i < SINE_WAVE_TABLE_LEN; i++) {
sine_wave_table[i] = 32767 * cosf(i * 2 * (float) (M_PI / SINE_WAVE_TABLE_LEN));
}
struct audio_buffer_pool *ap = init_audio();
uint32_t step = 0x200000;
uint32_t pos = 0;
uint32_t pos_max = 0x10000 * SINE_WAVE_TABLE_LEN;
uint vol = 128;
while (true) {
#if USE_AUDIO_PWM
enum audio_correction_mode m = audio_pwm_get_correction_mode();
#endif
int c = getchar_timeout_us(0);
if (c >= 0) {
if (c == '-' && vol) vol -= 4;
if ((c == '=' || c == '+') && vol < 255) vol += 4;
if (c == '[' && step > 0x10000) step -= 0x10000;
if (c == ']' && step < (SINE_WAVE_TABLE_LEN / 16) * 0x20000) step += 0x10000;
if (c == 'q') break;
#if USE_AUDIO_PWM
if (c == 'c') {
bool done = false;
while (!done) {
if (m == none) m = fixed_dither;
else if (m == fixed_dither) m = dither;
else if (m == dither) m = noise_shaped_dither;
else if (m == noise_shaped_dither) m = none;
done = audio_pwm_set_correction_mode(m);
}
}
printf("vol = %d, step = %d mode = %d \r", vol, step >>16, m);
#else
printf("vol = %d, step = %d \r", vol, step >> 16);
#endif
}
struct audio_buffer *buffer = take_audio_buffer(ap, true);
int16_t *samples = (int16_t *) buffer->buffer->bytes;
for (uint i = 0; i < buffer->max_sample_count; i++) {
samples[i] = (vol * sine_wave_table[pos >> 16u]) >> 8u;
pos += step;
if (pos >= pos_max) pos -= pos_max;
}
buffer->sample_count = buffer->max_sample_count;
give_audio_buffer(ap, buffer);
}
puts("\n");
return 0;
}

Wyświetl plik

@ -0,0 +1 @@
add_subdirectory(usb_host_webserver)

Wyświetl plik

@ -0,0 +1,10 @@
if (TARGET lwip)
add_executable(usb_host_webserver
main.c
)
target_include_directories(usb_host_webserver PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(usb_host_webserver PRIVATE pico_stdlib tinyusb_host tinyusb_board lwip)
pico_add_extra_outputs(usb_host_webserver)
endif()

Wyświetl plik

@ -0,0 +1,69 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
#define NO_SYS 1
#define MEM_ALIGNMENT 4
#define LWIP_RAW 1
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define LWIP_DHCP 0
#define LWIP_ICMP 1
#define LWIP_UDP 1
#define LWIP_TCP 1
#define ETH_PAD_SIZE 0
#define LWIP_IP_ACCEPT_UDP_PORT(p) ((p) == PP_NTOHS(67))
#define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
#define TCP_SND_BUF (2 * TCP_MSS)
#define ETHARP_SUPPORT_STATIC_ENTRIES 1
#define LWIP_HTTPD_CGI 0
#define LWIP_HTTPD_SSI 0
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
#if 0
#define LWIP_DEBUG 1
#define TCP_DEBUG LWIP_DBG_ON
#define ETHARP_DEBUG LWIP_DBG_ON
#define PBUF_DEBUG LWIP_DBG_ON
#define IP_DEBUG LWIP_DBG_ON
#define TCPIP_DEBUG LWIP_DBG_ON
#define DHCP_DEBUG LWIP_DBG_ON
#define UDP_DEBUG LWIP_DBG_ON
#endif
#endif /* __LWIPOPTS_H__ */

Wyświetl plik

@ -0,0 +1,70 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Peter Lawrence
*
* influenced by lrndis https://github.com/fetisov/lrndis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
/*
this appears as either a RNDIS or CDC-ECM USB virtual network adapter; the OS picks its preference
RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts
The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server.
*/
#include "bsp/board.h"
#include "tusb.h"
#include "lwip/init.h"
#include "lwip/timeouts.h"
#include "httpd.h"
/* shared between tud_network_recv_cb() and service_traffic() */
static struct pbuf *received_frame;
/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
/* it is suggested that the first two bytes are 0x02,0x02 to indicate a link-local address */
const uint8_t tud_network_mac_address[6] = {0x02,0x02,0x84,0x6A,0x96,0x00};
// Shouldn't need this?
void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes)
{
;
}
int main(void)
{
/* initialize TinyUSB */
board_init();
tusb_init();
while (1)
{
// tinyusb host task
tuh_task();
}
return 0;
}

Wyświetl plik

@ -0,0 +1,70 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// CONFIGURATION
//--------------------------------------------------------------------
#define CFG_TUH_HUB 1
#define CFG_TUH_HID_KEYBOARD 0
#define CFG_TUH_HID_MOUSE 0
#define CFG_TUSB_HOST_HID_GENERIC 0 // (not yet supported)
#define CFG_TUH_MSC 0
#define CFG_TUH_CDC 1
#define CFG_TUH_CDC_RNDIS 1
#define CFG_TUSB_HOST_DEVICE_MAX (CFG_TUH_HUB ? 5 : 1) // normal hub has 4 ports
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

Wyświetl plik

@ -0,0 +1,62 @@
# This is a copy of <PICO_EXTRAS_PATH>/external/pico_extras_import.cmake
# This can be dropped into an external project to help locate pico-extras
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_EXTRAS_PATH} AND (NOT PICO_EXTRAS_PATH))
set(PICO_EXTRAS_PATH $ENV{PICO_EXTRAS_PATH})
message("Using PICO_EXTRAS_PATH from environment ('${PICO_EXTRAS_PATH}')")
endif ()
if (DEFINED ENV{PICO_EXTRAS_FETCH_FROM_GIT} AND (NOT PICO_EXTRAS_FETCH_FROM_GIT))
set(PICO_EXTRAS_FETCH_FROM_GIT $ENV{PICO_EXTRAS_FETCH_FROM_GIT})
message("Using PICO_EXTRAS_FETCH_FROM_GIT from environment ('${PICO_EXTRAS_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_EXTRAS_FETCH_FROM_GIT_PATH} AND (NOT PICO_EXTRAS_FETCH_FROM_GIT_PATH))
set(PICO_EXTRAS_FETCH_FROM_GIT_PATH $ENV{PICO_EXTRAS_FETCH_FROM_GIT_PATH})
message("Using PICO_EXTRAS_FETCH_FROM_GIT_PATH from environment ('${PICO_EXTRAS_FETCH_FROM_GIT_PATH}')")
endif ()
if (NOT PICO_EXTRAS_PATH)
if (PICO_EXTRAS_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_EXTRAS_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_EXTRAS_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
PICO_EXTRAS
GIT_REPOSITORY https://github.com/raspberrypi/pico-extras
GIT_TAG master
)
if (NOT PICO_EXTRAS)
message("Downloading PICO EXTRAS")
FetchContent_Populate(PICO_EXTRAS)
set(PICO_EXTRAS_PATH ${PICO_EXTRAS_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
if (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../pico-extras")
set(PICO_EXTRAS_PATH ${PICO_SDK_PATH}/../pico-extras)
message("Defaulting PICO_EXTRAS_PATH as sibling of PICO_SDK_PATH: ${PICO_EXTRAS_PATH}")
else()
message(FATAL_ERROR
"PICO EXTRAS location was not specified. Please set PICO_EXTRAS_PATH or set PICO_EXTRAS_FETCH_FROM_GIT to on to fetch from git."
)
endif()
endif ()
endif ()
set(PICO_EXTRAS_PATH "${PICO_EXTRAS_PATH}" CACHE PATH "Path to the PICO EXTRAS")
set(PICO_EXTRAS_FETCH_FROM_GIT "${PICO_EXTRAS_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO EXTRAS from git if not otherwise locatable")
set(PICO_EXTRAS_FETCH_FROM_GIT_PATH "${PICO_EXTRAS_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download EXTRAS")
get_filename_component(PICO_EXTRAS_PATH "${PICO_EXTRAS_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_EXTRAS_PATH})
message(FATAL_ERROR "Directory '${PICO_EXTRAS_PATH}' not found")
endif ()
set(PICO_EXTRAS_PATH ${PICO_EXTRAS_PATH} CACHE PATH "Path to the PICO EXTRAS" FORCE)
add_subdirectory(${PICO_EXTRAS_PATH} pico_extras)

Wyświetl plik

@ -0,0 +1,62 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the PICO SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading PICO SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"PICO SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the PICO SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the PICO SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

Wyświetl plik

@ -0,0 +1 @@
add_subdirectory(hello_reset)

Wyświetl plik

@ -0,0 +1,14 @@
if (TARGET hardware_reset)
add_executable(hello_reset
hello_reset.c
)
# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(hello_reset pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_reset)
# add url via pico_set_program_url
example_auto_set_url(hello_reset)
endif ()

Wyświetl plik

@ -0,0 +1,31 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/resets.h"
// tag::hello_reset[]
int main() {
stdio_init_all();
printf("Hello, reset!\n");
// Put the PWM block into reset
reset_block(RESETS_RESET_PWM_RST_N_BITS);
// And bring it out
unreset_block_wait(RESETS_RESET_PWM_RST_N_BITS);
// Put the PWM and RTC block into reset
reset_block(RESETS_RESET_PWM_RST_N_BITS | RESETS_RESET_RTC_RST_N_BITS);
// Wait for both to come out of reset
unreset_block_wait(RESETS_RESET_PWM_RST_N_BITS | RESETS_RESET_RTC_RST_N_BITS);
return 0;
}
// end::hello_reset[]

Wyświetl plik

@ -0,0 +1,14 @@
if (TARGET pico_scanvideo) # not all build types support it
# Libs
add_subdirectory(render)
add_subdirectory(sprite)
# Apps
add_subdirectory(demo1)
add_subdirectory(hscroll_dma_tiles)
add_subdirectory(flash_stream)
add_subdirectory(mandelbrot)
add_subdirectory(mario_tiles)
add_subdirectory(scanvideo_minimal)
add_subdirectory(sprite_demo)
add_subdirectory(textmode)
endif()

Wyświetl plik

@ -0,0 +1,16 @@
if (TARGET pico_scanvideo_dpi)
add_executable(demo1
demo1.c
data.c
data.h
)
target_compile_definitions(demo1
PRIVATE
# video overlay is distracting
# PICO_SCANVIDEO_PLANE_COUNT=3
)
target_link_libraries(demo1 PRIVATE pico_stdlib pico_scanvideo_dpi render pico_multicore)
pico_add_extra_outputs(demo1)
endif()

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,10 @@
#ifndef SOFTWARE_DATA_H
#define SOFTWARE_DATA_H
#include "image.h"
extern const struct palette32 welcome_palette;
extern const struct palette32 pi_palette;
extern const struct image_data welcome_image_data;
extern const struct image_data pi400_image_data;
#endif //SOFTWARE_DATA_H

Wyświetl plik

@ -0,0 +1,623 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include "pico.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"
#include "spans.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/multicore.h"
#include "pico/sync.h"
#include "pico/stdlib.h"
#if !PICO_NO_HARDWARE
#include "hardware/clocks.h"
#endif
#include "data.h"
#include <stdio.h>
#if !PICO_NO_HARDWARE
#include "hardware/structs/bus_ctrl.h"
//#define SHOW_PERF_COUNTERS
#endif
CU_REGISTER_DEBUG_PINS(frame_generation)
// ---- select at most one ---
//CU_SELECT_DEBUG_PINS(frame_generation)
typedef bool (*render_scanline_func)(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_test_pattern(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_pi(struct scanvideo_scanline_buffer *dest, int core);
extern const struct scanvideo_pio_program video_24mhz_composable;
const struct scanvideo_mode vga_mode_320x256_60 =
{
.default_timing = &vga_timing_640x480_60_default,
.pio_program = &video_24mhz_composable,
.width = 320,
.height = 256,
.xscale = 2,
.yscale = 480,
.yscale_denominator = 256
};
//#define vga_mode vga_mode_1080p
//#define vga_mode vga_mode_720p
#define vga_mode vga_mode_640x480_60
//#define vga_mode vga_mode_320x256_60
//#define vga_mode vga_mode_320x240_60
//#define vga_mode vga_mode_213x160_60
//#define vga_mode vga_mode_160x120_60
//#define vga_mode vga_mode_tft_800x480_50
//#define vga_mode vga_mode_tft_400x240_50
// for now we want to see second counter on native and don't need both cores
//#if !PICO_NO_HARDWARE
#define RENDER_ON_CORE0
//#endif
#define RENDER_ON_CORE1
//#define IRQS_ON_CORE1
//render_scanline_func render_scanline = render_scanline_test_pattern;
render_scanline_func render_scanline = render_scanline_pi;
//render_scanline_func render_scanline = render_scanline_tmp;
int vspeed = 1 * 1;
int hspeed = 1 * -1;
#ifdef SHOW_PERF_COUNTERS
#define NUM_PERF_COUNTERS 10
uint32_t perf_count[NUM_PERF_COUNTERS];
uint32_t perf_contention[NUM_PERF_COUNTERS];
uint perf_base;
static uint16_t bar_chart[2][128];
static uint bar_chart_size[2];
#endif
static const int input_pin0 = 22;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
static struct mutex frame_logic_mutex;
static int left = 0;
static int top = 0;
void init_render_state(int core);
//void __isr isr_siob_proc0() {
// gpio_put(24, 1);
//}
static bool get_input() {
return gpio_get(input_pin0) || gpio_get(28);
}
uint16_t *draw_line(uint16_t *buf, uint16_t color, uint len) {
switch (len) {
case 0:
break;
case 1:
*buf++ = COMPOSABLE_RAW_1P;
*buf++ = color;
break;
case 2:
*buf++ = COMPOSABLE_RAW_2P;
*buf++ = color;
*buf++ = color;
break;
default:
*buf++ = COMPOSABLE_COLOR_RUN;
*buf++ = color;
*buf++ = (len - 3);
break;
}
return buf;
}
uint16_t bar_color(uint a, uint b) {
int x = a / 0x1000;
if (x > 0x1f) x = 0x1f;
return PICO_SCANVIDEO_PIXEL_FROM_RGB5(0x10, 0x1f - x, x);
}
int approx_log2(uint32_t x) {
int sig = 32 - __builtin_clz(x);
if (sig < 7) {
return (sig * 64) + ((x << (7 - sig)) & 63);
} else {
return (sig * 64) + ((x >> (sig - 7)) & 63);
}
}
uint16_t *draw_bar(uint16_t *buf, uint32_t color, uint32_t value, uint32_t maxv, uint bar_width) {
if (value > maxv) value = maxv;
uint w = (value * bar_width + maxv - 1) / maxv;
buf = draw_line(buf, color, w);
buf = draw_line(buf, PICO_SCANVIDEO_ALPHA_MASK | PICO_SCANVIDEO_PIXEL_FROM_RGB5(2, 2, 2), bar_width - w);
buf = draw_line(buf, PICO_SCANVIDEO_ALPHA_MASK | PICO_SCANVIDEO_PIXEL_FROM_RGB5(16, 16, 0x16), 4);
return buf;
}
void __time_critical_func(render_loop)() {
static uint8_t last_input = 0;
static uint32_t last_frame_num = 0;
static int which = 0;
int core_num = get_core_num();
assert(core_num >= 0 && core_num < 2);
printf("Rendering on core %d\n", core_num);
while (true) {
struct scanvideo_scanline_buffer *scanline_buffer = scanvideo_begin_scanline_generation(true);
// if (scanline_buffer->data_used) {
// // validate the previous scanline to make sure noone corrupted it
// validate_scanline(scanline_buffer->data, scanline_buffer->data_used, vga_mode.width, vga_mode.width);
// }
// do any frame related logic
mutex_enter_blocking(&frame_logic_mutex);
uint32_t frame_num = scanvideo_frame_number(scanline_buffer->scanline_id);
// note that with multiple cores we may have got here not for the first scanline, however one of the cores will do this logic first before either does the actual generation
if (frame_num != last_frame_num) {
#ifdef SHOW_PERF_COUNTERS
static uint32_t *val_ptr = perf_count;
static uint32_t *val_ptr2 = perf_count + 2;
static int rotator = 0;
for (int i = 0; i < 2; i++) {
val_ptr[i] = bus_ctrl_hw->counter[i].value;
val_ptr2[i] = bus_ctrl_hw->counter[i + 2].value;
bus_ctrl_hw->counter[i].value = 0;
bus_ctrl_hw->counter[i + 2].value = 0;
}
uint r = hw_divider_u32_remainder_inlined(rotator, 5);
if (r < 2) {
if (r & 1) {
bus_ctrl_hw->counter[0].sel = arbiter_sram0_perf_event_access_contested;
bus_ctrl_hw->counter[1].sel = arbiter_sram1_perf_event_access_contested;
bus_ctrl_hw->counter[2].sel = arbiter_sram2_perf_event_access_contested;
bus_ctrl_hw->counter[3].sel = arbiter_sram3_perf_event_access_contested;
val_ptr = perf_contention;
} else {
bus_ctrl_hw->counter[0].sel = arbiter_sram0_perf_event_access;
bus_ctrl_hw->counter[1].sel = arbiter_sram1_perf_event_access;
bus_ctrl_hw->counter[2].sel = arbiter_sram2_perf_event_access;
bus_ctrl_hw->counter[3].sel = arbiter_sram3_perf_event_access;
val_ptr = perf_count;
}
val_ptr2 = val_ptr + 2;
} else if (r < 4) {
if (r & 1) {
bus_ctrl_hw->counter[0].sel = arbiter_sram4_perf_event_access_contested;
bus_ctrl_hw->counter[1].sel = arbiter_sram5_perf_event_access_contested;
bus_ctrl_hw->counter[2].sel = arbiter_rom_perf_event_access_contested;
bus_ctrl_hw->counter[3].sel = arbiter_xip_main_perf_event_access_contested;
val_ptr = perf_contention + 4;
} else {
bus_ctrl_hw->counter[0].sel = arbiter_sram4_perf_event_access;
bus_ctrl_hw->counter[1].sel = arbiter_sram5_perf_event_access;
bus_ctrl_hw->counter[2].sel = arbiter_rom_perf_event_access;
bus_ctrl_hw->counter[3].sel = arbiter_xip_main_perf_event_access;
val_ptr = perf_count + 4;
}
val_ptr2 = val_ptr + 2;
} else {
bus_ctrl_hw->counter[0].sel = arbiter_apb_perf_event_access_contested;
bus_ctrl_hw->counter[1].sel = arbiter_fastperi_perf_event_access_contested;
val_ptr = perf_contention + 8;
bus_ctrl_hw->counter[2].sel = arbiter_apb_perf_event_access;
bus_ctrl_hw->counter[3].sel = arbiter_fastperi_perf_event_access;
val_ptr2 = perf_count + 8;
}
for (int i = 0; i < 4; i++) {
bus_ctrl_hw->counter[i].value = 0;
}
rotator++;
#define MAXX 0xc0000
uint16_t bar_width = hw_divider_u32_quotient(vga_mode.width, (NUM_PERF_COUNTERS + 1)) - 4;
for (int qq = 0; qq < 2; qq++) {
int total = 0;
uint16_t *buf_base = bar_chart[qq];
uint16_t *buf = buf_base;
for (int i = 0; i < NUM_PERF_COUNTERS; i++) {
if (qq) {
total += perf_count[i];
buf = draw_bar(buf, 0xfd08, perf_count[i], MAXX, bar_width);
} else {
total += perf_contention[i];
buf = draw_bar(buf, bar_color(perf_contention[i], perf_count[i]), perf_contention[i],
perf_count[i], bar_width);
}
};
buf = draw_bar(buf, qq ? 0xfd08 : bar_color(total, MAXX), total, MAXX, bar_width);
*buf++ = COMPOSABLE_RAW_1P;
*buf++ = 0;
if (2 & (uintptr_t) buf) {
*buf++ = COMPOSABLE_EOL_ALIGN;
} else {
*buf++ = COMPOSABLE_EOL_SKIP_ALIGN;
*buf++ = 0xffff;
}
bar_chart_size[qq] = (buf - buf_base) / 2;
}
// printf("\r%08x %04x %08x %08x %08x %08x %08x %08x %08x : %08x", perf_count[0], approx_log2(perf_count[0]), perf_count[1], perf_count[2], perf_count[3], perf_count[4], perf_count[5], perf_count[6], perf_count[7], total);
// printf("\r%08x %08x %08x %08x %08x %08x", perf_contention[2], perf_contention[3], perf_contention[4], perf_contention[5], perf_contention[6], perf_contention[7]);
#endif
// this could should be during vblank as we try to create the next line
// todo should we ignore if we aren't attempting the next line
last_frame_num = frame_num;
if (hspeed > 0) {
left += hspeed;
if (left >= vga_mode.width - pi400_image_data.width / 2) {
hspeed = -hspeed;
left += hspeed;
}
} else {
left += hspeed;
if (left < -pi400_image_data.width / 2) {
hspeed = -hspeed;
left += hspeed;
}
}
if (vspeed > 0) {
top += vspeed;
if (top >= vga_mode.height - pi400_image_data.height / 2) {
vspeed = -vspeed;
top += vspeed;
}
} else {
top += vspeed;
if (top < -pi400_image_data.height / 2) {
vspeed = -vspeed;
top += vspeed;
}
}
uint8_t new_input = get_input();
if (last_input && !new_input) {
if (which) {
hspeed++;
} else {
vspeed++;
}
//left++;
//printf("%d\n", left);
which = !which;
}
last_input = new_input;
}
mutex_exit(&frame_logic_mutex);
DEBUG_PINS_SET(frame_generation, (core_num) ? 2 : 4);
#ifdef SHOW_PERF_COUNTERS
int l = scanvideo_scanline_number(scanline_buffer->scanline_id);
if (l < 16 / vga_mode.yscale) {
int w = l >= (8 / vga_mode.yscale);
memcpy(scanline_buffer->data, bar_chart[w], bar_chart_size[w] * 4);
scanline_buffer->data_used = bar_chart_size[w];
} else {
render_scanline(scanline_buffer, core_num);
}
#else
render_scanline(scanline_buffer, core_num);
#endif
#ifdef SHOW_PERF_COUNTERS
bool update = l >= 16 / vga_mode.yscale;
if (!update) {
static uint32_t blank[] = {
COMPOSABLE_RAW_1P | (0 << 16),
COMPOSABLE_EOL_SKIP_ALIGN
};
#if PICO_SCANVIDEO_PLANE_COUNT > 1
memcpy(scanline_buffer->data2, blank, sizeof(blank));
scanline_buffer->data2_used = count_of(blank);
#if PICO_SCANVIDEO_PLANE_COUNT > 2
memcpy(scanline_buffer->data3, blank, sizeof(blank));
scanline_buffer->data3_used = count_of(blank);
#endif
#endif
}
#else
bool update = true;
#endif
// some colored pixels
static uint32_t blah[] = {
COMPOSABLE_COLOR_RUN | (0x0 << 16), /* color */
/*width-3*/ 0 | (COMPOSABLE_COLOR_RUN << 16),
0x801f /* color */ | (13 << 16),
COMPOSABLE_COLOR_RUN | (0x0 << 16), /* color */
/*width-3*/ 15 | (COMPOSABLE_COLOR_RUN << 16),
0x83e1 /* color */ | (13 << 16),
COMPOSABLE_COLOR_RUN |
((PICO_SCANVIDEO_ALPHA_MASK | PICO_SCANVIDEO_PIXEL_FROM_RGB5(0, 0x1f, 0x19)) << 16), /* color */
/*width-3*/ 5 | (COMPOSABLE_RAW_1P << 16),
0 | (COMPOSABLE_EOL_ALIGN << 16)
};
static uint32_t blah2[] = {
COMPOSABLE_COLOR_RUN | (0x0000 << 16), /* color */
/*width-3*/ 0 | (COMPOSABLE_COLOR_RUN << 16),
0xf01f /* color */ | (13 << 16),
COMPOSABLE_COLOR_RUN | (0x0 << 16), /* color */
/*width-3*/ 11 | (COMPOSABLE_COLOR_RUN << 16),
0xb3e1 /* color */ | (10 << 16),
COMPOSABLE_COLOR_RUN | (0x81ef << 16), /* color */
/*width-3*/ 6 | (COMPOSABLE_RAW_1P << 16),
0 | (COMPOSABLE_EOL_ALIGN << 16)
};
#if PICO_SCANVIDEO_PLANE_COUNT > 1
if (update) {
if (scanline_buffer->data2_used != count_of(blah)) {
memcpy(scanline_buffer->data2, blah, sizeof(blah));
scanline_buffer->data2_used = count_of(blah);
}
((uint16_t *) scanline_buffer->data2)[2] = (3 * frame_num / 4) & 255;
}
#if PICO_SCANVIDEO_PLANE_COUNT > 2
if (update) {
if (scanline_buffer->data3_used != count_of(blah2)) {
memcpy(scanline_buffer->data3, blah2, sizeof(blah2));
scanline_buffer->data3_used = count_of(blah2);
}
((uint16_t *) scanline_buffer->data3)[2] = 255 - (frame_num & 255);
}
#endif
#endif
DEBUG_PINS_CLR(frame_generation, (core_num) ? 2 : 4);
// release the scanline into the wild
scanvideo_end_scanline_generation(scanline_buffer);
}
}
struct semaphore video_setup_complete;
void setup_video() {
scanvideo_setup(&vga_mode);
scanvideo_timing_enable(true);
sem_release(&video_setup_complete);
}
void core1_func() {
#ifdef IRQS_ON_CORE1
setup_video();
#else
sem_acquire_blocking(&video_setup_complete);
#endif
#ifdef RENDER_ON_CORE1
render_loop();
#endif
}
#define TEST_WAIT_FOR_SCANLINE
#ifdef TEST_WAIT_FOR_SCANLINE
volatile uint32_t scanline_color = 0;
#endif
int vga_main(void) {
mutex_init(&frame_logic_mutex);
gpio_debug_pins_init();
gpio_init(24);
gpio_init(22);
// just from this core
gpio_set_dir_out_masked(0x01380000);
gpio_set_dir_in_masked(0x00400000);
// debug pin
gpio_put(24, 0);
gpio_set_function(input_pin0, GPIO_FUNC_SIO); // todo is this necessary
// go for launch (debug pin)
gpio_put(24, 1);
sem_init(&video_setup_complete, 0, 1);
init_render_state(0);
#ifdef RENDER_ON_CORE1
init_render_state(1);
#endif
#if defined(RENDER_ON_CORE1) || defined(IRQS_ON_CORE1)
multicore_launch_core1(core1_func);
#endif
#ifndef IRQS_ON_CORE1
setup_video();
#endif
#ifdef RENDER_ON_CORE0
render_loop();
#else
sem_acquire(&video_setup_complete);
while (true) {
#ifndef TEST_WAIT_FOR_SCANLINE
// Just use vblank to print out a value every second
static int i=0, s=0;
vga_wait_for_vblank();
if (++i == 60) {
printf("%d\n", s++);
i = 0;
}
#else
static uint32_t sl = 0;
sl = scanvideo_wait_for_scanline_complete(sl);
scanline_color = (scanline_color + 0x10u) & 0xffu;
#endif
}
#endif
__builtin_unreachable();
}
struct palette16 *opaque_pi_palette = NULL;
// two copies one for each core
struct span before_span[2];
struct span pi_span[2];
struct span after_span[2];
// must not be called concurrently
void init_render_state(int core) {
if (!opaque_pi_palette) {
// one time initialization
uint32_t back_color = 0xffff8000;
opaque_pi_palette = blend_palette(&pi_palette, back_color);
// todo we should of course have a wide solid color span that overlaps
// todo we can of course also reuse these
top = (vga_mode.height - pi400_image_data.height) / 2;
left = (vga_mode.width - pi400_image_data.width) / 2;
if (top < 0) top = 0;
if (left < 0) left = 0;
// set to top right for timing issues
//left = vga_mode.width - pi400_image_data.width;
top = -159;
left = 148;
}
// todo we should of course have a wide solid color span that overlaps
// todo we can of course also reuse these
init_solid_color_span(&before_span[core], left, opaque_pi_palette->entries[15], NULL);
init_vogon_4bit_span(&pi_span[core], pi400_image_data.width, NULL, 0, opaque_pi_palette, &before_span[core]);
init_solid_color_span(&after_span[core], vga_mode.width - left - pi400_image_data.width,
opaque_pi_palette->entries[15],
&pi_span[core]);
}
bool __time_critical_func(render_scanline_pi)(struct scanvideo_scanline_buffer *dest, int core) {
uint32_t *buf = dest->data;
size_t buf_length = dest->data_max;
int l = scanvideo_scanline_number(dest->scanline_id);
l -= top;
int left_offset = left < 0 ? -left : 0;
int right_offset = left + pi400_image_data.width - vga_mode.width;
right_offset = right_offset < 0 ? 0 : right_offset;
before_span[core].width = left + left_offset;
set_vogon_4bit_clipping(&pi_span[core], left_offset,
pi400_image_data.width >= left_offset + right_offset ? pi400_image_data.width -
left_offset - right_offset : 0);
after_span[core].width = vga_mode.width - left - pi400_image_data.width;
int length;
if (l < 0 || l >= pi400_image_data.height) {
length = single_color_scanline(buf, buf_length, vga_mode.width, opaque_pi_palette->entries[15]);
} else {
int sl = l;//&63;
set_vogon_4bit_span_encoding(&pi_span[core], pi400_image_data.blob.bytes + pi400_image_data.row_offsets[sl],
pi400_image_data.row_offsets[sl + 1] - pi400_image_data.row_offsets[sl]);
length = render_spans(buf, buf_length, &before_span[core], vga_mode.width);
}
if (length > 0) {
dest->status = SCANLINE_OK;
dest->data_used = (uint16_t) length;
} else {
dest->status = SCANLINE_ERROR;
dest->data_used = 0;
}
return true;
}
// the infamous grey/white triangle
bool render_scanline_test_pattern(struct scanvideo_scanline_buffer *dest, int core) {
// 1 + line_num red, then white
uint32_t *buf = dest->data;
size_t buf_length = dest->data_max;
int pos = 0;
int y = scanvideo_scanline_number(dest->scanline_id);
if (y > vga_mode.width - 10) y = vga_mode.width - 10;
int yy = vga_mode.height - y;
if (yy < 4) {
static uint32_t colors[] = {0xffff, 0x03e0, 0x7c1ef, 0};
pos = single_color_scanline(buf, buf_length, vga_mode.width, colors[yy]);
} else {
int w = MIN(y + 1, vga_mode.width - 6);
uint32_t red = (((y * 8) / vga_mode.height) & 1) ? 0x001f : 0x021f;
uint16_t *buf16 = (uint16_t *) buf;
if (w > 0) {
if (w == 1) {
buf16[pos++] = COMPOSABLE_RAW_1P;
} else if (w == 2) {
buf16[pos++] = COMPOSABLE_RAW_2P;
buf16[pos++] = red;
} else {
buf16[pos++] = COMPOSABLE_COLOR_RUN;
}
buf16[pos++] = red;
if (w > 2) {
buf16[pos++] = w - 3;
}
}
w = vga_mode.width - w - 6;
if (w > 0) {
buf16[pos++] = COMPOSABLE_RAW_2P;
buf16[pos++] = 0xfc00;
buf16[pos++] = 0xffe0;
#ifndef TEST_WAIT_FOR_SCANLINE
uint16_t c = 0xffff;
#else
uint16_t c = 0x0421 * (scanline_color >> 4);
#endif
if (w == 1) {
buf16[pos++] = COMPOSABLE_RAW_1P;
} else if (w == 2) {
buf16[pos++] = COMPOSABLE_RAW_2P;
buf16[pos++] = c;
} else {
buf16[pos++] = COMPOSABLE_COLOR_RUN;
}
buf16[pos++] = c;
if (w > 2) {
buf16[pos++] = w - 3;
}
}
buf16[pos++] = COMPOSABLE_RAW_RUN;
buf16[pos++] = 0x0000; // p0
buf16[pos++] = 4 - 3; // len - 3
buf16[pos++] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(0, 0, 0x1f); // p1
buf16[pos++] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(0x1f, 0, 0); // p2
buf16[pos++] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(0, 0x1f, 0); // p3
// black for eol
buf16[pos++] = COMPOSABLE_RAW_1P;
buf16[pos++] = 0;
if (pos & 1) {
buf16[pos++] = COMPOSABLE_EOL_ALIGN;
} else {
buf16[pos++] = COMPOSABLE_EOL_SKIP_ALIGN;
pos++;
}
assert(!(pos & 1));
pos >>= 1;
}
// weirdo:
dest->status = SCANLINE_OK;
dest->data = buf;
dest->data_used = (uint16_t) pos;
return true;
}
//#include "hardware/structs/vreg_and_chip_reset.h"
int main(void) {
gpio_put(27, 0);
#if PICO_ON_DEVICE && !PICO_ON_FPGA
set_sys_clock_khz(96000, true);
// set_sys_clock_48();
#endif
// Re init uart now that clk_peri has changed
setup_default_uart();
return vga_main();
}

Wyświetl plik

@ -0,0 +1,14 @@
if (PICO_ON_DEVICE AND TARGET pico_scanvideo_dpi)
add_executable(flash_stream
flash_stream.c
)
target_link_libraries(flash_stream PRIVATE
pico_stdlib
pico_scanvideo_dpi
hardware_dma
)
target_compile_definitions(flash_stream PRIVATE
PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS=500
)
pico_add_extra_outputs(flash_stream)
endif ()

Wyświetl plik

@ -0,0 +1,146 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/sync.h"
#include "pico/stdlib.h"
#include "hardware/structs/dma.h"
#include "hardware/structs/ssi.h"
// This app must be built with PICO_COPY_TO_RAM=1
#define FLASH_IMAGE_BASE 0x1003c000
#define FLASH_IMAGE_SCANLINE_SIZE (640 * sizeof(uint16_t))
#define FLASH_IMAGE_SIZE (FLASH_IMAGE_SCANLINE_SIZE * 480)
#define FLASH_N_IMAGES 3
#define FRAMES_PER_IMAGE 300
#define VGA_MODE vga_mode_640x480_60
extern const struct scanvideo_pio_program video_24mhz_composable;
static void frame_update_logic();
static void render_scanline(struct scanvideo_scanline_buffer *dest);
int __time_critical_func(render_loop)() {
static uint32_t last_frame_num = 0;
while (true) {
struct scanvideo_scanline_buffer *scanline_buffer = scanvideo_begin_scanline_generation(true);
uint32_t frame_num = scanvideo_frame_number(scanline_buffer->scanline_id);
if (frame_num != last_frame_num) {
last_frame_num = frame_num;
frame_update_logic();
}
render_scanline(scanline_buffer);
scanvideo_end_scanline_generation(scanline_buffer);
}
}
int vga_main(void) {
scanvideo_setup(&VGA_MODE);
scanvideo_timing_enable(true);
render_loop();
return 0;
}
const uint16_t *img_base = (const uint16_t *) FLASH_IMAGE_BASE;
void __time_critical_func(frame_update_logic)() {
static uint slideshow_ctr = 0;
static uint image_index = 0;
if (++slideshow_ctr >= FRAMES_PER_IMAGE) {
slideshow_ctr = 0;
image_index = (image_index + 1) % FLASH_N_IMAGES;
img_base = (const uint16_t *) (FLASH_IMAGE_BASE + FLASH_IMAGE_SIZE * image_index);
}
}
static inline uint16_t *raw_scanline_prepare(struct scanvideo_scanline_buffer *dest, uint width) {
assert(width >= 3);
assert(width % 2 == 0);
// +1 for the black pixel at the end, -3 because the program outputs n+3 pixels.
dest->data[0] = COMPOSABLE_RAW_RUN | (width + 1 - 3 << 16);
// After user pixels, 1 black pixel then discard remaining FIFO data
dest->data[width / 2 + 2] = 0x0000u | (COMPOSABLE_EOL_ALIGN << 16);
dest->data_used = width / 2 + 2;
assert(dest->data_used <= dest->data_max);
return (uint16_t *) &dest->data[1];
}
static inline void raw_scanline_finish(struct scanvideo_scanline_buffer *dest) {
// Need to pivot the first pixel with the count so that PIO can keep up
// with its 1 pixel per 2 clocks
uint32_t first = dest->data[0];
uint32_t second = dest->data[1];
dest->data[0] = (first & 0x0000ffffu) | ((second & 0x0000ffffu) << 16);
dest->data[1] = (second & 0xffff0000u) | ((first & 0xffff0000u) >> 16);
dest->status = SCANLINE_OK;
}
// Use direct SSI DMA for maximum transfer speed (but cannot execute from
// flash at the same time)
void __no_inline_not_in_flash_func(flash_bulk_read)(uint32_t *rxbuf, uint32_t flash_offs, size_t len,
uint dma_chan) {
ssi_hw->ssienr = 0;
ssi_hw->ctrlr1 = len - 1; // NDF, number of data frames (32b each)
ssi_hw->dmacr = SSI_DMACR_TDMAE_BITS | SSI_DMACR_RDMAE_BITS;
ssi_hw->ssienr = 1;
dma_hw->ch[dma_chan].read_addr = (uint32_t) &ssi_hw->dr0;
dma_hw->ch[dma_chan].write_addr = (uint32_t) rxbuf;
dma_hw->ch[dma_chan].transfer_count = len;
// Must enable DMA byteswap because non-XIP 32-bit flash transfers are
// big-endian on SSI (we added a hardware tweak to make XIP sensible)
dma_hw->ch[dma_chan].ctrl_trig =
DMA_CH0_CTRL_TRIG_BSWAP_BITS |
DREQ_XIP_SSIRX << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB |
dma_chan << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB |
DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS |
DMA_CH0_CTRL_TRIG_DATA_SIZE_VALUE_SIZE_WORD << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB |
DMA_CH0_CTRL_TRIG_EN_BITS;
// Now DMA is waiting, kick off the SSI transfer (mode continuation bits in LSBs)
ssi_hw->dr0 = (flash_offs << 8) | 0xa0;
while (dma_hw->ch[dma_chan].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS)
tight_loop_contents();
ssi_hw->ssienr = 0;
ssi_hw->ctrlr1 = 0;
ssi_hw->dmacr = 0;
ssi_hw->ssienr = 1;
}
void __time_critical_func(render_scanline)(struct scanvideo_scanline_buffer *dest) {
int l = scanvideo_scanline_number(dest->scanline_id);
uint16_t *colour_buf = raw_scanline_prepare(dest, VGA_MODE.width);
// Just use a random DMA channel which hopefully nobody minds us borrowing
// "It's easier to seek forgiveness than permission, unless you hardfault"
flash_bulk_read(
(uint32_t *) colour_buf,
(uint32_t) img_base + l * FLASH_IMAGE_SCANLINE_SIZE,
FLASH_IMAGE_SCANLINE_SIZE / sizeof(uint32_t),
11
);
raw_scanline_finish(dest);
}
int main(void) {
set_sys_clock_khz(192000, true);
setup_default_uart();
#ifdef PICO_SMPS_MODE_PIN
gpio_init(PICO_SMPS_MODE_PIN);
gpio_set_dir(PICO_SMPS_MODE_PIN, GPIO_OUT);
gpio_put(PICO_SMPS_MODE_PIN, 1);
#endif
return vga_main();
}

Wyświetl plik

@ -0,0 +1,2 @@
*.bin
*.uf2

Wyświetl plik

@ -0,0 +1,12 @@
Upstream-Name: ubuntu-wallpapers
Source: https://launchpad.net/ubuntu-wallpapers
Files: *.png
Copyright: 2018-2020 Ubuntu community contributors
License: CC-BY-SA 3.0
The wallpapers used are:
Lighthouse at sunrise, by Frenchie Smalls
Stone Mountain, by Brad Huchteman
Voss, by fortuneblues

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 476 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 622 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 526 KiB

Wyświetl plik

@ -0,0 +1,9 @@
#!/bin/bash
set -ex
rm -f *.bin pack.uf2
./packtiles -sdf bgar5515 Lighthouse_at_sunrise_by_Frenchie_Smalls.png lighthouse.bin
./packtiles -sdf bgar5515 Stone_Mountain_by_Brad_Huchteman.png stone_mountain.bin
./packtiles -sdf bgar5515 Voss_by_fortuneblues.png voss.bin
cat *.bin > pack.bin
uf2conv -f pico -b 0x1003c000 pack.bin -o pack.uf2

Wyświetl plik

@ -0,0 +1,171 @@
#!/usr/bin/env python3
# Public Domain software (c) Luke Wren
from PIL import Image
import argparse
import struct
import sys
FORMATS = ["argb1555", "rgab5515", "bgar5515", "rgb565", "argb1232", "ragb2132", "rgb332", "p8", "p4", "p2", "p1"]
def bytes_from_bitstream_le(bitstream):
accum = 0
accum_size = 0
while True:
while accum_size < 8:
try:
nbits, newdata = next(bitstream)
except StopIteration:
return
accum = accum | (newdata << accum_size)
accum_size += nbits
while accum_size >= 8:
yield accum & 0xff
accum = accum >> 8
accum_size -= 8
class BinHeader:
def __init__(self, filename, arrayname=None):
if arrayname is None:
arrayname = filename.split(".")[0]
self.f = open(filename, "w")
self.out_count = 0
self.f.write("static char __attribute__((aligned(4))) {}[] = {{\n\t".format(arrayname))
def write(self, bs):
for b in bs:
self.f.write("0x{:02x}".format(b) + (",\n\t" if self.out_count % 16 == 15 else ", "))
self.out_count += 1
def close(self):
self.f.write("\n};\n")
self.f.close()
# Fixed dither -- note every number 0...15 appears once (thanks Graham)
dither_pattern_4x4 = [
[0 , 8 , 2 , 10],
[12 , 4 , 14 , 6 ],
[3 , 11 , 1 , 9 ],
[15 , 7 , 13 , 5 ],
]
def format_channel(data, msb, lsb, dither=False, dithercoord=None):
# Assume data to be 8 bits
out_width = msb - lsb + 1
assert(out_width <= 8)
if dither:
ditherval = dither_pattern_4x4[dithercoord[1] % 4][dithercoord[0] % 4]
shamt = (8 - out_width) - 4
if shamt >= 0:
data += ditherval << shamt
else:
data += ditherval >> -shamt
data = min(data, 0xff)
return (data >> (8 - out_width)) << lsb
def format_rgb_pixel(pix, fmt, dither=False, dithercoord=None):
accum = 0
for p, f in zip(pix, fmt):
accum |= format_channel(p, f[0], f[1], dither, dithercoord)
if len(pix) == len(fmt) - 1:
accum |= format_channel(0xff, fmt[-1][0], fmt[-1][1])
return accum
# TODO would be kind of nice to generate these based on format string but I don't need that yet
rgb_formats = {
"argb1555": (16, ((14, 10), (9, 5), (4, 0), (15, 15))),
"rgab5515": (16, ((15, 11), (10, 6), (4, 0), (5, 5))),
"bgar5515": (16, ((4, 0), (10, 6), (15, 11), (5, 5))),
"rgb565" : (16, ((15, 11), (10, 5), (4, 0))),
"argb1232": (8, ((6, 5), (4, 2), (1, 0), (7, 7))),
"ragb2132": (8, ((7, 6), (4, 2), (1, 0), (5, 5))),
"rgb332" : (8, ((7, 5), (4, 2), (1, 0))),
}
def format_pixel(format, src_has_transparency, pixel, dither=False, dithercoord=None):
assert(format in FORMATS)
if format in rgb_formats:
return (rgb_formats[format][0], format_rgb_pixel(pixel, rgb_formats[format][1], dither, dithercoord))
elif format in ["p8", "p4", "p2", "p1"]:
size = int(format[1:])
return (size, (pixel + src_has_transparency) & ((1 << size) - 1))
else:
raise Exception()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("input", help="Input file name")
parser.add_argument("output", help="Output file name")
parser.add_argument("--tilesize", "-t", help="Tile size (pixels), default 8",
default="8", choices=[str(2 ** i) for i in range(3, 11)])
parser.add_argument("--single", "-s", action="store_true",
help="The input consists of a single image of arbitrary width/height, rather than a tileset")
parser.add_argument("--format", "-f", help="Output pixel format, default argb1555",
default="argb1555", choices=FORMATS)
parser.add_argument("--dither", "-d", action="store_true",
help="Apply a simple fixed dither pattern when packing RGB files")
parser.add_argument("--metadata", "-m", action="store_true",
help="Write out opacity metadata at end of file for faster alpha blit (must be used with --single)")
args = parser.parse_args()
img = Image.open(args.input)
if args.single:
tsize_x = img.width
tsize_y = img.height
else:
tsize_x = int(args.tilesize)
tsize_y = tsize_x
if args.metadata and not args.single:
sys.exit("--metadata must be used with --single")
format_is_paletted = args.format.startswith("p")
image_is_transparent = img.mode == "RGBA" and img.getextrema()[3][0] < 255
if args.metadata and not image_is_transparent:
sys.exit("Can't write opacity metadata for a non-transparent image")
if format_is_paletted:
ncolours_max = 1 << int(args.format[1:])
ncolours_actual = min(ncolours_max, len(img.getcolors()))
pimg = img.quantize(ncolours_max)
palette = pimg.getpalette()
# TODO haven't found a sane way to make PIL map transparency to palette
if image_is_transparent:
for x in range(img.width):
for y in range(img.height):
if not (img.getpixel((x, y))[3] & 0x80):
pimg.putpixel((x, y), 255)
with open(args.output + ".pal", "wb") as pfile:
if image_is_transparent:
pfile.write(bytes(2))
pfile.write(bytes(bytes_from_bitstream_le(
format_pixel("argb1555", False, palette[i:i+3]) for i in range(0, ncolours_actual * 3, 3)
)))
if ncolours_actual < ncolours_max:
pfile.write(bytes(2 * (ncolours_max - ncolours_actual)))
img = pimg
if args.output.endswith(".h"):
ofile = BinHeader(args.output, arrayname = args.input.split(".")[0])
else:
ofile = open(args.output, "wb")
for y in range(0, img.height - (tsize_y - 1), tsize_y):
for x in range(0, img.width - (tsize_x - 1), tsize_x):
tile = img.crop((x, y, x + tsize_x, y + tsize_y))
ofile.write(bytes(bytes_from_bitstream_le(
format_pixel(args.format, image_is_transparent, tile.getpixel((i, j)), args.dither, dithercoord=(i, j)) for j in range(tsize_y) for i in range(tsize_x)
)))
if args.metadata:
assert(tsize_x * tsize_y % 4 == 0)
for y in range(0, tsize_y):
opacity = list(img.getpixel((x, y))[3] >= 128 for x in range(tsize_x))
try:
first_transparent = opacity.index(True)
last_transparent = tsize_x - 1 - list(reversed(opacity)).index(True)
continuous_span = all(opacity[first_transparent:last_transparent + 1])
ofile.write(struct.pack("<L", (last_transparent & 0xffff) | ((first_transparent & 0x7fff) << 16) | ((continuous_span & 1) << 31)))
except ValueError:
# Completely transparent row
ofile.write(struct.pack("<L", 0))
ofile.close()

Wyświetl plik

@ -0,0 +1,25 @@
if (TARGET pico_scanvideo_dpi)
add_executable(hscroll_dma_tiles
hscroll_dma_tiles.c
data.c
data.h
)
add_compile_definitions(hscroll_dma_tiles PRIVATE
# DISABLE_HPIXELS
PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1
PICO_SCANVIDEO_USE_RAW1P_2CYCLE=1
PICO_SCANVIDEO_PLANE_COUNT=2
PICO_SCANVIDEO_PLANE2_VARIABLE_FRAGMENT_DMA=1
PICO_SCANVIDEO_MAX_SCANLINE_BUFFER2_WORDS=200
PICO_SCANVIDEO_SCANLINE_BUFFER_COUNT=5
PICO_SCANVIDEO_ENABLE_VIDEO_CLOCK_DOWN=1
)
target_link_libraries(hscroll_dma_tiles PRIVATE
pico_stdlib
pico_multicore
pico_scanvideo_dpi
render)
pico_add_extra_outputs(hscroll_dma_tiles)
endif()

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,13 @@
#ifndef SOFTWARE_DATA_H
#define SOFTWARE_DATA_H
#include "image.h"
extern const struct tile_data16 tiles_tile_data;
extern int level0_map_width;
extern int level0_map_height;
extern uint16_t level0_map[];
extern const struct tile_data16 galaga_tile_data;
#endif //SOFTWARE_DATA_H

Wyświetl plik

@ -0,0 +1,603 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/sync.h"
#include "pico/stdlib.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/multicore.h"
#include "spans.h"
#include "data.h"
CU_REGISTER_DEBUG_PINS(frame_gen)
//CU_SELECT_DEBUG_PINS(frame_gen)
//#define DEBUG_HALF_PIXEL
typedef bool (*render_scanline_func)(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_test_pattern(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_bg(struct scanvideo_scanline_buffer *dest, int core);
////#define vga_mode vga_mode_640x480_60
#define vga_mode vga_mode_320x240_60
//#define vga_mode vga_mode_213x160_60
//#define vga_mode vga_mode_160x120_60
////#define vga_mode vga_mode_tft_800x480_50
//#define vga_mode vga_mode_tft_400x240_50
//#define DISABLE_HPIXELS
//#define vga_mode vga_mode_tft_320x240_60
#define COUNT ((vga_mode.width/8)-1)
// for now we want to see second counter on native and don't need both cores
#if !PICO_NO_HARDWARE
// todo there is a bug in multithreaded rendering atm
#define RENDER_ON_CORE0
#endif
#define RENDER_ON_CORE1
//#define IRQS_ON_CORE1
render_scanline_func render_scanline = render_scanline_bg;
#define COORD_SHIFT 3
int vspeed = 1 * 1;
int hspeed = 1 << COORD_SHIFT;
int hpos;
int vpos;
#ifndef DISABLE_HPIXELS
bool enable_half_pixels = true;
#else
#define enable_half_pixels false
#endif
bool enable_wave;
int wave_amplitude = 50;
static const int input_pin0 = 22;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
static struct mutex frame_logic_mutex;
static int left = 0;
static int top = 0;
static int x_sprites = 1;
void go_core1(void (*execute)());
void init_render_state(int core);
void print_status() {
printf("hspeed %d/8 half-pixel=%d wave=%d (amp=%d) (sprites %d) \r", hspeed, enable_half_pixels, enable_wave,
wave_amplitude, x_sprites);
}
// ok this is going to be the beginning of retained mode
//
// data is in the wrong color format
void convert_spans(const struct tile_data16 *td) {
#if PICO_ON_DEVICE
uint16_t *p = (uint16_t *) td->blob.bytes;
for (int i = 0; i < td->blob.size / 2; i++) {
uint r = p[i] & 0x1f;
uint g = (p[i] >> 5) & 0x1f;
uint b = (p[i] >> 10) & 0x1f;
uint alpha = p[i] >> 15;
p[i] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(r, g, b) | (alpha ? PICO_SCANVIDEO_ALPHA_MASK : 0);
}
#endif
}
void render_loop() {
static uint8_t last_input = 0;
static uint32_t last_frame_num = 0;
int core_num = get_core_num();
assert(core_num >= 0 && core_num < 2);
printf("Rendering on core %d\r\n", core_num);
if (DEBUG_PINS_ENABLED(frame_gen)) {
gpio_init(PICO_DEBUG_PIN_BASE + 1);
gpio_set_dir_out_masked(2 << PICO_DEBUG_PIN_BASE); // steal debug pin 2 for this core
}
while (true) {
struct scanvideo_scanline_buffer *scanvideo_scanline_buffer = scanvideo_begin_scanline_generation(true);
// if (scanvideo_scanline_buffer->data_used) {
// // validate the previous scanline to make sure no one corrupted it
// validate_scanline(scanvideo_scanline_buffer->data, scanvideo_scanline_buffer->data_used, vga_mode.width, vga_mode.width);
// }
// do any frame related logic
bool ps = false;
// todo probably a race condition here ... thread dealing with last line of a frame may end
// todo up waiting on the next frame...
mutex_enter_blocking(&frame_logic_mutex);
uint32_t frame_num = scanvideo_frame_number(scanvideo_scanline_buffer->scanline_id);
// note that with multiple cores we may have got here not for the first scanline, however one of the cores will do this logic first before either does the actual generation
if (frame_num != last_frame_num) {
if (frame_num == 1) {
ps = true;
}
// this could should be during vblank as we try to create the next line
// todo should we ignore if we aren't attempting the next line
last_frame_num = frame_num;
#if PICO_ON_DEVICE
if (uart_is_readable(uart_default)) {
int c = uart_getc(uart_default);
switch (c) {
case '+':
case '=':
hspeed++;
break;
case '_':
case '-':
hspeed--;
break;
case '9':
if (x_sprites > 0) x_sprites--;
break;
case '0':
if (x_sprites < 17) x_sprites++;
break;
case '[':
wave_amplitude--;
break;
case ']':
wave_amplitude++;
break;
#ifndef DISABLE_HPIXELS
case 'h':
enable_half_pixels ^= true;
break;
#endif
case 'w':
enable_wave ^= true;
}
ps = true;
}
#endif
hpos += hspeed;
if (hpos < 0) {
hpos = 0;
hspeed = -hspeed;
} else if (hpos >= (level0_map_width * 8 - vga_mode.width) << COORD_SHIFT) {
hpos = (level0_map_width * 8 - vga_mode.width) << COORD_SHIFT;
hspeed = -hspeed;
}
uint8_t new_input = gpio_get(input_pin0);
if (last_input && !new_input) {
hpos++;
}
last_input = new_input;
}
mutex_exit(&frame_logic_mutex);
DEBUG_PINS_SET(frame_gen, core_num ? 2 : 4);
render_scanline(scanvideo_scanline_buffer, core_num);
DEBUG_PINS_CLR(frame_gen, core_num ? 2 : 4);
#if PICO_SCANVIDEO_PLANE_COUNT > 2
assert(false);
#endif
// release the scanline into the wild
scanvideo_end_scanline_generation(scanvideo_scanline_buffer);
// do this outside mutex and scanline generation
if (ps) {
print_status();
}
}
}
struct semaphore video_setup_complete;
void setup_video() {
scanvideo_setup(&vga_mode);
scanvideo_timing_enable(true);
sem_release(&video_setup_complete);
}
void core1_func() {
#ifdef IRQS_ON_CORE1
setup_video();
#endif
#ifdef RENDER_ON_CORE1
render_loop();
#endif
}
#define TEST_WAIT_FOR_SCANLINE
#ifdef TEST_WAIT_FOR_SCANLINE
volatile uint32_t scanline_color = 0;
#endif
int video_main(void) {
#ifndef DISABLE_HPIXELS
assert(vga_mode.xscale >= 2); // too slow anyway, but we would need to turn half pixel off
#endif
// gpio_debug_pins_init();
mutex_init(&frame_logic_mutex);
// get the bottom
vpos = level0_map_height * 8 - vga_mode.height;
assert(vpos >= 0);
convert_spans(&tiles_tile_data);
convert_spans(&galaga_tile_data);
sem_init(&video_setup_complete, 0, 1);
#ifndef IRQS_ON_CORE1
setup_video();
#endif
puts("KEYS:");
puts(" +/- adjust horizonatal speed");
puts(" h toggle half pixel mode");
puts(" 9/0 up/down horizontal sprite count");
puts(" w toggle wave mode");
puts(" [/] adjust wave amplitude");
init_render_state(0);
#ifdef RENDER_ON_CORE1
init_render_state(1);
#endif
#if defined(RENDER_ON_CORE1) || defined(IRQS_ON_CORE1)
go_core1(core1_func);
#endif
#ifdef RENDER_ON_CORE0
render_loop();
#else
sem_acquire_blocking(&video_setup_complete);
while (true) {
#ifndef TEST_WAIT_FOR_SCANLINE
// Just use vblank to print out a value every second
static int i=0, s=0;
video_wait_for_vblank();
if (++i == 60) {
printf("%d\n", s++);
i = 0;
}
#else
static uint32_t sl = 0;
sl = scanvideo_wait_for_scanline_complete(sl);
scanline_color = (scanline_color + 0x10u) & 0xffu;
#endif
}
#endif
__builtin_unreachable();
}
//struct palette16 *opaque_pi_palette = NULL;
// must not be called concurrently
void init_render_state(int core) {
// todo we should of course have a wide solid color span that overlaps
// todo we can of course also reuse these
// init_solid_color_span(&before_span[core], left, opaque_pi_palette->entries[15], NULL);
// init_vogon_4bit_span(&pi_span[core], pi400_image_data.width, NULL, 0, opaque_pi_palette, &before_span[core]);
// init_solid_color_span(&after_span[core], vga_mode.width - left - pi400_image_data.width, opaque_pi_palette->entries[15],
// &pi_span[core]);
}
static const int8_t hacky_cos_table[] = {127, 126, 124, 121, 117, 112, 105, 98, 89, 80, 70, 59, 48, 36, 24, 12, 0, -12,
-24, -36, -48, -59, -70, -80, -89, -98, -105, -112, -117, -121, -124, -126,
-127, -126, -124, -121, -117, -112, -105, -98, -89, -80, -70, -59, -48, -36,
-24, -12, 0, 12, 24, 36, 48, 59, 70, 80, 89, 98, 105, 112, 117, 121, 124, 126};
bool render_scanline_bg(struct scanvideo_scanline_buffer *dest, int core) {
// 1 + line_num red, then white
uint32_t *buf = dest->data;
size_t buf_length = dest->data_max;
int y = scanvideo_scanline_number(dest->scanline_id) + vpos;
int x = hpos;
if (enable_wave) {
x += (wave_amplitude *
hacky_cos_table[(y + scanvideo_frame_number(dest->scanline_id)) % count_of(hacky_cos_table)]) >> 8;
if (x < 0) x = 0;
if (x > ((level0_map_width * 8 - vga_mode.width) << COORD_SHIFT))
x = (level0_map_width * 8 - vga_mode.width) << COORD_SHIFT;
}
//y = (y + frame_number(dest->scanline_id)) % (level0_map_height * 8);
const uint16_t *map = level0_map + level0_map_width * (y / 8);
map += (x >> (COORD_SHIFT + 3));
const uint16_t *map0 = map;
const uint16_t *span_offsets = tiles_tile_data.span_offsets + (y & 7u);
#if !PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA
uint16_t *output = (uint16_t*)buf;
// raw run has an inline first pixel, so we need to handle that here
// todo shift the video mode over by a pixel to account for this
*output++ = COMPOSABLE_RAW_RUN;
*output++ = 0;
*output++ = 1 + COUNT * 8 - 3;
for(int i=0;i<COUNT;i++) {
uint32_t off = span_offsets[8 * *map++];
uint16_t *data = (uint16_t *)(tiles_tile_data.blob.bytes + off);
for(int j=0;j<8;j++) *output++ = *data++;
}
// todo fix so we don't need whole scanline
*output++ = COMPOSABLE_COLOR_RUN;
*output++ = 0;
*output++ = vga_mode.width - COUNT * 8 - 1 - 3;
// end of line stuff
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
if (2 & (intptr_t)output) {
// we are unaligned
*output++ = COMPOSABLE_EOL_ALIGN;
} else {
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff; // eye catcher
}
assert(0 == (3u & (intptr_t)output));
assert((uint32_t*)output <= (buf + dest->data_max));
dest->data_used = (uint16_t)(((uint32_t*)output) - buf);
#else
#ifdef DEBUG_HALF_PIXEL
int debug_half_pixel_count = 0;
#endif
// we handle both ends separately
// static const uint32_t end_of_line[] = {
// COMPOSABLE_RAW_1P | (0u<<16),
// COMPOSABLE_EOL_SKIP_ALIGN | (0xffff << 16) // eye catcher ffff
// };
uint32_t *output32 = buf + 2; // skip one chain segment - we fill in below
map++; // skip first element
uint32_t off = span_offsets[8 * map0[0]];
int i = (x >> COORD_SHIFT) & 7;
int eol_pixels = i;
uint16_t *data = (uint16_t *) (tiles_tile_data.blob.bytes + off);
bool half_pixel = enable_half_pixels && (x & (1 << (COORD_SHIFT - 1)));
data += i;
if (half_pixel) i++; // we deal with the second pixel specially
int j;
if (i >= 7) {
j = 1;
// skip second element in the offset 7 7/12 case
map++;
} else {
j = 0;
}
// render full size tiles
for (; j < COUNT; j++) {
uint32_t off = span_offsets[8 * *map++];
uint16_t *data = (uint16_t *) (tiles_tile_data.blob.bytes + off);
*output32++ = 4;
assert(!(3u & (intptr_t) data));
*output32++ = host_safe_hw_ptr(data);
}
// end of scanline // to be filled in below
*output32++ = 0;
*output32++ = 0;
// end of dma chain (correct 0 values)
*output32++ = 0;
*output32++ = 0;
uint16_t *output = (uint16_t *) output32;
// draw a possibly fractional first tile
// 0: RUN T00 | LEN T01 | T02 T03 | T04 T05 | T06 T07 |
// 1: R2P T01 | T02 RUN | T03 LEN | T04 T05 | T06 T07 |
// 2: RUN T02 | LEN T03 | T04 T05 | T06 T07 |
// 3: R2P T03 | T04 RUN | T05 LEN | T06 T07 |
// 4: RUN T04 | LEN T05 | T06 T07 |
// 5: R2P T05 | T06 RUN | T05 LEN | T06 T07 |
// 6: RUN T06 | LEN T07 |
// 7: R2P T07 | T10 RUN | T11 LEN | T12 T13 | T14 T15 | T16 T17 |
// with half pixel (i.e we set i to i+1 above, and always prefix)
// 0: H1P T00 | R2P T01 | T02 RUN | T03 LEN | T04 T05 | T06 T07 |
// 1: H1P T01 | RUN T02 | LEN T03 | T04 T05 | T06 T07 |
// 2: H1P T02 | R2P T03 | T04 RUN | T05 LEN | T06 T07 |
// 3: H1P T03 | RUN T04 | LEN T05 | T06 T07 |
// 4: H1P T04 | R2P T05 | T06 RUN | T05 LEN | T06 T07 |
// 5: H1P T05 | RUN T06 | LEN T07 |
// 6: H1P T06 | R2P T07 | T10 RUN | T11 LEN | T12 T13 | T14 T15 | T16 T17 |
// 7: H1P T07 | RUN T10 | LEN T11 | T12 T13 | T14 T15 | T16 T17 |
int run_length = (8 - (i & 7u)) + COUNT * 8 - 3;
#ifndef DISABLE_HPIXELS
if (half_pixel) {
// prefix with the half pixel
*output++ = COMPOSABLE_RAW_1P_2CYCLE;
*output++ = *data++;
#ifdef DEBUG_HALF_PIXEL
debug_half_pixel_count++;
#endif
if (i == 8) {
// cope with the case where we've stepped onto the new tile after the half-pixel
off = span_offsets[8 * map0[1]];
data = (uint16_t *) (tiles_tile_data.blob.bytes + off);
i = 0;
run_length -= 8;
}
}
#endif
if (i & 1) {
*output++ = COMPOSABLE_RAW_2P;
*output++ = *data++;
if (i == 7) {
// cope with the case where we've stepped onto the new tile
off = span_offsets[8 * map0[1]];
data = (uint16_t *) (tiles_tile_data.blob.bytes + off);
i = 1;
} else {
i += 2;
}
run_length -= 2;
#ifdef DEBUG_HALF_PIXEL
debug_half_pixel_count+=4;
#endif
*output++ = *data++;
*output++ = COMPOSABLE_RAW_RUN;
} else {
*output++ = COMPOSABLE_RAW_RUN;
}
*output++ = *data++;
*output++ = run_length;
for (; i < 7; i++) {
*output++ = *data++;
}
assert(0 == (3u & (intptr_t) output));
// setup our first chain segment (to point into our buffer here)
buf[0] = ((uint32_t *) output) - output32;
buf[1] = host_safe_hw_ptr(output32);
// end of line
uint32_t *eol_base = (uint32_t *) output;
if (eol_pixels || half_pixel) {
off = span_offsets[8 * *map++];
data = (uint16_t *) (tiles_tile_data.blob.bytes + off);
#ifdef DEBUG_HALF_PIXEL
debug_half_pixel_count+=eol_pixels * 2;
#endif
switch (eol_pixels) {
// we could be slightly more optimal in the non half pixel case, but don't reall care
case 0:
break;
case 1:
*output++ = COMPOSABLE_RAW_1P;
*output++ = *data++;
break;
case 2:
*output++ = COMPOSABLE_RAW_2P;
*output++ = *data++;
*output++ = *data++;
break;
default:
*output++ = COMPOSABLE_RAW_RUN;
*output++ = *data++;
*output++ = eol_pixels - 3;
for (int i = 1; i < eol_pixels; i++) {
*output++ = *data++;
}
break;
}
#ifndef DISABLE_HPIXELS
if (half_pixel) {
*output++ = COMPOSABLE_RAW_1P_2CYCLE;
*output++ = *data++;
#ifdef DEBUG_HALF_PIXEL
debug_half_pixel_count++;
#endif
}
#endif
}
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
if (2u & (intptr_t) output) {
*output++ = COMPOSABLE_EOL_ALIGN;
} else {
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff; // eye catcher
}
// setup our last chain segment (to point into our buffer here)
output32[-4] = ((uint32_t *) output) - eol_base;; //len
output32[-3] = host_safe_hw_ptr(eol_base);
#ifdef DEBUG_HALF_PIXEL
debug_half_pixel_count += (run_length+3)*2;
if (y==vpos) printf("%d %d %d %d\n", (x>>COORD_SHIFT)&7, half_pixel, debug_half_pixel_count, eol_pixels);
#endif
assert(0 == (3u & (intptr_t) output));
assert((uint32_t *) output <= (buf + dest->data_max));
dest->data_used = (uint16_t) (output32 -
buf); // todo we don't want to include the off the end data in the "size" for the dma
#endif
// why was this here, it is buf anyway!
// dest->data = buf;
#if PICO_SCANVIDEO_PLANE_COUNT > 1
#if !PICO_SCANVIDEO_PLANE2_VARIABLE_FRAGMENT_DMA
assert(false);
#endif
buf = dest->data2;
output32 = buf;
uint32_t *inline_data = output32 + PICO_SCANVIDEO_MAX_SCANLINE_BUFFER2_WORDS / 2;
output = (uint16_t *) inline_data;
uint32_t *base = (uint32_t *) output;
#define MAKE_SEGMENT \
assert(0 == (3u & (intptr_t)output)); \
*output32++ = (uint32_t*)output - base; \
*output32++ = host_safe_hw_ptr(base); \
base = (uint32_t *)output;
int wibble = (scanvideo_frame_number(dest->scanline_id) >> 2) % 7;
for (int q = 0; q < x_sprites; q++) {
// nice if we can do two black pixel before
*output++ = COMPOSABLE_RAW_RUN;
*output++ = 0;
*output++ = galaga_tile_data.width + 2 - 3;
*output++ = 0;
MAKE_SEGMENT;
span_offsets = galaga_tile_data.span_offsets + (q + wibble) * galaga_tile_data.height +
(y - vpos);//(y%galaga_tile_data.count 7u);
off = span_offsets[0];
data = (uint16_t *) (galaga_tile_data.blob.bytes + off);
*output32++ = galaga_tile_data.width / 2;
*output32++ = host_safe_hw_ptr(data);
}
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff;
MAKE_SEGMENT;
// end of dma chain
*output32++ = 0;
*output32++ = 0;
assert(output32 < inline_data);
assert((uint32_t *) output <= (buf + dest->data2_max));
dest->data2_used = (uint16_t) (output32 -
buf); // todo we don't want to include the inline data in the "size" for the dma
#endif
dest->status = SCANLINE_OK;
return true;
}
void go_core1(void (*execute)()) {
multicore_launch_core1(execute);
}
int main(void) {
set_sys_clock_48mhz();
setup_default_uart();
#if PICO_NO_HARDWARE
//#include <math.h>
// for(int i = 0; i<64;i++) {
// printf("%d, ", (int)(0x7f*cos(i*M_PI/32)));
// }
// printf("\n");
#endif
//#include "level0.h"
// uint8_t *p = level0_dat;
// int w = 1<<p[0];
// int h = 1<<p[1];
// printf("const int level0_map_width = %d;\n", w);
// printf("const int level0_map_height = %d;\n", h);
// printf("const uint16_t level0_map = {\n");
// for (int i = 0; i < w*h; i += 32) {
// printf("\t\t");
// for (int j = i; j < w*h && j < (i + 32); j++) {
// uint8_t *q = p + 2 + j*2;
// printf("0x%04x, ", q[0]*256+q[1]);
// }
// printf("\n");
// }
// printf("};\n");
return video_main();
}

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,15 @@
if (TARGET pico_scanvideo_dpi)
add_executable(mandelbrot
mandelbrot.c
)
target_compile_definitions(mandelbrot PRIVATE
PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1
#TURBO_BOOST
)
target_link_libraries(mandelbrot PRIVATE
pico_stdlib
pico_scanvideo_dpi
pico_multicore)
pico_add_extra_outputs(mandelbrot)
endif ()

Wyświetl plik

@ -0,0 +1,257 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <stdio.h>
#include "pico.h"
#include "pico/scanvideo.h"
#include "pico/sync.h"
#include "pico/scanvideo/composable_scanline.h"
#include "hardware/gpio.h"
#include "pico/stdlib.h"
#include "pico/multicore.h"
#if PICO_ON_DEVICE
#include "hardware/clocks.h"
#include "hardware/structs/vreg_and_chip_reset.h"
#endif
CU_REGISTER_DEBUG_PINS(generation)
#define vga_mode vga_mode_320x240_60
//#define USE_FLOAT 1
#if USE_FLOAT
//typedef float fixed;
typedef double fixed;
static inline fixed float_to_fixed(float x) {
return x;
}
static inline fixed fixed_mult(fixed a, fixed b) {
return a*b;
}
#else
#define FRAC_BITS 25u
typedef int32_t fixed;
static inline fixed float_to_fixed(float x) {
return (fixed) (x * (float) (1u << FRAC_BITS));
}
static inline fixed fixed_mult(fixed a, fixed b) {
int64_t r = ((int64_t) a) * b;
return (int32_t) (r >> FRAC_BITS);
}
#endif
#define max_iters 127//255
struct mutex frame_logic_mutex;
static void frame_update_logic();
void fill_scanline_buffer(struct scanvideo_scanline_buffer *buffer);
static uint y;
static fixed x0, y0;
static fixed dx0_dx, dy0_dy;
static fixed max;
static bool params_ready;
static uint16_t framebuffer[320 * 240];
//static uint16_t *framebuffer;
static uint16_t colors[16] = {
PICO_SCANVIDEO_PIXEL_FROM_RGB8(66, 30, 15),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(25, 7, 26),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(9, 1, 47),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(4, 4, 73),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(0, 7, 100),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(12, 44, 138),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(24, 82, 177),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(57, 125, 209),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(134, 181, 229),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(211, 236, 248),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(241, 233, 191),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(248, 201, 95),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(255, 170, 0),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(204, 128, 0),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(153, 87, 0),
PICO_SCANVIDEO_PIXEL_FROM_RGB8(106, 52, 3),
};
static void scanline(uint16_t *line_buffer, uint length, fixed mx, fixed my, fixed dmx_dx) {
for (int x = 0; x < length; ++x) {
int iters;
fixed cr = mx;
fixed ci = my;
fixed zr = cr;
fixed zi = ci;
fixed xold = 0;
fixed yold = 0;
int period = 0;
for (iters = 0; iters < max_iters; ++iters) {
fixed zr2 = fixed_mult(zr, zr);
fixed zi2 = fixed_mult(zi, zi);
if (zr2 + zi2 > max) {
break;
}
fixed zrtemp = zr2 - zi2 + cr;
zi = 2 * fixed_mult(zr, zi) + ci;
zr = zrtemp;
if (zr == xold && zi == yold) {
iters = max_iters + 1;
break;
}
if (++period > 20) {
period = 0;
xold = zr;
yold = zi;
}
}
if (iters == max_iters + 1) {
line_buffer[x] = 0;//x1f;
} else {
line_buffer[x] = iters == max_iters ? 0 : colors[iters & 15u];
}
mx += dmx_dx;
}
}
// "Worker thread" for each core
void __time_critical_func(render_loop)() {
static uint32_t last_frame_num = 0;
int core_num = get_core_num();
printf("Rendering on core %d\n", core_num);
while (true) {
mutex_enter_blocking(&frame_logic_mutex);
if (y == vga_mode.height) {
params_ready = false;
frame_update_logic();
y = 0;
}
uint _y = y++;
fixed _x0 = x0, _y0 = y0;
fixed _dx0_dx = dx0_dx, _dy0_dy = dy0_dy;
mutex_exit(&frame_logic_mutex);
scanline(framebuffer + _y * 320, 320, _x0, _y0 + _dy0_dy * _y, _dx0_dx);
#if !PICO_ON_DEVICE
struct scanvideo_scanline_buffer *buffer = scanvideo_begin_scanline_generation(true);
fill_scanline_buffer(buffer);
scanvideo_end_scanline_generation(buffer);
#endif
}
}
int64_t timer_callback(alarm_id_t alarm_id, void *user_data) {
struct scanvideo_scanline_buffer *buffer = scanvideo_begin_scanline_generation(false);
while (buffer) {
fill_scanline_buffer(buffer);
scanvideo_end_scanline_generation(buffer);
buffer = scanvideo_begin_scanline_generation(false);
}
return 100;
}
void fill_scanline_buffer(struct scanvideo_scanline_buffer *buffer) {
static uint32_t postamble[] = {
0x0000u | (COMPOSABLE_EOL_ALIGN << 16)
};
buffer->data[0] = 4;
buffer->data[1] = host_safe_hw_ptr(buffer->data + 8);
buffer->data[2] = 158; // first four pixels are handled separately
uint16_t *pixels = framebuffer + scanvideo_scanline_number(buffer->scanline_id) * 320;
buffer->data[3] = host_safe_hw_ptr(pixels + 4);
buffer->data[4] = count_of(postamble);
buffer->data[5] = host_safe_hw_ptr(postamble);
buffer->data[6] = 0;
buffer->data[7] = 0;
buffer->data_used = 8;
// 3 pixel run followed by main run, consuming the first 4 pixels
buffer->data[8] = (pixels[0] << 16u) | COMPOSABLE_RAW_RUN;
buffer->data[9] = (pixels[1] << 16u) | 0;
buffer->data[10] = (COMPOSABLE_RAW_RUN << 16u) | pixels[2];
buffer->data[11] = ((317 + 1 - 3) << 16u) | pixels[3]; // note we add one for the black pixel at the end
}
struct semaphore video_setup_complete;
void core1_func() {
sem_acquire_blocking(&video_setup_complete);
render_loop();
}
int vga_main(void) {
// framebuffer = calloc(320*240, sizeof(uint16_t));
mutex_init(&frame_logic_mutex);
sem_init(&video_setup_complete, 0, 1);
// Core 1 will wait for us to finish video setup, and then start rendering
multicore_launch_core1(core1_func);
hard_assert(vga_mode.width + 4 <= PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS * 2);
scanvideo_setup(&vga_mode);
scanvideo_timing_enable(true);
frame_update_logic();
sem_release(&video_setup_complete);
#if PICO_ON_DEVICE
add_alarm_in_us(100, timer_callback, NULL, true);
#endif
render_loop();
return 0;
}
static inline void raw_scanline_finish(struct scanvideo_scanline_buffer *dest) {
// Need to pivot the first pixel with the count so that PIO can keep up
// with its 1 pixel per 2 clocks
uint32_t first = dest->data[0];
uint32_t second = dest->data[1];
dest->data[0] = (first & 0x0000ffffu) | ((second & 0x0000ffffu) << 16);
dest->data[1] = (second & 0xffff0000u) | ((first & 0xffff0000u) >> 16);
dest->status = SCANLINE_OK;
}
void __time_critical_func(frame_update_logic)() {
if (!params_ready) {
float scale = vga_mode.height / 2;
static int foo;
float offx = (MIN(foo, 200)) / 500.0f;
float offy = -(MIN(foo, 230)) / 250.0f;
scale *= (10000 + (foo++) * (float) foo) / 10000.0f;
x0 = float_to_fixed(offx + (-vga_mode.width / 2) / scale - 0.5f);
y0 = float_to_fixed(offy + (-vga_mode.height / 2) / scale);
dx0_dx = float_to_fixed(1.0f / scale);
dy0_dy = float_to_fixed(1.0f / scale);
max = float_to_fixed(4.f);
params_ready = true;
}
}
int main(void) {
#if PICO_ON_DEVICE
#ifdef TURBO_BOOST
hw_set_bits(&mm_vreg_and_chip_reset->vreg, VREG_AND_CHIP_RESET_VREG_VSEL_BITS);
sleep_ms(10);
set_sys_clock_khz(48000*6, true);
#else
//set_sys_clock(1536*MHZ, 4, 2);
set_sys_clock_khz(48000 * 4, true);
#endif
#endif
// Re init uart now that clk_peri has changed
setup_default_uart();
gpio_debug_pins_init();
return vga_main();
}

Wyświetl plik

@ -0,0 +1,29 @@
if (PICO_ON_DEVICE AND TARGET pico_scanvideo_dpi)
add_executable(mario_tiles
mario_tiles.c
data.c
data.h
)
add_compile_definitions(mario_tiles PRIVATE
# DISABLE_HPIXELS
PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS=200
PICO_SCANVIDEO_PLANE_COUNT=2
PICO_SCANVIDEO_PLANE2_VARIABLE_FRAGMENT_DMA=1
PICO_SCANVIDEO_MAX_SCANLINE_BUFFER2_WORDS=200
PICO_SCANVIDEO_SCANLINE_BUFFER_COUNT=5
PICO_SCANVIDEO_ENABLE_VIDEO_CLOCK_DOWN=1
)
target_link_libraries(mario_tiles PRIVATE
pico_stdlib
pico_multicore
pico_scanvideo_dpi
render)
if (PICO_ON_DEVICE)
target_link_libraries(mario_tiles PRIVATE
hardware_interp)
endif()
pico_add_extra_outputs(mario_tiles)
endif()

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,13 @@
#ifndef SOFTWARE_DATA_H
#define SOFTWARE_DATA_H
#include "image.h"
extern const struct tile_data16 tiles_tile_data;
extern int level0_map_width;
extern int level0_map_height;
extern uint16_t level0_map[];
extern const struct tile_data16 galaga_tile_data;
#endif //SOFTWARE_DATA_H

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,696 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "stdlib.h"
#include "pico/sync.h"
#include "pico/stdlib.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/multicore.h"
#include "data.h"
#if PICO_ON_DEVICE
#include "hardware/interp.h"
#endif
CU_REGISTER_DEBUG_PINS(frame_gen)
//CU_SELECT_DEBUG_PINS(frame_gen)
//#define DEBUG_HALF_PIXEL
typedef bool (*render_scanline_func)(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_test_pattern(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_bg(struct scanvideo_scanline_buffer *dest, int core);
////#define vga_mode vga_mode_640x480_60
#define vga_mode vga_mode_320x240_60
//#define vga_mode vga_mode_213x160_60
//#define vga_mode vga_mode_160x120_60
////#define vga_mode vga_mode_tft_800x480_50
//#define vga_mode vga_mode_tft_400x240_50
#define COUNT ((vga_mode.width/8))
// for now we want to see second counter on native and don't need both cores
#if !PICO_NO_HARDWARE
// todo there is a bug in multithreaded rendering atm
#define RENDER_ON_CORE0
#endif
#define RENDER_ON_CORE1
//#define IRQS_ON_CORE1
render_scanline_func render_scanline = render_scanline_bg;
#define COORD_SHIFT 3
int vspeed = 1*1;
int hspeed = 1<<COORD_SHIFT;
int hpos;
int vpos;
static const int input_pin0 = 22;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
static struct mutex frame_logic_mutex;
static int x_sprites = 1;
const int16_t hacky_cos_table[] = {
16384, 16383, 16382, 16381, 16379, 16376, 16372, 16368, 16364, 16359, 16353, 16346, 16339, 16331, 16323, 16314,
16305, 16294, 16284, 16272, 16260, 16248, 16234, 16221, 16206, 16191, 16175, 16159, 16142, 16125, 16107, 16088,
16069, 16049, 16028, 16007, 15985, 15963, 15940, 15917, 15892, 15868, 15842, 15817, 15790, 15763, 15735, 15707,
15678, 15649, 15618, 15588, 15557, 15525, 15492, 15459, 15426, 15392, 15357, 15322, 15286, 15249, 15212, 15175,
15136, 15098, 15058, 15018, 14978, 14937, 14895, 14853, 14810, 14767, 14723, 14679, 14634, 14589, 14543, 14496,
14449, 14401, 14353, 14304, 14255, 14205, 14155, 14104, 14053, 14001, 13948, 13895, 13842, 13788, 13733, 13678,
13622, 13566, 13510, 13452, 13395, 13337, 13278, 13219, 13159, 13099, 13038, 12977, 12916, 12854, 12791, 12728,
12665, 12600, 12536, 12471, 12406, 12340, 12273, 12207, 12139, 12072, 12003, 11935, 11866, 11796, 11726, 11656,
11585, 11513, 11442, 11370, 11297, 11224, 11150, 11077, 11002, 10928, 10853, 10777, 10701, 10625, 10548, 10471,
10393, 10315, 10237, 10159, 10079, 10000, 9920, 9840, 9759, 9679, 9597, 9516, 9434, 9351, 9268, 9185,
9102, 9018, 8934, 8850, 8765, 8680, 8594, 8509, 8423, 8336, 8249, 8162, 8075, 7988, 7900, 7811,
7723, 7634, 7545, 7456, 7366, 7276, 7186, 7095, 7005, 6914, 6822, 6731, 6639, 6547, 6455, 6362,
6269, 6176, 6083, 5990, 5896, 5802, 5708, 5614, 5519, 5424, 5329, 5234, 5139, 5043, 4948, 4852,
4756, 4659, 4563, 4466, 4369, 4272, 4175, 4078, 3980, 3883, 3785, 3687, 3589, 3491, 3393, 3294,
3196, 3097, 2998, 2900, 2801, 2701, 2602, 2503, 2404, 2304, 2204, 2105, 2005, 1905, 1805, 1705,
1605, 1505, 1405, 1305, 1205, 1105, 1004, 904, 803, 703, 603, 502, 402, 301, 201, 100,
0, -100, -201, -301, -402, -502, -603, -703, -803, -904, -1004, -1105, -1205, -1305, -1405, -1505,
-1605, -1705, -1805, -1905, -2005, -2105, -2204, -2304, -2404, -2503, -2602, -2701, -2801, -2900, -2998, -3097,
-3196, -3294, -3393, -3491, -3589, -3687, -3785, -3883, -3980, -4078, -4175, -4272, -4369, -4466, -4563, -4659,
-4756, -4852, -4948, -5043, -5139, -5234, -5329, -5424, -5519, -5614, -5708, -5802, -5896, -5990, -6083, -6176,
-6269, -6362, -6455, -6547, -6639, -6731, -6822, -6914, -7005, -7095, -7186, -7276, -7366, -7456, -7545, -7634,
-7723, -7811, -7900, -7988, -8075, -8162, -8249, -8336, -8423, -8509, -8594, -8680, -8765, -8850, -8934, -9018,
-9102, -9185, -9268, -9351, -9434, -9516, -9597, -9679, -9759, -9840, -9920, -10000, -10079, -10159, -10237, -10315,
-10393, -10471, -10548, -10625, -10701, -10777, -10853, -10928, -11002, -11077, -11150, -11224, -11297, -11370, -11442, -11513,
-11585, -11656, -11726, -11796, -11866, -11935, -12003, -12072, -12139, -12207, -12273, -12340, -12406, -12471, -12536, -12600,
-12665, -12728, -12791, -12854, -12916, -12977, -13038, -13099, -13159, -13219, -13278, -13337, -13395, -13452, -13510, -13566,
-13622, -13678, -13733, -13788, -13842, -13895, -13948, -14001, -14053, -14104, -14155, -14205, -14255, -14304, -14353, -14401,
-14449, -14496, -14543, -14589, -14634, -14679, -14723, -14767, -14810, -14853, -14895, -14937, -14978, -15018, -15058, -15098,
-15136, -15175, -15212, -15249, -15286, -15322, -15357, -15392, -15426, -15459, -15492, -15525, -15557, -15588, -15618, -15649,
-15678, -15707, -15735, -15763, -15790, -15817, -15842, -15868, -15892, -15917, -15940, -15963, -15985, -16007, -16028, -16049,
-16069, -16088, -16107, -16125, -16142, -16159, -16175, -16191, -16206, -16221, -16234, -16248, -16260, -16272, -16284, -16294,
-16305, -16314, -16323, -16331, -16339, -16346, -16353, -16359, -16364, -16368, -16372, -16376, -16379, -16381, -16382, -16383,
-16384, -16383, -16382, -16381, -16379, -16376, -16372, -16368, -16364, -16359, -16353, -16346, -16339, -16331, -16323, -16314,
-16305, -16294, -16284, -16272, -16260, -16248, -16234, -16221, -16206, -16191, -16175, -16159, -16142, -16125, -16107, -16088,
-16069, -16049, -16028, -16007, -15985, -15963, -15940, -15917, -15892, -15868, -15842, -15817, -15790, -15763, -15735, -15707,
-15678, -15649, -15618, -15588, -15557, -15525, -15492, -15459, -15426, -15392, -15357, -15322, -15286, -15249, -15212, -15175,
-15136, -15098, -15058, -15018, -14978, -14937, -14895, -14853, -14810, -14767, -14723, -14679, -14634, -14589, -14543, -14496,
-14449, -14401, -14353, -14304, -14255, -14205, -14155, -14104, -14053, -14001, -13948, -13895, -13842, -13788, -13733, -13678,
-13622, -13566, -13510, -13452, -13395, -13337, -13278, -13219, -13159, -13099, -13038, -12977, -12916, -12854, -12791, -12728,
-12665, -12600, -12536, -12471, -12406, -12340, -12273, -12207, -12139, -12072, -12003, -11935, -11866, -11796, -11726, -11656,
-11585, -11513, -11442, -11370, -11297, -11224, -11150, -11077, -11002, -10928, -10853, -10777, -10701, -10625, -10548, -10471,
-10393, -10315, -10237, -10159, -10079, -10000, -9920, -9840, -9759, -9679, -9597, -9516, -9434, -9351, -9268, -9185,
-9102, -9018, -8934, -8850, -8765, -8680, -8594, -8509, -8423, -8336, -8249, -8162, -8075, -7988, -7900, -7811,
-7723, -7634, -7545, -7456, -7366, -7276, -7186, -7095, -7005, -6914, -6822, -6731, -6639, -6547, -6455, -6362,
-6269, -6176, -6083, -5990, -5896, -5802, -5708, -5614, -5519, -5424, -5329, -5234, -5139, -5043, -4948, -4852,
-4756, -4659, -4563, -4466, -4369, -4272, -4175, -4078, -3980, -3883, -3785, -3687, -3589, -3491, -3393, -3294,
-3196, -3097, -2998, -2900, -2801, -2701, -2602, -2503, -2404, -2304, -2204, -2105, -2005, -1905, -1805, -1705,
-1605, -1505, -1405, -1305, -1205, -1105, -1004, -904, -803, -703, -603, -502, -402, -301, -201, -100,
0, 100, 201, 301, 402, 502, 603, 703, 803, 904, 1004, 1105, 1205, 1305, 1405, 1505,
1605, 1705, 1805, 1905, 2005, 2105, 2204, 2304, 2404, 2503, 2602, 2701, 2801, 2900, 2998, 3097,
3196, 3294, 3393, 3491, 3589, 3687, 3785, 3883, 3980, 4078, 4175, 4272, 4369, 4466, 4563, 4659,
4756, 4852, 4948, 5043, 5139, 5234, 5329, 5424, 5519, 5614, 5708, 5802, 5896, 5990, 6083, 6176,
6269, 6362, 6455, 6547, 6639, 6731, 6822, 6914, 7005, 7095, 7186, 7276, 7366, 7456, 7545, 7634,
7723, 7811, 7900, 7988, 8075, 8162, 8249, 8336, 8423, 8509, 8594, 8680, 8765, 8850, 8934, 9018,
9102, 9185, 9268, 9351, 9434, 9516, 9597, 9679, 9759, 9840, 9920, 10000, 10079, 10159, 10237, 10315,
10393, 10471, 10548, 10625, 10701, 10777, 10853, 10928, 11002, 11077, 11150, 11224, 11297, 11370, 11442, 11513,
11585, 11656, 11726, 11796, 11866, 11935, 12003, 12072, 12139, 12207, 12273, 12340, 12406, 12471, 12536, 12600,
12665, 12728, 12791, 12854, 12916, 12977, 13038, 13099, 13159, 13219, 13278, 13337, 13395, 13452, 13510, 13566,
13622, 13678, 13733, 13788, 13842, 13895, 13948, 14001, 14053, 14104, 14155, 14205, 14255, 14304, 14353, 14401,
14449, 14496, 14543, 14589, 14634, 14679, 14723, 14767, 14810, 14853, 14895, 14937, 14978, 15018, 15058, 15098,
15136, 15175, 15212, 15249, 15286, 15322, 15357, 15392, 15426, 15459, 15492, 15525, 15557, 15588, 15618, 15649,
15678, 15707, 15735, 15763, 15790, 15817, 15842, 15868, 15892, 15917, 15940, 15963, 15985, 16007, 16028, 16049,
16069, 16088, 16107, 16125, 16142, 16159, 16175, 16191, 16206, 16221, 16234, 16248, 16260, 16272, 16284, 16294,
16305, 16314, 16323, 16331, 16339, 16346, 16353, 16359, 16364, 16368, 16372, 16376, 16379, 16381, 16382, 16383,
16384
};
void go_core1(void (*execute)());
void init_render_state(int core);
void print_status() {
printf("hspeed %d/8 (sprites %d) \r", hspeed, x_sprites);
}
// ok this is going to be the beginning of retained mode
//
struct tile_data16 runtime_tile_data;
int32_t ha_du, ha_dv, ha_dud, ha_dvd;
int32_t hacky_cos(int32_t angle) {
uint off = (angle >> 8)&0x3ff;
int32_t a = hacky_cos_table[off];
int32_t b = hacky_cos_table[off+1];
return a + ((b - a) * (angle & 0xff))/0x100;
}
int32_t hacky_sin(int32_t angle) {
return hacky_cos(angle - 0x10000);
}
// data is in the wrong color format
void convert_spans(const struct tile_data16 *td) {
#if PICO_ON_DEVICE
uint16_t *p = (uint16_t *) td->blob.bytes;
for (int i = 0; i < td->blob.size / 2; i++) {
uint r = p[i] & 0x1f;
uint g = (p[i] >> 5) & 0x1f;
uint b = (p[i] >> 10) & 0x1f;
uint alpha = p[i] >> 15;
p[i] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(r, g, b) | (alpha ? PICO_SCANVIDEO_ALPHA_MASK : 0);
}
#endif
}
int render_loop() {
static uint8_t last_input = 0;
static uint32_t last_frame_num = 0;
int core_num = get_core_num();
assert(core_num >=0 && core_num < 2);
printf("Rendering on core %d\r\n", core_num);
#if DEBUG_PINS_ENABLED(frame_gen)
if (core_num == 1) {
gpio_init(PICO_DEBUG_PIN_BASE+1);
gpio_set_dir_out_masked(2 << PICO_DEBUG_PIN_BASE); // steal debug pin 2 for this core
}
#endif
while (true) {
struct scanvideo_scanline_buffer *scanvideo_scanline_buffer = scanvideo_begin_scanline_generation(true);
// if (scanline_buffer->data_used) {
// // validate the previous scanline to make sure noone corrupted it
// validate_scanline(scanline_buffer->data, scanline_buffer->data_used, vga_mode.width, vga_mode.width);
// }
// do any frame related logic
bool ps = false;
// todo probably a race condition here ... thread dealing with last line of a frame may end
// todo up waiting on the next frame...
mutex_enter_blocking(&frame_logic_mutex);
uint32_t frame_num = scanvideo_frame_number(scanvideo_scanline_buffer->scanline_id);
// note that with multiple cores we may have got here not for the first scanline, however one of the cores will do this logic first before either does the actual generation
if (frame_num != last_frame_num) {
if (frame_num == 1) {
ps = true;
}
// this could should be during vblank as we try to create the next line
// todo should we ignore if we aren't attempting the next line
last_frame_num = frame_num;
// if (enable_wave) {
uint32_t angle2 = frame_num * 17;
int64_t amp2 = 0x10000 + (2* hacky_sin(frame_num * 120));
amp2 /= 8;
// int64_t amp2 = 4 * (1.3f - 0.5f * ((cos(0.3f + frame_num * (M_PI_4 / 60.0f))) +
// cos(frame_num * (M_PI_4 / 120.0f))));
ha_du = (int32_t) ((amp2 * hacky_cos(angle2)) / 0x4000);
ha_dv = (int32_t) ((amp2 * hacky_sin(-angle2)) / 0x4000);
ha_dud = -ha_dv;
ha_dvd = ha_du;
// }
#if PICO_ON_DEVICE
if (uart_is_readable(uart_default)) {
int c = uart_getc(uart_default);
switch (c) {
case '+':
case '=':
hspeed++;
break;
case '_':
case '-':
hspeed--;
break;
case '9':
if (x_sprites > 0) x_sprites--;
break;
case '0':
if (x_sprites < 17) x_sprites++;
break;
}
ps = true;
}
#endif
hpos += hspeed;
if (hpos < 0) {
hpos = 0;
hspeed = -hspeed;
} else if (hpos >= (level0_map_width*8 - vga_mode.width) << COORD_SHIFT) {
hpos = (level0_map_width*8 - vga_mode.width) << COORD_SHIFT;
hspeed = -hspeed;
}
uint8_t new_input = gpio_get(input_pin0);
if (last_input && !new_input) {
hpos++;
}
last_input = new_input;
}
mutex_exit(&frame_logic_mutex);
DEBUG_PINS_SET(frame_gen, core_num?2:4);
render_scanline(scanvideo_scanline_buffer, core_num);
DEBUG_PINS_CLR(frame_gen, core_num?2:4);
#if PICO_SCANVIDEO_PLANE_COUNT > 2
assert(false);
#endif
// release the scanline into the wild
scanvideo_end_scanline_generation(scanvideo_scanline_buffer);
// do this outside mutex and scanline generation
if (ps) {
print_status();
}
}
}
struct semaphore video_setup_complete;
void setup_video() {
scanvideo_setup(&vga_mode);
scanvideo_timing_enable(true);
sem_release(&video_setup_complete);
}
void core1_func() {
#ifdef IRQS_ON_CORE1
setup_video();
#endif
#ifdef RENDER_ON_CORE1
render_loop();
#endif
}
#define TEST_WAIT_FOR_SCANLINE
#ifdef TEST_WAIT_FOR_SCANLINE
volatile uint32_t scanline_color = 0;
#endif
int video_main(void) {
assert(vga_mode.xscale >= 2); // too slow anyway, but we would need to turn half pixel off
mutex_init(&frame_logic_mutex);
//gpio_debug_pins_init()''
// need to inflat the tiles for this demo (can't reuse span data)
runtime_tile_data.blob.size = tiles_tile_data.width * tiles_tile_data.height * tiles_tile_data.count * 2;
runtime_tile_data.blob.bytes = malloc(runtime_tile_data.blob.size);
assert(runtime_tile_data.blob.bytes);
const int width = tiles_tile_data.width * 2;
for(int i=0;i<tiles_tile_data.count * tiles_tile_data.height;i++) {
const uint8_t *src = tiles_tile_data.blob.bytes + tiles_tile_data.span_offsets[i];
__builtin_memcpy((uint8_t *)runtime_tile_data.blob.bytes + i * width, src, width);
}
// get the bottom
vpos = level0_map_height*8 - vga_mode.height;
assert(vpos >= 0);
convert_spans(&runtime_tile_data);
convert_spans(&galaga_tile_data);
sem_init(&video_setup_complete, 0, 1);
#ifndef IRQS_ON_CORE1
setup_video();
#endif
puts("KEYS:");
puts(" +/- adjust horizonatal speed");
puts(" 9/0 up/down horizontal sprite count");
init_render_state(0);
#ifdef RENDER_ON_CORE1
init_render_state(1);
#endif
#if defined(RENDER_ON_CORE1) || defined(IRQS_ON_CORE1)
go_core1(core1_func);
#endif
#ifdef RENDER_ON_CORE0
render_loop();
#else
sem_acquire_blocking(&video_setup_complete);
while (true) {
#ifndef TEST_WAIT_FOR_SCANLINE
// Just use vblank to print out a value every second
static int i=0, s=0;
video_wait_for_vblank();
if (++i == 60) {
printf("%d\n", s++);
i = 0;
}
#else
static uint32_t sl = 0;
sl = scanvideo_wait_for_scanline_complete(sl);
scanline_color = (scanline_color + 0x10u) & 0xffu;
#endif
}
#endif
__builtin_unreachable();
}
//struct palette16 *opaque_pi_palette = NULL;
// must not be called concurrently
void init_render_state(int core) {
// todo we should of course have a wide solid color span that overlaps
// todo we can of course also reuse these
// init_solid_color_span(&before_span[core], left, opaque_pi_palette->entries[15], NULL);
// init_vogon_4bit_span(&pi_span[core], pi400_image_data.width, NULL, 0, opaque_pi_palette, &before_span[core]);
// init_solid_color_span(&after_span[core], vga_mode.width - left - pi400_image_data.width, opaque_pi_palette->entries[15],
// &pi_span[core]);
}
uint16_t __attribute__((noinline)) *tile_loop(uint16_t *buf, int w0, uint32_t u, uint32_t v, int32_t du, int32_t dv) {
const int FRACTIONAL_BITS = 16;
const int MAP_BITS_U = 8;
const int MAP_BITS_V = 5;
#if PICO_ON_DEVICE
interp0->base[0] = du;
interp_config config = interp_default_config();
interp_config_set_shift(&config, FRACTIONAL_BITS - 1);
interp_config_set_mask(&config, 1, MAP_BITS_U);
interp_config_set_add_raw(&config, true);
interp_set_config(interp0, 0, &config);
interp0->base[1] = dv;
config = interp_default_config();
interp_config_set_shift(&config, FRACTIONAL_BITS - MAP_BITS_U - 1);
interp_config_set_mask(&config, 1 + MAP_BITS_U, 1 + MAP_BITS_U + (MAP_BITS_V - 1));
interp_config_set_add_raw(&config, true);
interp_set_config(interp0, 1, &config);
interp0->base[2] = (uintptr_t) level0_map;
interp0->accum[0] = u;
interp0->accum[1] = v;
const int FRACTIONAL_BITS2 = 13;
const int TILE_BITS_U = 3;
const int TILE_BITS_V = 3;
interp1->base[0] = du;
config = interp_default_config();
interp_config_set_shift(&config, FRACTIONAL_BITS2 - 1);
interp_config_set_mask(&config, 1, TILE_BITS_U);
interp_config_set_add_raw(&config, true);
interp_set_config(interp1, 0, &config);
interp1->base[1] = dv;
config = interp_default_config();
interp_config_set_shift(&config, FRACTIONAL_BITS2 - TILE_BITS_U - 1);
interp_config_set_mask(&config, 1 + TILE_BITS_U, 1 + TILE_BITS_U + (TILE_BITS_V - 1));
interp_config_set_add_raw(&config, true);
interp_set_config(interp1, 1, &config);
interp1->base[2] = (uintptr_t) runtime_tile_data.blob.bytes;
interp1->accum[0] = u;
interp1->accum[1] = v;
for (int w = 0; w < w0; w++) {
for(int i=0;i<8;i++) {
uint16_t *map = (uint16_t *)interp0->pop[2];
uint16_t *base = (uint16_t *)interp1->pop[2];
*buf++ = base[64 * *map];
}
}
#else
for (int w = 0; w < w0; w++) {
for(int i=0;i<8;i++) {
*buf++ = 0x421*i;
}
}
#endif
return buf;
}
bool render_scanline_bg(struct scanvideo_scanline_buffer *dest, int core) {
// 1 + line_num red, then white
uint32_t *buf = dest->data;
int y = scanvideo_scanline_number(dest->scanline_id) + vpos;
int x = hpos;
//y = (y + frame_number(dest->scanline_id)) % (level0_map_height * 8);
const uint16_t *map = level0_map + level0_map_width * (y/8);
map += (x >> (COORD_SHIFT + 3));
const uint16_t *map0 = map;
const uint8_t *data_base /* ha */ = runtime_tile_data.blob.bytes + (y&7u)*16;
uint32_t *output32;
uint32_t off;
uint16_t *data;
// const uint16_t *span_offsets = runtime_tile_data.span_offsets + (y&7u);
#if !PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA
uint16_t *output = (uint16_t*)buf;
*output++ = COMPOSABLE_RAW_RUN;
uint16_t *fixup = output;
*output++ = 0;
#if 0
for(int i=0;i<COUNT;i++) {
uint32_t off = 128 * (*map++);
uint16_t *data = (uint16_t *)(data_base + off);
for(int j=0;j<8;j++) *output++ = *data++;
}
#else
int32_t u = x << (13 - COORD_SHIFT);
int32_t v = 0;
u += ha_dud * (y - vpos);
v += ha_dvd * (y - vpos);
output = tile_loop(output, COUNT, u, v, ha_du, ha_dv);
#endif
fixup[0] = fixup[1];
fixup[1] = COUNT * 8 - 3;
// todo fix so we don't need whole scanline
// *output++ = COMPOSABLE_COLOR_RUN;
// *output++ = 0;
// *output++ = vga_mode.width - COUNT * 8 - 1 - 3;
// end of line stuff
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
if (2 & (intptr_t)output) {
// we are unaligned
*output++ = COMPOSABLE_EOL_ALIGN;
} else {
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff; // eye catcher
}
assert(0 == (3u & (intptr_t)output));
assert((uint32_t*)output <= (buf + dest->data_max));
dest->data_used = (uint16_t)(((uint32_t*)output) - buf);
#else
// we handle both ends separately
// static const uint32_t end_of_line[] = {
// COMPOSABLE_RAW_1P | (0u<<16),
// COMPOSABLE_EOL_SKIP_ALIGN | (0xffff << 16) // eye catcher ffff
// };
output32 = buf + 2; // skip one chain segment - we fill in below
map++; // skip first element
off = 128 * map0[0];
int i = (x>>COORD_SHIFT)&7;
int eol_pixels = i;
data = (uint16_t *)(data_base + off);
data += i;
int j;
if (i>=7) {
j = 1;
// skip second element in the offset 7 7/12 case
map++;
} else {
j = 0;
}
// render full size tiles
for(;j<COUNT;j++) {
uint32_t off = 128 * *map++;
uint16_t *data = (uint16_t *)(data_base + off);
*output32++ = 4;
assert(!(3u & (intptr_t)data));
*output32++ = native_safe_hw_ptr(data);
}
// end of scanline // to be filled in below
*output32++ = 0;
*output32++ = 0;
// end of dma chain (correct 0 values)
*output32++ = 0;
*output32++ = 0;
uint16_t *output = (uint16_t*)output32;
// draw a possibly fractional first tile
// 0: RUN T00 | LEN T01 | T02 T03 | T04 T05 | T06 T07 |
// 1: R2P T01 | T02 RUN | T03 LEN | T04 T05 | T06 T07 |
// 2: RUN T02 | LEN T03 | T04 T05 | T06 T07 |
// 3: R2P T03 | T04 RUN | T05 LEN | T06 T07 |
// 4: RUN T04 | LEN T05 | T06 T07 |
// 5: R2P T05 | T06 RUN | T05 LEN | T06 T07 |
// 6: RUN T06 | LEN T07 |
// 7: R2P T07 | T10 RUN | T11 LEN | T12 T13 | T14 T15 | T16 T17 |
// with half pixel (i.e we set i to i+1 above, and always prefix)
// 0: H1P T00 | R2P T01 | T02 RUN | T03 LEN | T04 T05 | T06 T07 |
// 1: H1P T01 | RUN T02 | LEN T03 | T04 T05 | T06 T07 |
// 2: H1P T02 | R2P T03 | T04 RUN | T05 LEN | T06 T07 |
// 3: H1P T03 | RUN T04 | LEN T05 | T06 T07 |
// 4: H1P T04 | R2P T05 | T06 RUN | T05 LEN | T06 T07 |
// 5: H1P T05 | RUN T06 | LEN T07 |
// 6: H1P T06 | R2P T07 | T10 RUN | T11 LEN | T12 T13 | T14 T15 | T16 T17 |
// 7: H1P T07 | RUN T10 | LEN T11 | T12 T13 | T14 T15 | T16 T17 |
int run_length = (8 - (i & 7u)) + COUNT * 8 - 3;
if (i&1) {
*output++ = COMPOSABLE_RAW_2P;
*output++ = *data++;
if (i==7) {
// cope with the case where we've stepped onto the new tile
off = 128 * map0[1];
data = (uint16_t *)(data_base + off);
i = 1;
} else {
i += 2;
}
run_length -= 2;
*output++ = *data++;
*output++ = COMPOSABLE_RAW_RUN;
} else {
*output++ = COMPOSABLE_RAW_RUN;
}
*output++ = *data++;
*output++ = run_length;
for (; i < 7; i++) {
*output++ = *data++;
}
assert(0 == (3u & (intptr_t)output));
// setup our first chain segment (to point into our buffer here)
buf[0] = ((uint32_t *)output) - output32;
buf[1] = native_safe_hw_ptr(output32);
// end of line
uint32_t *eol_base = (uint32_t*)output;
if (eol_pixels) {
off = 128 * *map++;
data = (uint16_t *) (data_base + off);
switch (eol_pixels) {
// we could be slightly more optimal in the non half pixel case, but don't reall care
case 0:
break;
case 1:
*output++ = COMPOSABLE_RAW_1P;
*output++ = *data++;
break;
case 2:
*output++ = COMPOSABLE_RAW_2P;
*output++ = *data++;
*output++ = *data++;
break;
default:
*output++ = COMPOSABLE_RAW_RUN;
*output++ = *data++;
*output++ = eol_pixels - 3;
for (int i = 1; i < eol_pixels; i++) {
*output++ = *data++;
}
break;
}
}
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
if (2u & (intptr_t)output) {
*output++ = COMPOSABLE_EOL_ALIGN;
} else {
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff; // eye catcher
}
// setup our last chain segment (to point into our buffer here)
output32[-4] = ((uint32_t *)output) - eol_base;; //len
output32[-3] = native_safe_hw_ptr(eol_base);
assert(0 == (3u & (intptr_t)output));
assert((uint32_t*)output <= (buf + dest->data_max));
dest->data_used = (uint16_t)(output32 - buf); // todo we don't want to include the off the end data in the "size" for the dma
#endif
// why was this here, it is buf anyway!
// dest->data = buf;
#if PICO_SCANVIDEO_PLANE_COUNT > 1
#if !PICO_SCANVIDEO_PLANE2_VARIABLE_FRAGMENT_DMA
assert(false);
#endif
buf = dest->data2;
output32 = buf;
uint32_t *inline_data = output32 + PICO_SCANVIDEO_MAX_SCANLINE_BUFFER2_WORDS / 2;
output = (uint16_t *)inline_data;
uint32_t *base = (uint32_t *)output;
#define MAKE_SEGMENT \
assert(0 == (3u & (intptr_t)output)); \
*output32++ = (uint32_t*)output - base; \
*output32++ = host_safe_hw_ptr(base); \
base = (uint32_t *)output;
int wibble = (scanvideo_frame_number(dest->scanline_id) >> 2) % 7;
for(int q = 0; q < x_sprites; q++) {
// nice if we can do two black pixel before
*output++ = COMPOSABLE_RAW_RUN;
*output++ = 0;
*output++ = galaga_tile_data.width + 2 - 3;
*output++ = 0;
MAKE_SEGMENT;
const uint16_t *span_offsets = galaga_tile_data.span_offsets + (q+wibble) * galaga_tile_data.height + (y - vpos);//(y%galaga_tile_data.count 7u);
off = span_offsets[0];
data = (uint16_t *) (galaga_tile_data.blob.bytes + off);
*output32++ = galaga_tile_data.width / 2;
*output32++ = host_safe_hw_ptr(data);
}
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff;
MAKE_SEGMENT;
// end of dma chain
*output32++ = 0;
*output32++ = 0;
assert(output32 < inline_data);
assert((uint32_t*)output <= (buf + dest->data2_max));
dest->data2_used = (uint16_t)(output32 - buf); // todo we don't want to include the inline data in the "size" for the dma
#endif
dest->status = SCANLINE_OK;
return true;
}
void go_core1(void (*execute)()) {
multicore_launch_core1(execute);
}
int main(void) {
set_sys_clock_48mhz();
setup_default_uart();
#if PICO_NO_HARDWARE
//#include <math.h>
// for(int i = 0; i<64;i++) {
// printf("%d, ", (int)(0x7f*cos(i*M_PI/32)));
// }
// printf("\n");
#endif
//#include "level0.h"
// uint8_t *p = level0_dat;
// int w = 1<<p[0];
// int h = 1<<p[1];
// printf("const int level0_map_width = %d;\n", w);
// printf("const int level0_map_height = %d;\n", h);
// printf("const uint16_t level0_map = {\n");
// for (int i = 0; i < w*h; i += 32) {
// printf("\t\t");
// for (int j = i; j < w*h && j < (i + 32); j++) {
// uint8_t *q = p + 2 + j*2;
// printf("0x%04x, ", q[0]*256+q[1]);
// }
// printf("\n");
// }
// printf("};\n");
return video_main();
}

Wyświetl plik

@ -0,0 +1,12 @@
add_library(render INTERFACE)
cmake_policy(SET CMP0076 NEW)
target_sources(render INTERFACE
image.c
image.h
spans.c
spans.h
)
target_include_directories(render INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(render INTERFACE pico_base_headers)

Wyświetl plik

@ -0,0 +1 @@
This `render` library is entirely legacy - it just supports the example `demo1`

Wyświetl plik

@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdlib.h>
#include "image.h"
#include "pico/scanvideo.h"
struct palette16 *blend_palette(const struct palette32 *source, uint32_t back_color) {
struct palette16 *dest = (struct palette16 *) malloc(sizeof(struct palette16) + source->size * sizeof(uint16_t));
dest->flags =
CF_PALETTE_COMPOSITED | (source->flags & ~(CF_HAS_SEMI_TRANSPARENT | CF_HAS_TRANSPARENT)) | CF_HAS_OPAQUE;
dest->composited_on_color = back_color;
dest->size = source->size;
uint32_t __unused ba = (back_color >> 24) & 0xff;
uint32_t bb = (back_color >> 16) & 0xff;
uint32_t bg = (back_color >> 8) & 0xff;
uint32_t br = (back_color >> 0) & 0xff;
assert(ba == 255); // expect to be on an opaque color
for (int i = 0; i < source->size; i++) {
uint32_t fore_color = source->entries[i];
uint32_t fa = (fore_color >> 24) & 0xff;
uint32_t fb = (fore_color >> 16) & 0xff;
uint32_t fg = (fore_color >> 8) & 0xff;
uint32_t fr = (fore_color >> 0) & 0xff;
if (!i && !fa) {
// even though we don't record alpha in the blended palette, we may care to use a color key (of 0)
dest->flags |= CF_PALETTE_INDEX_0_TRANSPARENT;
}
if (fa == 255) fa = 256;
fb = (fa * fb + (256 - fa) * bb) >> 11;
fg = (fa * fg + (256 - fa) * bg) >> 11;
fr = (fa * fr + (256 - fa) * br) >> 11;
dest->entries[i] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(fr, fg, fb);
}
return dest;
}

Wyświetl plik

@ -0,0 +1,74 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _RENDER_IMAGE_H
#define _RENDER_IMAGE_H
#include "pico.h"
typedef uint16_t short_flags;
// common flags
#define CF_HAS_OPAQUE ((short_flags)1)
#define CF_HAS_SEMI_TRANSPARENT ((short_flags)2)
#define CF_HAS_TRANSPARENT ((short_flags)4)
#define CF_PALETTE_INDEX_0_TRANSPARENT ((short_flags)8)
#define CF_PALETTE_COMPOSITED ((short_flags)16)
#define CF_OPACITY_MASK (CF_HAS_OPAQUE | CF_HAS_SEMI_TRANSPARENT | CF_HAS_TRANSPARENT)
struct palette32 {
uint16_t size;
short_flags flags;
uint32_t entries[];
};
struct palette16 {
uint16_t size;
short_flags flags;
uint32_t composited_on_color; // if flags & CF_PALETTE_COMPOSITED
uint16_t entries[];
};
enum image_format {
IMG_FMT_4BIT_VOGON = 1,
IMG_FMT_8_BIT_RAW,
IMG_FMT_16_BIT_RAW
};
struct blob {
size_t size;
const uint8_t *bytes;
};
struct image_data {
int format;
int width;
int height;
struct blob blob;
const uint16_t *row_offsets; // optional and possibly initted on demand
};
struct tile_data {
uint8_t depth;
uint16_t count;
uint16_t width;
uint16_t height;
struct blob blob;
const uint16_t *span_numbers;
};
struct tile_data16 {
uint16_t count;
uint16_t width;
uint16_t height;
struct blob blob;
const uint16_t *span_offsets;
};
extern struct palette16 *blend_palette(const struct palette32 *source, uint32_t back_color);
#endif //SOFTWARE_IMAGE_H

Wyświetl plik

@ -0,0 +1,454 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include "pico.h"
#include "image.h"
#include "spans.h"
#include "pico/scanvideo/composable_scanline.h"
#ifdef __arm__
#pragma GCC push_options
#pragma GCC optimize("O3")
#endif
#ifdef ENABLE_SPAN_ASSERTIONS
#define span_assert(x) assert(x)
#else
#define span_assert(x) false
#endif
inline static void
init_span(struct span *span, uint8_t type, uint16_t flags, uint16_t visible_width, struct span *prev) {
memset(span, 0, sizeof(struct span));
if (prev) {
prev->next = span;
}
span->flags = flags;
span->width = visible_width;
span->type = type;
}
void init_solid_color_span(struct span *span, uint16_t width, uint16_t color16, struct span *prev) {
init_span(span, SPAN_SOLID, CF_HAS_OPAQUE, width, prev);
set_solid_color_span_color(span, color16);
}
void init_vogon_4bit_span(struct span *span, uint16_t content_width, const uint8_t *encoding, uint16_t encoded_size,
struct palette16 *palette, struct span *prev) {
// by default we have a clip_left of 0, and a width of content_width
init_span(span, SPAN_4BIT_VOGON_OPAQUE, palette->flags & CF_OPACITY_MASK, content_width, prev);
set_vogon_4bit_span_encoding(span, encoding, encoded_size);
span->vogon.content_width = content_width;
span->vogon.palette = palette;
// palette should be opaque
assert(CF_HAS_OPAQUE == (palette->flags & CF_OPACITY_MASK));
}
void __time_critical_func(set_solid_color_span_color)(struct span *span, uint16_t color16) {
assert(span->type == SPAN_SOLID);
span->solid.color16 = color16;
}
void __time_critical_func(set_vogon_4bit_span_encoding)(struct span *span, const uint8_t *data, uint16_t data_length) {
assert(span->type == SPAN_4BIT_VOGON_OPAQUE);
span->vogon.data = data;
span->vogon.data_length = data_length;
}
void __time_critical_func(set_vogon_4bit_clipping)(struct span *span, int clip_left, int display_width) {
assert(span->type == SPAN_4BIT_VOGON_OPAQUE);
assert(clip_left >= 0);
assert(display_width >= 0); // todo should we allow this? probably
assert(clip_left + display_width <= span->vogon.content_width);
span->vogon.clip_left = clip_left;
span->width = display_width;
}
// todo needs to be shared - currently the same as GAP_SKIPPED_PIXELS as it happens
#define MIN_COLOR_RUN 3
// todo allow for chained DMA (indeed, we may have a pool of small fixed size chunks (says 64 words) we can re-use for scanlines anyway - a big scanline could use more than one
// todo but we can simply split our rendering across them (and link them into the chain)... this will make it easier to join in raw data etc.
// todo simple span allocation
int32_t __time_critical_func(single_color_scanline)(uint32_t *buf, size_t buf_length, int width, uint32_t color16) {
assert(buf_length >= 2);
assert(width >= MIN_COLOR_RUN);
// | jmp color_run | color | count-3 | buf[0] =
buf[0] = COMPOSABLE_COLOR_RUN | (color16 << 16);
buf[1] = (width - MIN_COLOR_RUN) | (COMPOSABLE_RAW_1P << 16);
// note we must end with a black pixel
buf[2] = 0 | (COMPOSABLE_EOL_ALIGN << 16);
return 3;
}
#define output_4bit_paletted_pixels_ff(output, palette_entries, encoding, count) if (true) { \
span_assert((count)>0); \
span_assert(!((count)&1)); \
uint32_t p = *encoding++; \
if ((count)>2) { \
*output++ = COMPOSABLE_RAW_RUN; \
*output++ = palette_entries[p&0xf]; \
*output++ = (count) - 3; \
*output++ = palette_entries[p>>4]; \
int c = count; \
while (0 < (c = c -2)) { \
p = *encoding++; \
*output++ = palette_entries[p&0xf]; \
*output++ = palette_entries[p>>4]; \
} \
} else { \
*output++ = COMPOSABLE_RAW_2P; \
*output++ = palette_entries[p&0xf]; \
*output++ = palette_entries[p>>4]; \
} \
} else __builtin_unreachable()
#define output_4bit_paletted_pixels_fx(output, palette_entries, encoding, count) if (true) { \
span_assert((count)>0); \
uint32_t p = *encoding++; \
if ((count)>2) { \
*output++ = COMPOSABLE_RAW_RUN; \
*output++ = palette_entries[p&0xf]; \
*output++ = (count) - 3; \
*output++ = palette_entries[p>>4]; \
int c = count; \
while (1 < (c = c -2)) { \
p = *encoding++; \
*output++ = palette_entries[p&0xf]; \
*output++ = palette_entries[p>>4]; \
} \
if (count & 1) { \
p = *encoding++; \
*output++ = palette_entries[p&0xf]; \
} \
} else { \
if ((count) == 1) { \
*output++ = COMPOSABLE_RAW_1P; \
*output++ = palette_entries[p&0xf]; \
} else { \
*output++ = COMPOSABLE_RAW_2P; \
*output++ = palette_entries[p&0xf]; \
*output++ = palette_entries[p>>4]; \
} \
} \
} else __builtin_unreachable()
#define XXoutput_4bit_paletted_pixels_xf(output, palette_entries, encoding, count) encoding += ((count+1)>>1)
#define output_4bit_paletted_pixels_xf(output, palette_entries, encoding, count) if (true) { \
span_assert((count)>0); \
uint32_t p = *encoding++; \
if ((count)>2) { \
*output++ = COMPOSABLE_RAW_RUN; \
if ((count) & 1) { \
*output++ = palette_entries[p>>4]; \
*output++ = (count) - 3; \
} else { \
*output++ = palette_entries[p&0xf]; \
*output++ = (count) - 3; \
*output++ = palette_entries[p>>4]; \
} \
int c = ((count)-1)>>1; \
while (c--) { \
p = *encoding++; \
*output++ = palette_entries[p&0xf]; \
*output++ = palette_entries[p>>4]; \
} \
} else { \
if ((count) == 1) { \
*output++ = COMPOSABLE_RAW_1P; \
} else { \
*output++ = COMPOSABLE_RAW_2P; \
*output++ = palette_entries[p&0xf]; \
} \
*output++ = palette_entries[p>>4]; \
} \
} else __builtin_unreachable()
#define output_color_one_pixel(output, color) if (true) { \
*output++ = COMPOSABLE_RAW_1P; \
*output++ = color; \
} else __builtin_unreachable()
#define output_color_two_pixels(output, color) if (true) { \
*output++ = COMPOSABLE_RAW_2P; \
*output++ = color; \
*output++ = color; \
} else __builtin_unreachable()
#define output_color_run_as_run_length(output, color, run_length) if (true) { \
span_assert(run_length >= MIN_COLOR_RUN); \
*output++ = COMPOSABLE_COLOR_RUN; \
*output++ = color; \
*output++ = (run_length) - MIN_COLOR_RUN; \
} else __builtin_unreachable()
#define output_color_run_of_min_size(output, color, run_length) if (true) { \
span_assert(run_length >= MIN_COLOR_RUN); \
output_color_run_as_run_length(output, color, run_length); \
} else __builtin_unreachable()
#define output_color_run_of_any_size(output, color, run_length) if (true) { \
if ((run_length) >= 3) { \
output_color_run_as_run_length(output, color, run_length); \
} else if ((run_length) == 1) { \
output_color_one_pixel(output, color); \
} else if ((run_length) == 2) { \
output_color_two_pixels(output, color); \
} else { \
assert(false); \
} \
} else __builtin_unreachable()
/**
* This method is kinda ugly, but really needs to be fast - C++ and particular templates and references could probably make it better
* but still, this will probably want to be assembly anyway. For now cut and paste code rather than sub-method fragments to string together...
* assembly being good for state machines!
*
* Actually I've started to move some common stuff/loops out into static inline functions that we can hopefully _asm-ify in the short term
*
* @param render_spans_buffer
* @param max_words
* @param head
* @param width
* @param do_free
* @return
*/
int32_t __time_critical_func(render_spans)(uint32_t *render_spans_buffer, size_t max_words, struct span *head,
int width) {
uint16_t *output = (uint16_t *) render_spans_buffer;
assert(!(3u & (uintptr_t) output)); // should be dword aligned
#ifndef NDEBUG
// todo output_end
uint16_t *output_end = output + 2 * max_words;
#endif
int total_pixels_remaining = width;
for (const struct span *cur = head; cur && total_pixels_remaining > 0; cur = cur->next) {
int local_pixels_remaining = cur->width;
if (!local_pixels_remaining) continue;
total_pixels_remaining -= local_pixels_remaining;
if (total_pixels_remaining < 0) {
local_pixels_remaining += total_pixels_remaining;
}
// todo i think this is reasonable, since for it to be 0 we'd have to have pixels_remaining == 0
span_assert(local_pixels_remaining > 0);
if (cur->type == SPAN_SOLID) {
// no hard clipping work; we just output what we're told
uint16_t color = cur->solid.color16;
output_color_run_of_any_size(output, color, local_pixels_remaining);
} else if (cur->type == SPAN_4BIT_VOGON_OPAQUE) {
int skip_pixels_remaining = cur->vogon.clip_left;
int right_clipped_pixels = cur->vogon.content_width - skip_pixels_remaining - local_pixels_remaining;
const uint16_t *palette_entries = cur->vogon.palette->entries;
const uint8_t *encoding = cur->vogon.data;
uint8_t c;
// deal with the skip pixels if any (do the whole rendering loop here, because it has been adulterated
// with code to check for clipping
while (skip_pixels_remaining > 0) {
c = *encoding++;
/* -------------------------------
// this variant skips a run which is wholly inside the clip_left
// or does a partially clipped span (which may be both left and right clipped)
// -------------------------------
*/
assert(right_clipped_pixels == 0); // can't do that here for now
if (RAW_PIXELS_SHORT == (c & 0xc0)) {
// count is already pairs of pixels count
int pair_count = ((c & 0x3f) + 1);
int run_length = pair_count << 1;
const uint8_t *end = encoding + pair_count;
if (skip_pixels_remaining < run_length) {
encoding += skip_pixels_remaining >> 1;
run_length -= skip_pixels_remaining;
output_4bit_paletted_pixels_xf(output, palette_entries, encoding, run_length);
skip_pixels_remaining = 0;
} else {
// wholly clipped
skip_pixels_remaining -= run_length;
encoding = end;
}
span_assert(encoding == end);
} else if (COLOR_PIXELS_SHORT == (c & 0xc0)) {
int run_length = ((c & 0x3f) + MIN_COLOR_SPAN_4BIT);
skip_pixels_remaining -= run_length;
if (skip_pixels_remaining < 0) {
run_length = -skip_pixels_remaining;
span_assert(run_length > 0);
uint16_t color = palette_entries[*encoding++];
output_color_run_of_any_size(output, color, run_length);
} else {
encoding++;
}
} else if (SINGLE_PIXEL == (c & 0xf0)) {
// if we are clipped, then there is nothing to do (no pixels left)
skip_pixels_remaining--;
} else if (c == COLOR_PIXELS_LONG) {
int run_length = 1 + *encoding++;
run_length += (*encoding++ << 8);
skip_pixels_remaining -= run_length;
if (skip_pixels_remaining < 0) {
run_length = -skip_pixels_remaining;
span_assert(run_length > 0);
uint16_t color = palette_entries[*encoding++];
output_color_run_of_any_size(output, color, run_length);
} else {
encoding++;
}
} else if (c == RAW_PIXELS_LONG) {
int run_length = 1 + *encoding++;
run_length += (*encoding++ << 8);
span_assert(!(run_length & 1)); // we always have even numbers of pixels
if (skip_pixels_remaining < run_length) {
encoding += skip_pixels_remaining >> 1;
run_length -= skip_pixels_remaining;
output_4bit_paletted_pixels_xf(output, palette_entries, encoding, run_length);
skip_pixels_remaining = 0;
} else {
encoding += run_length >> 1;
skip_pixels_remaining -= run_length;
}
span_assert(encoding == end);
} else if (c == END_OF_LINE) {
// just pass it on, though we could do some assertiony stuff here
encoding--;
break;
} else {
return -1;
}
}
if (!right_clipped_pixels) {
// -------------------------------
// here we do entirely unclipped runs from now on, without having to bother
// with book-keeping
// -------------------------------
while (true) {
c = *encoding++;
if (RAW_PIXELS_SHORT == (c & 0xc0)) {
// count is pairs of pixels
int run_length = ((c & 0x3f) + 1) * 2;
output_4bit_paletted_pixels_ff(output, palette_entries, encoding, run_length);
} else if (COLOR_PIXELS_SHORT == (c & 0xc0)) {
int run_length = ((c & 0x3f) + MIN_COLOR_SPAN_4BIT);
uint16_t color = palette_entries[*encoding++];
output_color_run_of_min_size(output, color, run_length);
} else if (SINGLE_PIXEL == (c & 0xf0)) {
uint16_t color = palette_entries[c & 0xf];
output_color_one_pixel(output, color);
} else if (c == COLOR_PIXELS_LONG) {
int run_length = 1 + *encoding++;
run_length += (*encoding++) << 8;
uint16_t color = palette_entries[*encoding++];
output_color_run_of_min_size(output, color, run_length);
} else if (c == RAW_PIXELS_LONG) {
int run_length = 1 + *encoding++;
run_length += (*encoding++) << 8;
assert(!(run_length & 1)); // we always have even numbers of pixels
output_4bit_paletted_pixels_ff(output, palette_entries, encoding, run_length);
} else if (c == END_OF_LINE) {
break;
} else {
return -1;
}
}
} else {
span_assert(right_clipped_pixels > 0); // should not be negative ever
span_assert(local_pixels_remaining > 0); // believe this is impossible
// similar to the regular loop but we must track local_pixels_remaining;
while (local_pixels_remaining > 0) {
c = *encoding++;
if (RAW_PIXELS_SHORT == (c & 0xc0)) {
// count is already pairs of pixels count
int pair_count = ((c & 0x3f) + 1);
const uint8_t *end = encoding + pair_count;
int run_length = pair_count * 2;
local_pixels_remaining -= run_length;
if (local_pixels_remaining >= 0) {
output_4bit_paletted_pixels_ff(output, palette_entries, encoding, run_length);
} else {
run_length += local_pixels_remaining;
span_assert(run_length >= 0);
output_4bit_paletted_pixels_fx(output, palette_entries, encoding, run_length);
encoding = end;
}
span_assert(encoding == end);
} else if (COLOR_PIXELS_SHORT == (c & 0xc0)) {
int run_length = ((c & 0x3f) + MIN_COLOR_SPAN_4BIT);
uint16_t color = palette_entries[*encoding++];
local_pixels_remaining -= run_length;
// todo collapse these into a single call?
if (local_pixels_remaining < 0) {
run_length += local_pixels_remaining;
output_color_run_of_any_size(output, color, run_length);
} else {
output_color_run_of_min_size(output, color, run_length);
}
} else if (SINGLE_PIXEL == (c & 0xf0)) {
uint16_t color = palette_entries[c & 0xf];
// since the span is not clipped its one pixel must not be
output_color_one_pixel(output, color);
local_pixels_remaining--;
} else if (c == COLOR_PIXELS_LONG) {
int run_length = 1 + *encoding++;
run_length += (*encoding++) << 8;
local_pixels_remaining -= run_length;
uint16_t color = palette_entries[*encoding++];
// todo collapse these into a single call? more so because this is a long run
if (local_pixels_remaining < 0) {
run_length += local_pixels_remaining;
output_color_run_of_any_size(output, color, run_length);
} else {
output_color_run_of_min_size(output, color, run_length);
}
} else if (c == RAW_PIXELS_LONG) {
int run_length = 1 + *encoding++;
run_length += (*encoding++) << 8;
assert(!(run_length & 1)); // we always have even numbers of pixels
const uint8_t *end = encoding + (run_length >> 1);
local_pixels_remaining -= run_length;
if (local_pixels_remaining >= 0) {
output_4bit_paletted_pixels_ff(output, palette_entries, encoding, run_length);
} else {
run_length += local_pixels_remaining;
span_assert(run_length >= 0);
output_4bit_paletted_pixels_fx(output, palette_entries, encoding, run_length);
encoding = end;
}
span_assert(encoding == end);
} else if (c == END_OF_LINE) {
break;
} else {
return -1;
}
}
}
}
}
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
if (2u & (uintptr_t) output) {
// we are unaligned
*output++ = COMPOSABLE_EOL_ALIGN;
} else {
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff; // eye catcher
// output++;
}
// *output ++ = 29;
// *output ++ = 29;
assert(output <= output_end);
assert(0 == (3u & (uintptr_t) output));
return ((uint32_t *) output) - render_spans_buffer;
}
#ifdef __arm__
#pragma GCC pop_options
#endif

Wyświetl plik

@ -0,0 +1,62 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _RENDER_SPANS_H
#define _RENDER_SPANS_H
#include "image.h"
// ----------------------------------------------------------------------------
// 4bit1 encoding (vogon) - data is paletted and as such may contain alpha
//
// note changing this affects decoder since it is subtracted from length
#define MIN_COLOR_SPAN_4BIT 5
#define MIN_RAW_SPAN_4BIT 4
enum vogon_commands {
END_OF_LINE = 0,
RAW_PIXELS_SHORT = 0x40,
COLOR_PIXELS_SHORT = 0x80,
SINGLE_PIXEL = 0xc0,
RAW_PIXELS_LONG = 0xd0,
COLOR_PIXELS_LONG = 0xd1
};
enum {
SPAN_SOLID,
SPAN_4BIT_VOGON_OPAQUE, // vogon data but using a solid color palette
SPAN_4BIT_RAW,
SPAN_8BIT_RAW
};
struct span {
struct span *next;
short_flags flags;
uint16_t width; // count of displayed pixels
uint8_t type;
union {
struct {
uint16_t color16;
} solid;
struct {
uint16_t clip_left; // > 0 to clip pixels off the left
uint16_t content_width; // pixel width of the original content
struct palette16 *palette;
const uint8_t *data;
uint16_t data_length;
} vogon, raw_4bit, raw_8bit;
};
};
extern int32_t render_spans(uint32_t *render_spans_buffer, size_t max_words, struct span *head, int width);
extern int32_t single_color_scanline(uint32_t *buf, size_t buf_length, int width, uint32_t color16);
extern void init_solid_color_span(struct span *span, uint16_t width, uint16_t color16, struct span *prev);
extern void init_vogon_4bit_span(struct span *span, uint16_t width, const uint8_t *encoding, uint16_t encoded_size,
struct palette16 *palette, struct span *prev);
extern void set_solid_color_span_color(struct span *span, uint16_t color16);
extern void set_vogon_4bit_span_encoding(struct span *span, const uint8_t *data, uint16_t data_length);
extern void set_vogon_4bit_clipping(struct span *span, int clip_left, int display_width);
#endif //CONVERT_SPANS_H

Wyświetl plik

@ -0,0 +1,12 @@
if (TARGET pico_scanvideo_dpi)
add_executable(scanvideo_minimal
scanvideo_minimal.c
)
target_link_libraries(scanvideo_minimal PRIVATE
pico_multicore
pico_stdlib
pico_scanvideo_dpi)
pico_add_extra_outputs(scanvideo_minimal)
endif ()

Wyświetl plik

@ -0,0 +1,106 @@
#include <stdio.h>
#include "pico.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/multicore.h"
#include "pico/sync.h"
#include "pico/stdlib.h"
#define DUAL_CORE_RENDER
#define VGA_MODE vga_mode_320x240_60
extern const struct scanvideo_pio_program video_24mhz_composable;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
static struct mutex frame_logic_mutex;
static void frame_update_logic();
static void render_scanline(struct scanvideo_scanline_buffer *dest, int core);
// "Worker thread" for each core
void render_loop() {
static uint32_t last_frame_num = 0;
int core_num = get_core_num();
printf("Rendering on core %d\n", core_num);
while (true) {
struct scanvideo_scanline_buffer *scanline_buffer = scanvideo_begin_scanline_generation(true);
mutex_enter_blocking(&frame_logic_mutex);
uint32_t frame_num = scanvideo_frame_number(scanline_buffer->scanline_id);
// Note that with multiple cores we may have got here not for the first
// scanline, however one of the cores will do this logic first before either
// does the actual generation
if (frame_num != last_frame_num) {
last_frame_num = frame_num;
frame_update_logic();
}
mutex_exit(&frame_logic_mutex);
render_scanline(scanline_buffer, core_num);
// Release the rendered buffer into the wild
scanvideo_end_scanline_generation(scanline_buffer);
}
}
struct semaphore video_setup_complete;
void core1_func() {
sem_acquire_blocking(&video_setup_complete);
render_loop();
}
int vga_main(void) {
mutex_init(&frame_logic_mutex);
sem_init(&video_setup_complete, 0, 1);
// Core 1 will wait for us to finish video setup, and then start rendering
#ifdef DUAL_CORE_RENDER
multicore_launch_core1(core1_func);
#endif
scanvideo_setup(&VGA_MODE);
scanvideo_timing_enable(true);
sem_release(&video_setup_complete);
render_loop();
return 0;
}
void frame_update_logic() {
}
#define MIN_COLOR_RUN 3
int32_t single_color_scanline(uint32_t *buf, size_t buf_length, int width, uint32_t color16) {
assert(buf_length >= 2);
assert(width >= MIN_COLOR_RUN);
// | jmp color_run | color | count-3 | buf[0] =
buf[0] = COMPOSABLE_COLOR_RUN | (color16 << 16);
buf[1] = (width - MIN_COLOR_RUN) | (COMPOSABLE_RAW_1P << 16);
// note we must end with a black pixel
buf[2] = 0 | (COMPOSABLE_EOL_ALIGN << 16);
return 3;
}
void render_scanline(struct scanvideo_scanline_buffer *dest, int core) {
uint32_t *buf = dest->data;
size_t buf_length = dest->data_max;
int l = scanvideo_scanline_number(dest->scanline_id);
uint16_t bgcolour = (uint16_t) l << 2;
dest->data_used = single_color_scanline(buf, buf_length, VGA_MODE.width, bgcolour);
dest->status = SCANLINE_OK;
}
int main(void) {
set_sys_clock_48mhz();
// Re init uart now that clk_peri has changed
setup_default_uart();
return vga_main();
}

Wyświetl plik

@ -0,0 +1,10 @@
add_library(sprite INTERFACE)
target_sources(sprite INTERFACE
$<$<BOOL:${PICO_ON_DEVICE}>:${CMAKE_CURRENT_LIST_DIR}/sprite.S>
${CMAKE_CURRENT_LIST_DIR}/sprite.c
${CMAKE_CURRENT_LIST_DIR}/sprite.h
)
target_include_directories(sprite INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(sprite INTERFACE pico_base_headers hardware_interp)

Wyświetl plik

@ -0,0 +1,143 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _AFFINE_TRANSFORM_H_
#define _AFFINE_TRANSFORM_H_
// Stolen from RISCBoy
#include <stdint.h>
#include "pico/platform.h"
// Store unpacked affine transforms as signed 16.16 fixed point in the following order:
// a00, a01, b0, a10, a11, b1
// i.e. the top two rows of the matrix
// [ a00 a01 b0 ]
// [ a01 a11 b1 ]
// [ 0 0 1 ]
// Then pack integers appropriately
typedef int32_t affine_transform_t[6];
static const int32_t AF_ONE = 1 << 16;
static inline __attribute__((always_inline)) int32_t mul_fp1616(int32_t x, int32_t y) {
// TODO this results in an aeabi call?!
int64_t result = (int64_t) x * y;
return result >> 16;
}
// result can not be == left or right
static inline void affine_mul(affine_transform_t result, const affine_transform_t left,
const affine_transform_t right) {
result[0] = mul_fp1616(left[0], right[0]) + mul_fp1616(left[1], right[3]);
result[1] = mul_fp1616(left[0], right[1]) + mul_fp1616(left[1], right[4]);
result[2] = mul_fp1616(left[0], right[2]) + mul_fp1616(left[1], right[5]) + left[2];
result[3] = mul_fp1616(left[3], right[0]) + mul_fp1616(left[4], right[3]);
result[4] = mul_fp1616(left[3], right[1]) + mul_fp1616(left[4], right[4]);
result[5] = mul_fp1616(left[3], right[2]) + mul_fp1616(left[4], right[5]) + left[5];
}
static inline void affine_copy(affine_transform_t dst, const affine_transform_t src) {
for (int i = 0; i < 6; ++i)
dst[i] = src[i];
}
// User is describing a sequence of transformations from texture space to
// screen space, which are applied by premultiplying a column vector. However,
// hardware transforms *from* screenspace *to* texture space, so we want the
// inverse of the transform the user is building. Therefore our functions each
// produce the inverse of the requested transform, and we apply transforms by
// *post*-multiplication.
static inline void affine_identity(affine_transform_t current_trans) {
int32_t tmp[6] = {
AF_ONE, 0, 0,
0, AF_ONE, 0
};
affine_copy(current_trans, tmp);
}
static inline void affine_translate(affine_transform_t current_trans, int32_t x, int32_t y) {
int32_t tmp[6];
int32_t transform[6] = {
AF_ONE, 0, -AF_ONE * x,
0, AF_ONE, -AF_ONE * y
};
affine_mul(tmp, current_trans, transform);
affine_copy(current_trans, tmp);
}
// TODO this is shit
static const int32_t __not_in_flash("atrans") sin_lookup_fp1616[256] = {
0x0, 0x648, 0xc8f, 0x12d5, 0x1917, 0x1f56, 0x2590, 0x2bc4, 0x31f1, 0x3817,
0x3e33, 0x4447, 0x4a50, 0x504d, 0x563e, 0x5c22, 0x61f7, 0x67bd, 0x6d74,
0x7319, 0x78ad, 0x7e2e, 0x839c, 0x88f5, 0x8e39, 0x9368, 0x987f, 0x9d7f,
0xa267, 0xa736, 0xabeb, 0xb085, 0xb504, 0xb968, 0xbdae, 0xc1d8, 0xc5e4,
0xc9d1, 0xcd9f, 0xd14d, 0xd4db, 0xd848, 0xdb94, 0xdebe, 0xe1c5, 0xe4aa,
0xe76b, 0xea09, 0xec83, 0xeed8, 0xf109, 0xf314, 0xf4fa, 0xf6ba, 0xf853,
0xf9c7, 0xfb14, 0xfc3b, 0xfd3a, 0xfe13, 0xfec4, 0xff4e, 0xffb1, 0xffec,
0x10000, 0xffec, 0xffb1, 0xff4e, 0xfec4, 0xfe13, 0xfd3a, 0xfc3b, 0xfb14,
0xf9c7, 0xf853, 0xf6ba, 0xf4fa, 0xf314, 0xf109, 0xeed8, 0xec83, 0xea09,
0xe76b, 0xe4aa, 0xe1c5, 0xdebe, 0xdb94, 0xd848, 0xd4db, 0xd14d, 0xcd9f,
0xc9d1, 0xc5e4, 0xc1d8, 0xbdae, 0xb968, 0xb504, 0xb085, 0xabeb, 0xa736,
0xa267, 0x9d7f, 0x987f, 0x9368, 0x8e39, 0x88f5, 0x839c, 0x7e2e, 0x78ad,
0x7319, 0x6d74, 0x67bd, 0x61f7, 0x5c22, 0x563e, 0x504d, 0x4a50, 0x4447,
0x3e33, 0x3817, 0x31f1, 0x2bc4, 0x2590, 0x1f56, 0x1917, 0x12d5, 0xc8f, 0x648,
0x0, 0xfffff9b8, 0xfffff371, 0xffffed2b, 0xffffe6e9, 0xffffe0aa, 0xffffda70,
0xffffd43c, 0xffffce0f, 0xffffc7e9, 0xffffc1cd, 0xffffbbb9, 0xffffb5b0,
0xffffafb3, 0xffffa9c2, 0xffffa3de, 0xffff9e09, 0xffff9843, 0xffff928c,
0xffff8ce7, 0xffff8753, 0xffff81d2, 0xffff7c64, 0xffff770b, 0xffff71c7,
0xffff6c98, 0xffff6781, 0xffff6281, 0xffff5d99, 0xffff58ca, 0xffff5415,
0xffff4f7b, 0xffff4afc, 0xffff4698, 0xffff4252, 0xffff3e28, 0xffff3a1c,
0xffff362f, 0xffff3261, 0xffff2eb3, 0xffff2b25, 0xffff27b8, 0xffff246c,
0xffff2142, 0xffff1e3b, 0xffff1b56, 0xffff1895, 0xffff15f7, 0xffff137d,
0xffff1128, 0xffff0ef7, 0xffff0cec, 0xffff0b06, 0xffff0946, 0xffff07ad,
0xffff0639, 0xffff04ec, 0xffff03c5, 0xffff02c6, 0xffff01ed, 0xffff013c,
0xffff00b2, 0xffff004f, 0xffff0014, 0xffff0000, 0xffff0014, 0xffff004f,
0xffff00b2, 0xffff013c, 0xffff01ed, 0xffff02c6, 0xffff03c5, 0xffff04ec,
0xffff0639, 0xffff07ad, 0xffff0946, 0xffff0b06, 0xffff0cec, 0xffff0ef7,
0xffff1128, 0xffff137d, 0xffff15f7, 0xffff1895, 0xffff1b56, 0xffff1e3b,
0xffff2142, 0xffff246c, 0xffff27b8, 0xffff2b25, 0xffff2eb3, 0xffff3261,
0xffff362f, 0xffff3a1c, 0xffff3e28, 0xffff4252, 0xffff4698, 0xffff4afc,
0xffff4f7b, 0xffff5415, 0xffff58ca, 0xffff5d99, 0xffff6281, 0xffff6781,
0xffff6c98, 0xffff71c7, 0xffff770b, 0xffff7c64, 0xffff81d2, 0xffff8753,
0xffff8ce7, 0xffff928c, 0xffff9843, 0xffff9e09, 0xffffa3de, 0xffffa9c2,
0xffffafb3, 0xffffb5b0, 0xffffbbb9, 0xffffc1cd, 0xffffc7e9, 0xffffce0f,
0xffffd43c, 0xffffda70, 0xffffe0aa, 0xffffe6e9, 0xffffed2b, 0xfffff371,
0xfffff9b8
};
static inline int32_t sin_fp1616(uint8_t theta) {
return sin_lookup_fp1616[theta];
}
static inline int32_t cos_fp1616(uint8_t theta) {
return sin_lookup_fp1616[(theta + 64) & 0xff];
}
// Appears as a counterclockwise rotation (when viewed from texture space to screen space)
// Units of angle are 256 = one turn
static inline void affine_rotate(affine_transform_t current_trans, uint8_t theta) {
int32_t tmp[6];
int32_t transform[6] = {
cos_fp1616(theta), -sin_fp1616(theta), 0,
sin_fp1616(theta), cos_fp1616(theta), 0
};
affine_mul(tmp, current_trans, transform);
affine_copy(current_trans, tmp);
}
static inline void affine_scale(affine_transform_t current_trans, int32_t sx, int32_t sy) {
int32_t sx_inv = ((int64_t) AF_ONE * AF_ONE) / sx;
int32_t sy_inv = ((int64_t) AF_ONE * AF_ONE) / sy;
int32_t tmp[6];
int32_t transform[6] = {
sx_inv, 0, 0,
0, sy_inv, 0
};
affine_mul(tmp, current_trans, transform);
affine_copy(current_trans, tmp);
}
#endif // _AFFINE_TRANSFORM_H_

Wyświetl plik

@ -0,0 +1,584 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Functions for doing simple 2D graphics operations on a RGB scanline buffer.
#include "hardware/regs/addressmap.h"
#include "hardware/regs/sio.h"
#define POP2_OFFS (SIO_INTERP0_POP_FULL_OFFSET - SIO_INTERP0_ACCUM0_OFFSET)
#define CTRL0_OFFS (SIO_INTERP0_CTRL_LANE0_OFFSET - SIO_INTERP0_ACCUM0_OFFSET)
#define INTERP1 (SIO_INTERP1_ACCUM0_OFFSET - SIO_INTERP0_ACCUM0_OFFSET)
.syntax unified
.cpu cortex-m0plus
.thumb
// Put every function in its own ELF section, to permit linker GC
.macro decl_func name
.section .time_critical.\name, "ax"
.global \name
.type \name,%function
.thumb_func
\name:
.endm
// ----------------------------------------------------------------------------
// Colour fill
// r0: dst
// r1: value
// r2: count
decl_func sprite_fill8
// Slide for short fills
cmp r2, #18
bhi 2f
adr r3, 1f
lsls r2, #1
subs r3, r2
adds r3, #1 // thumb bit
bx r3
.align 2
strb r1, [r0, #17]
strb r1, [r0, #16]
strb r1, [r0, #15]
strb r1, [r0, #14]
strb r1, [r0, #13]
strb r1, [r0, #12]
strb r1, [r0, #11]
strb r1, [r0, #10]
strb r1, [r0, #9]
strb r1, [r0, #8]
strb r1, [r0, #7]
strb r1, [r0, #6]
strb r1, [r0, #5]
strb r1, [r0, #4]
strb r1, [r0, #3]
strb r1, [r0, #2]
strb r1, [r0, #1]
strb r1, [r0, #0]
1:
bx lr
2:
lsls r3, r1, #8
orrs r1, r3
lsls r3, r1, #16
orrs r1, r3
// Get r0 word-aligned:
lsrs r3, r0, #1
bcc 1f
strb r1, [r0]
adds r0, #1
subs r2, #1
1:
lsrs r3, r0, #2
bcc 1f
strh r1, [r0]
adds r0, #2
subs r2, #2
1:
// Set up for main loop. Limit pointer at end - (loop body size - 1)
push {r4}
adds r2, r0
subs r2, #15
mov ip, r2
mov r2, r1
mov r3, r1
mov r4, r1
// Fall straight into loop, because cases less than (loop body + max misalignment) are handled by slide
1:
stmia r0!, {r1, r2, r3, r4}
cmp r0, ip
blo 1b
// Main loop done, now tidy up the odds and ends
mov r4, ip
subs r4, r0
adds r4, #15
// No more than 15 bytes remaining -- first test bit 3
lsls r4, #29
bcc 1f
stmia r0!, {r1, r2}
1:
lsls r4, #1
bcc 1f
stmia r0!, {r1}
1:
lsls r4, #1
bcc 1f
strh r1, [r0]
adds r0, #2
1:
lsls r4, #1
bcc 1f
strb r1, [r0]
1:
pop {r4}
bx lr
decl_func sprite_fill16
// Slide for short fills
cmp r2, #15
bhi 2f
adr r3, 1f
lsls r2, #1
subs r3, r2
adds r3, #1
bx r3
.align 2
strh r1, [r0, #30]
strh r1, [r0, #28]
strh r1, [r0, #26]
strh r1, [r0, #24]
strh r1, [r0, #22]
strh r1, [r0, #20]
strh r1, [r0, #18]
strh r1, [r0, #16]
strh r1, [r0, #14]
strh r1, [r0, #12]
strh r1, [r0, #10]
strh r1, [r0, #8]
strh r1, [r0, #6]
strh r1, [r0, #4]
strh r1, [r0, #2]
strh r1, [r0, #0]
1:
bx lr
2:
push {r4, r5, r6, r7, lr}
// Get word-aligned before main fill loop
lsrs r3, r2, #2
bcc 1f
strh r1, [r0]
adds r0, #2
subs r2, #1
1:
// Set limit pointer at end - (loop body size - 1)
lsls r2, #1
adds r2, r0
subs r2, #26
mov ip, r2
lsls r2, r1, #16
orrs r1, r2
mov r2, r1
mov r3, r1
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
// We can fall through because cases < 1 loop are handled by slide
1:
stmia r0!, {r1, r2, r3, r4, r5, r6, r7} // wheeeeeeeeeee
cmp r0, ip
blo 1b
// Most of the work done, we have a few more to tidy up
movs r2, #26
add r2, ip
subs r2, r0
lsls r2, #28
bcc 1f
stmia r0!, {r4, r5, r6, r7}
1:
lsls r2, #1
bcc 1f
stmia r0!, {r4, r5}
1:
lsls r2, #1
bcc 1f
stmia r0!, {r4}
1:
lsls r2, #1
bcc 1f
strh r4, [r0]
1:
pop {r4, r5, r6, r7, pc}
// ----------------------------------------------------------------------------
// Non-AT sprite
// r0: dst
// r1: src
// r2: pixel count
//
// Unrolled loop body with an initial computed branch. Note we can go much
// faster if r0 and r1 are co-aligned, but it's not all that helpful to have a
// 1 in 4 chance of being really fast when minimising worst-case scanline time
decl_func sprite_blit8
mov ip, r0
lsrs r3, r2, #3
lsls r3, #3
eors r2, r3 // r2 = pixels % 8, r3 = pixels = pixels % 8
add r0, r3
add r1, r3
adr r3, 2f
lsls r2, #2
subs r3, r2
adds r3, #1 // thumb bit >:(
bx r3
.align 2
1:
subs r0, #8
subs r1, #8
ldrb r3, [r1, #7]
strb r3, [r0, #7]
ldrb r3, [r1, #6]
strb r3, [r0, #6]
ldrb r3, [r1, #5]
strb r3, [r0, #5]
ldrb r3, [r1, #4]
strb r3, [r0, #4]
ldrb r3, [r1, #3]
strb r3, [r0, #3]
ldrb r3, [r1, #2]
strb r3, [r0, #2]
ldrb r3, [r1, #1]
strb r3, [r0, #1]
ldrb r3, [r1, #0]
strb r3, [r0, #0]
2:
cmp r0, ip
bhi 1b
bx lr
// Assume RAGB2132 (so alpha is bit 5)
#define ALPHA_SHIFT_8BPP 6
.macro sprite_blit8_alpha_body n
ldrb r3, [r1, #\n]
lsrs r2, r3, #ALPHA_SHIFT_8BPP
bcc 2f
strb r3, [r0, #\n]
2:
.endm
decl_func sprite_blit8_alpha
mov ip, r0
lsrs r3, r2, #3
lsls r3, #3
eors r2, r3
add r0, r3
add r1, r3
adr r3, 3f
lsls r2, #3
subs r3, r2
adds r3, #1
bx r3
.align 2
1:
subs r0, #8
subs r1, #8
sprite_blit8_alpha_body 7
sprite_blit8_alpha_body 6
sprite_blit8_alpha_body 5
sprite_blit8_alpha_body 4
sprite_blit8_alpha_body 3
sprite_blit8_alpha_body 2
sprite_blit8_alpha_body 1
sprite_blit8_alpha_body 0
3:
cmp r0, ip
bhi 1b
bx lr
decl_func sprite_blit16
mov ip, r0
lsrs r3, r2, #3
lsls r3, #3
eors r2, r3 // r2 = pixels % 8, r3 = pixels = pixels % 8
lsls r3, #1
add r0, r3
add r1, r3
adr r3, 2f
lsls r2, #2
subs r3, r2
adds r3, #1 // thumb bit >:(
bx r3
.align 2
1:
subs r0, #16
subs r1, #16
ldrh r3, [r1, #14]
strh r3, [r0, #14]
ldrh r3, [r1, #12]
strh r3, [r0, #12]
ldrh r3, [r1, #10]
strh r3, [r0, #10]
ldrh r3, [r1, #8]
strh r3, [r0, #8]
ldrh r3, [r1, #6]
strh r3, [r0, #6]
ldrh r3, [r1, #4]
strh r3, [r0, #4]
ldrh r3, [r1, #2]
strh r3, [r0, #2]
ldrh r3, [r1, #0]
strh r3, [r0, #0]
2:
cmp r0, ip
bhi 1b
bx lr
// Assume RGAB5515 (so alpha is bit 5)
// Note the alpha bit being in the same position as RAGB2132 is a coincidence.
// We are just stealing an LSB such that we can treat our alpha pixels in the
// same way as non-alpha pixels when encoding (and the co-opted channel LSB
// always ends up being set on alpha pixels, which is pretty harmless)
#define ALPHA_SHIFT_16BPP 6
.macro sprite_blit16_alpha_body n
ldrh r3, [r1, #2*\n]
lsrs r2, r3, #ALPHA_SHIFT_16BPP
bcc 2f
strh r3, [r0, #2*\n]
2:
.endm
decl_func sprite_blit16_alpha
mov ip, r0
lsrs r3, r2, #3
lsls r3, #3
eors r2, r3
lsls r3, #1
add r0, r3
add r1, r3
adr r3, 3f
lsls r2, #3
subs r3, r2
adds r3, #1
bx r3
.align 2
1:
subs r0, #16
subs r1, #16
sprite_blit16_alpha_body 7
sprite_blit16_alpha_body 6
sprite_blit16_alpha_body 5
sprite_blit16_alpha_body 4
sprite_blit16_alpha_body 3
sprite_blit16_alpha_body 2
sprite_blit16_alpha_body 1
sprite_blit16_alpha_body 0
3:
cmp r0, ip
bhi 1b
bx lr
// ----------------------------------------------------------------------------
// Affine-transformed sprite (note these are just the inner loops -- INTERP0
// must be configured by the caller, which is presumably not written in asm)
// r0: raster start pointer
// r1: raster span size (pixels)
.macro sprite_ablit8_loop_body n
ldr r1, [r3, #CTRL0_OFFS]
ldr r2, [r3, #POP2_OFFS]
lsrs r1, #SIO_INTERP0_CTRL_LANE0_OVERF_LSB + 1
bcs 2f
ldrb r2, [r2]
strb r2, [r0, #\n]
2:
.endm
decl_func sprite_ablit8_loop
mov ip, r0
lsrs r2, r1, #3
lsls r2, #3
eors r1, r2
add r0, r2
adr r2, 3f
movs r3, #12 // Each (non-unrolled) loop body is 12 bytes
muls r1, r3
subs r2, r1
adds r2, #1
ldr r3, =(SIO_BASE + SIO_INTERP0_ACCUM0_OFFSET)
bx r2
.align 2
nop
1:
subs r0, #8
sprite_ablit8_loop_body 7
sprite_ablit8_loop_body 6
sprite_ablit8_loop_body 5
sprite_ablit8_loop_body 4
sprite_ablit8_loop_body 3
sprite_ablit8_loop_body 2
sprite_ablit8_loop_body 1
sprite_ablit8_loop_body 0
3:
cmp r0, ip
bne 1b
bx lr
// As above but bit 5 is assumed to be an alpha bit (RAGB2132)
.macro sprite_ablit8_alpha_loop_body n
ldr r1, [r3, #CTRL0_OFFS]
ldr r2, [r3, #POP2_OFFS]
lsrs r1, #SIO_INTERP0_CTRL_LANE0_OVERF_LSB + 1
bcs 2f
ldrb r2, [r2]
lsrs r1, r2, #ALPHA_SHIFT_8BPP
bcc 2f
strb r2, [r0, #\n]
2:
.endm
decl_func sprite_ablit8_alpha_loop
mov ip, r0
ldr r3, =(SIO_BASE + SIO_INTERP0_ACCUM0_OFFSET)
lsrs r2, r1, #3
lsls r2, #3
eors r1, r2
add r0, r2
adr r2, 3f
lsls r1, #4 // Each (non-unrolled) loop body is 16 bytes
subs r2, r1
adds r2, #1
bx r2
.align 2
nop
1:
subs r0, #8
sprite_ablit8_alpha_loop_body 7
sprite_ablit8_alpha_loop_body 6
sprite_ablit8_alpha_loop_body 5
sprite_ablit8_alpha_loop_body 4
sprite_ablit8_alpha_loop_body 3
sprite_ablit8_alpha_loop_body 2
sprite_ablit8_alpha_loop_body 1
sprite_ablit8_alpha_loop_body 0
3:
cmp r0, ip
bhi 1b
bx lr
.macro sprite_ablit16_loop_body n
ldr r1, [r3, #CTRL0_OFFS]
ldr r2, [r3, #POP2_OFFS]
lsrs r1, #SIO_INTERP0_CTRL_LANE0_OVERF_LSB + 1
bcs 2f
ldrh r2, [r2]
strh r2, [r0, #2*\n]
2:
.endm
decl_func sprite_ablit16_loop
mov ip, r0
lsrs r2, r1, #3
lsls r2, #3
eors r1, r2
lsls r2, #1 // Each pixel is 2 bytes
add r0, r2
adr r2, 3f
movs r3, #12 // Each (non-unrolled) loop body is 12 bytes
muls r1, r3
subs r2, r1
adds r2, #1
ldr r3, =(SIO_BASE + SIO_INTERP0_ACCUM0_OFFSET)
bx r2
.align 2
nop
1:
subs r0, #16
sprite_ablit16_loop_body 7
sprite_ablit16_loop_body 6
sprite_ablit16_loop_body 5
sprite_ablit16_loop_body 4
sprite_ablit16_loop_body 3
sprite_ablit16_loop_body 2
sprite_ablit16_loop_body 1
sprite_ablit16_loop_body 0
3:
cmp r0, ip
bne 1b
bx lr
.macro sprite_ablit16_alpha_loop_body n
ldr r1, [r3, #CTRL0_OFFS]
ldr r2, [r3, #POP2_OFFS]
lsrs r1, #SIO_INTERP0_CTRL_LANE0_OVERF_LSB + 1
bcs 2f
ldrh r2, [r2]
lsrs r1, r2, #ALPHA_SHIFT_16BPP
bcc 2f
strh r2, [r0, #2*\n]
2:
.endm
decl_func sprite_ablit16_alpha_loop
mov ip, r0
ldr r3, =(SIO_BASE + SIO_INTERP0_ACCUM0_OFFSET)
lsrs r2, r1, #3
lsls r2, #3
eors r1, r2
lsls r2, #1 // Each pixel is 2 bytes
add r0, r2
adr r2, 3f
lsls r1, #4 // Each (non-unrolled) loop body is 16 bytes
subs r2, r1
adds r2, #1
bx r2
.align 2
nop
1:
subs r0, #16
sprite_ablit16_alpha_loop_body 7
sprite_ablit16_alpha_loop_body 6
sprite_ablit16_alpha_loop_body 5
sprite_ablit16_alpha_loop_body 4
sprite_ablit16_alpha_loop_body 3
sprite_ablit16_alpha_loop_body 2
sprite_ablit16_alpha_loop_body 1
sprite_ablit16_alpha_loop_body 0
3:
cmp r0, ip
bhi 1b
bx lr

Wyświetl plik

@ -0,0 +1,176 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "sprite.h"
#include "affine_transform.h"
#include "pico/platform.h" // for __not_in_flash
#include "hardware/interp.h"
// Note some of the sprite routines are quite large (unrolled), so trying to
// keep everything in separate sections so the linker can garbage collect
// unused sprite code. In particular we usually need 8bpp xor 16bpp functions!
#define __ram_func(foo) __not_in_flash_func(foo)
typedef struct {
int tex_offs_x;
int tex_offs_y;
int size_x;
} intersect_t;
// Always-inline else the compiler does rash things like passing structs in memory
static inline intersect_t _get_sprite_intersect(const sprite_t *sp, uint raster_y, uint raster_w) {
intersect_t isct = {0};
isct.tex_offs_y = (int) raster_y - sp->y;
int size = 1u << sp->log_size;
uint upper_mask = -size;
if ((uint) isct.tex_offs_y & upper_mask)
return isct;
int x_start_clipped = MAX(0, sp->x);
isct.tex_offs_x = x_start_clipped - sp->x;
isct.size_x = MIN(sp->x + size, (int) raster_w) - x_start_clipped;
return isct;
}
// Sprites may have an array of metadata on the end. One word per line, encodes first opaque pixel, last opaque pixel, and whether the span in between is solid. This allows fewer
static inline intersect_t _intersect_with_metadata(intersect_t isct, uint32_t meta) {
int span_end = meta & 0xffff;
int span_start = (meta >> 16) & 0x7fff;
int isct_new_start = MAX(isct.tex_offs_x, span_start);
int isct_new_end = MIN(isct.tex_offs_x + isct.size_x, span_end);
isct.tex_offs_x = isct_new_start;
isct.size_x = isct_new_end - isct_new_start;
return isct;
}
void __ram_func(sprite_sprite8)(uint8_t *scanbuf, const sprite_t *sp, uint raster_y, uint raster_w) {
int size = 1u << sp->log_size;
intersect_t isct = _get_sprite_intersect(sp, raster_y, raster_w);
if (isct.size_x <= 0)
return;
const uint8_t *img = sp->img;
if (sp->has_opacity_metadata) {
// Metadata is one word per row, concatenated to end of pixel data
uint32_t meta = ((uint32_t *) (sp->img + size * size * sizeof(uint8_t)))[isct.tex_offs_y];
isct = _intersect_with_metadata(isct, meta);
if (isct.size_x <= 0)
return;
bool span_continuous = !!(meta & (1u << 31));
if (span_continuous) {
// Non-alpha blit is ~50% faster
sprite_blit8(scanbuf + sp->x + isct.tex_offs_x, img + isct.tex_offs_x + isct.tex_offs_y * size,
isct.size_x);
} else {
sprite_blit8_alpha(scanbuf + sp->x + isct.tex_offs_x, img + isct.tex_offs_x + isct.tex_offs_y * size,
isct.size_x);
}
} else {
sprite_blit8_alpha(scanbuf + sp->x + isct.tex_offs_x, img + isct.tex_offs_x + isct.tex_offs_y * size,
isct.size_x);
}
}
void __ram_func(sprite_sprite16)(uint16_t *scanbuf, const sprite_t *sp, uint raster_y, uint raster_w) {
int size = 1u << sp->log_size;
intersect_t isct = _get_sprite_intersect(sp, raster_y, raster_w);
if (isct.size_x <= 0)
return;
const uint16_t *img = sp->img;
if (sp->has_opacity_metadata) {
uint32_t meta = ((uint32_t *) (sp->img + size * size * sizeof(uint16_t)))[isct.tex_offs_y];
isct = _intersect_with_metadata(isct, meta);
if (isct.size_x <= 0)
return;
bool span_continuous = !!(meta & (1u << 31));
if (span_continuous)
sprite_blit16(scanbuf + sp->x + isct.tex_offs_x, img + isct.tex_offs_x + isct.tex_offs_y * size,
isct.size_x);
else
sprite_blit16_alpha(scanbuf + sp->x + isct.tex_offs_x, img + isct.tex_offs_x + isct.tex_offs_y * size,
isct.size_x);
} else {
sprite_blit16_alpha(scanbuf + MAX(0, sp->x), img + isct.tex_offs_x + isct.tex_offs_y * size, isct.size_x);
}
}
// We're defining the affine transform as:
//
// [u] [ a00 a01 b0 ] [x] [a00 * x + a01 * y + b0]
// [v] = [ a10 a11 b1 ] * [y] = [a10 * x + a11 * y + b1]
// [1] [ 0 0 1 ] [1] [ 1 ]
//
// We represent this in memory as {a00, a01, b0, a10, a11, b1} (all int32_t)
// i.e. the non-constant parts in row-major order
// Set up an interpolator to follow a straight line through u,v space
static inline __attribute__((always_inline)) void _setup_interp_affine(interp_hw_t *interp, intersect_t isct,
const affine_transform_t atrans) {
// Calculate the u,v coord of the first sample. Note that we are iterating
// *backward* along the raster span because this is faster (yes)
int32_t x0 =
mul_fp1616(atrans[0], (isct.tex_offs_x + isct.size_x) * AF_ONE) +
mul_fp1616(atrans[1], isct.tex_offs_y * AF_ONE) +
atrans[2];
int32_t y0 =
mul_fp1616(atrans[3], (isct.tex_offs_x + isct.size_x) * AF_ONE) +
mul_fp1616(atrans[4], isct.tex_offs_y * AF_ONE) +
atrans[5];
interp->accum[0] = x0;
interp->accum[1] = y0;
interp->base[0] = -atrans[0]; // -a00, since x decrements by 1 with each coord
interp->base[1] = -atrans[3]; // -a10
}
// Set up an interpolator to generate pixel lookup addresses from fp1616
// numbers in accum1, accum0 based on the parameters of sprite sp and the size
// of the individual pixels
static inline __attribute__((always_inline)) void _setup_interp_pix_coordgen(interp_hw_t *interp,
const sprite_t *sp, uint pixel_shift) {
// Concatenate from accum0[31:16] and accum1[31:16] as many LSBs as required
// to index the sprite texture in both directions. Reading from POP_FULL will
// yields these bits, added to sp->img, and this will also trigger BASE0 and
// BASE1 to be directly added (thanks to CTRL_ADD_RAW) to the accumulators,
// which generates the u,v coordinate for the *next* read.
assert(sp->log_size + pixel_shift <= 16);
interp_config c0 = interp_default_config();
interp_config_set_add_raw(&c0, true);
interp_config_set_shift(&c0, 16 - pixel_shift);
interp_config_set_mask(&c0, pixel_shift, pixel_shift + sp->log_size - 1);
interp_set_config(interp, 0, &c0);
interp_config c1 = interp_default_config();
interp_config_set_add_raw(&c1, true);
interp_config_set_shift(&c1, 16 - sp->log_size - pixel_shift);
interp_config_set_mask(&c1, pixel_shift + sp->log_size, pixel_shift + 2 * sp->log_size - 1);
interp_set_config(interp, 1, &c1);
interp->base[2] = (uint32_t) sp->img;
}
// Note we do NOT save/restore the interpolator!
void __ram_func(sprite_asprite8)(uint8_t *scanbuf, const sprite_t *sp, const affine_transform_t atrans, uint raster_y,
uint raster_w) {
intersect_t isct = _get_sprite_intersect(sp, raster_y, raster_w);
if (isct.size_x <= 0)
return;
interp_hw_t *interp = interp0;
_setup_interp_affine(interp, isct, atrans);
_setup_interp_pix_coordgen(interp, sp, 0);
// Now every read from POP_FULL will give us a new MODE7 lookup pointer for sp->img :)
sprite_ablit8_alpha_loop(scanbuf + MAX(0, sp->x), isct.size_x);
}
void __ram_func(sprite_asprite16)(uint16_t *scanbuf, const sprite_t *sp, const affine_transform_t atrans, uint raster_y,
uint raster_w) {
intersect_t isct = _get_sprite_intersect(sp, raster_y, raster_w);
if (isct.size_x <= 0)
return;
interp_hw_t *interp = interp0;
_setup_interp_affine(interp, isct, atrans);
_setup_interp_pix_coordgen(interp, sp, 1);
sprite_ablit16_alpha_loop(scanbuf + MAX(0, sp->x), isct.size_x);
}

Wyświetl plik

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _SPRITE_H
#define _SPRITE_H
#include "pico/types.h"
#include "affine_transform.h"
typedef struct sprite {
int16_t x;
int16_t y;
const void *img;
uint8_t log_size; // always square
bool has_opacity_metadata;
} sprite_t;
// ----------------------------------------------------------------------------
// Functions from sprite.S
// Constant-colour span
void sprite_fill8(uint8_t *dst, uint8_t colour, uint len);
void sprite_fill16(uint16_t *dst, uint16_t colour, uint len);
// Block image transfers
void sprite_blit8(uint8_t *dst, const uint8_t *src, uint len);
void sprite_blit8_alpha(uint8_t *dst, const uint8_t *src, uint len);
void sprite_blit16(uint16_t *dst, const uint16_t *src, uint len);
void sprite_blit16_alpha(uint16_t *dst, const uint16_t *src, uint len);
// These are just inner loops, and require INTERP0 to be configured before calling:
void sprite_ablit8_loop(uint8_t *dst, uint len);
void sprite_ablit8_alpha_loop(uint8_t *dst, uint len);
void sprite_ablit16_loop(uint16_t *dst, uint len);
void sprite_ablit16_alpha_loop(uint16_t *dst, uint len);
// ----------------------------------------------------------------------------
// Functions from sprite.c
// Render the intersection of a sprite with the current scanline:
void sprite_sprite8(uint8_t *scanbuf, const sprite_t *sp, uint raster_y, uint raster_w);
void sprite_sprite16(uint16_t *scanbuf, const sprite_t *sp, uint raster_y, uint raster_w);
// As above, but apply an affine transform on sprite texture lookups (SLOW, even with interpolator)
void sprite_asprite8(uint8_t *scanbuf, const sprite_t *sp, const affine_transform_t atrans, uint raster_y,
uint raster_w);
void sprite_asprite16(uint16_t *scanbuf, const sprite_t *sp, const affine_transform_t atrans, uint raster_y,
uint raster_w);
#endif

Wyświetl plik

@ -0,0 +1,15 @@
if (PICO_ON_DEVICE AND TARGET pico_scanvideo_dpi)
add_executable(sprite_demo
sprite_demo.c
)
target_compile_definitions(sprite_demo PRIVATE
PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS=500
)
target_link_libraries(sprite_demo PRIVATE
pico_multicore
pico_stdlib
pico_scanvideo_dpi
sprite)
pico_add_extra_outputs(sprite_demo)
endif ()

Wyświetl plik

@ -0,0 +1,206 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/multicore.h"
#include "pico/sync.h"
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "sprite.h"
#include "raspberry_128x128_bgar5515.h"
#include "raspberry_128x128_bgar5515_flip.h"
#include "hardware/structs/vreg_and_chip_reset.h"
//#define VGA_MODE vga_mode_320x240_60
#define VGA_MODE vga_mode_640x480_60
#define DUAL_CORE_RENDER
// #define TURBO_BOOST
#define N_BERRIES 45
CU_REGISTER_DEBUG_PINS(generation)
CU_SELECT_DEBUG_PINS(generation)
extern const struct scanvideo_pio_program video_24mhz_composable;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
static struct mutex frame_logic_mutex;
static void frame_update_logic();
static void render_scanline(struct scanvideo_scanline_buffer *dest, int core);
// "Worker thread" for each core
void __time_critical_func(render_loop)() {
static uint32_t last_frame_num = 0;
int core_num = get_core_num();
printf("Rendering on core %d\n", core_num);
while (true) {
struct scanvideo_scanline_buffer *scanline_buffer = scanvideo_begin_scanline_generation(true);
mutex_enter_blocking(&frame_logic_mutex);
uint32_t frame_num = scanvideo_frame_number(scanline_buffer->scanline_id);
// Note that with multiple cores we may have got here not for the first
// scanline, however one of the cores will do this logic first before either
// does the actual generation
if (frame_num != last_frame_num) {
last_frame_num = frame_num;
frame_update_logic();
}
mutex_exit(&frame_logic_mutex);
render_scanline(scanline_buffer, core_num);
// Release the rendered buffer into the wild
scanvideo_end_scanline_generation(scanline_buffer);
}
}
struct semaphore video_setup_complete;
void core1_func() {
sem_acquire_blocking(&video_setup_complete);
render_loop();
}
int vga_main(void) {
mutex_init(&frame_logic_mutex);
sem_init(&video_setup_complete, 0, 1);
// Core 1 will wait for us to finish video setup, and then start rendering
#ifdef DUAL_CORE_RENDER
multicore_launch_core1(core1_func);
#endif
hard_assert(VGA_MODE.width + 4 <= PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS * 2);
scanvideo_setup(&VGA_MODE);
scanvideo_timing_enable(true);
sem_release(&video_setup_complete);
render_loop();
}
// Helper functions to:
// - Get a scanbuf into a state where a region of it can be directly rendered to,
// and return a pointer to this region
// - After rendering, manipulate this scanbuffer into a form where PIO can
// yeet it out on VGA
static inline uint16_t *raw_scanline_prepare(struct scanvideo_scanline_buffer *dest, uint width) {
assert(width >= 3);
assert(width % 2 == 0);
// +1 for the black pixel at the end, -3 because the program outputs n+3 pixels.
dest->data[0] = COMPOSABLE_RAW_RUN | (width + 1 - 3 << 16);
// After user pixels, 1 black pixel then discard remaining FIFO data
dest->data[width / 2 + 2] = 0x0000u | (COMPOSABLE_EOL_ALIGN << 16);
dest->data_used = width / 2 + 2;
assert(dest->data_used <= dest->data_max);
return (uint16_t *) &dest->data[1];
}
static inline void raw_scanline_finish(struct scanvideo_scanline_buffer *dest) {
// Need to pivot the first pixel with the count so that PIO can keep up
// with its 1 pixel per 2 clocks
uint32_t first = dest->data[0];
uint32_t second = dest->data[1];
dest->data[0] = (first & 0x0000ffffu) | ((second & 0x0000ffffu) << 16);
dest->data[1] = (second & 0xffff0000u) | ((first & 0xffff0000u) >> 16);
dest->status = SCANLINE_OK;
}
sprite_t berry[N_BERRIES];
int vx[N_BERRIES];
int vy[N_BERRIES];
void __time_critical_func(render_scanline)(struct scanvideo_scanline_buffer *dest, int core) {
int l = scanvideo_scanline_number(dest->scanline_id);
uint16_t *colour_buf = raw_scanline_prepare(dest, VGA_MODE.width);
DEBUG_PINS_SET(generation, (core + 1));
DEBUG_PINS_SET(generation, 4);
const uint16_t bgcol = PICO_SCANVIDEO_PIXEL_FROM_RGB8(0x40, 0xc0, 0xff);
sprite_fill16(colour_buf, bgcol, VGA_MODE.width);
DEBUG_PINS_CLR(generation, 4);
for (int i = 0; i < N_BERRIES; ++i)
sprite_sprite16(colour_buf, &berry[i], l, VGA_MODE.width);
DEBUG_PINS_CLR(generation, (core + 1));
raw_scanline_finish(dest);
}
static inline int random_velocity() {
// Never return 0 -- it makes the demo much less interesting
return (rand() % 5 + 1) * (rand() & 0x8000 ? 1 : -1);
}
static inline int clip(int x, int min, int max) {
return x < min ? min : x > max ? max : x;
}
static int xmin;
static int xmax;
static int ymin;
static int ymax;
void __time_critical_func(frame_update_logic)() {
for (int i = 0; i < N_BERRIES; ++i) {
berry[i].x += vx[i];
berry[i].y += vy[i];
int xclip = clip(berry[i].x, xmin, xmax);
int yclip = clip(berry[i].y, ymin, ymax);
if (berry[i].x != xclip || berry[i].y != yclip) {
berry[i].x = xclip;
berry[i].y = yclip;
vx[i] = random_velocity();
vy[i] = random_velocity();
berry[i].img = vx[i] < 0 ? raspberry_128x128_flip : raspberry_128x128;
}
}
}
int main(void) {
#ifdef TURBO_BOOST
hw_set_bits(&mm_vreg_and_chip_reset->vreg, VREG_AND_CHIP_RESET_VREG_VSEL_BITS);
sleep_ms(10);
set_sys_clock(1536*MHZ, 4, 1);
#else
set_sys_clock_pll(1536 * MHZ, 4, 2);
#endif
// Re init uart now that clk_peri has changed
setup_default_uart();
#ifdef PICO_SMPS_MODE_PIN
gpio_init(PICO_SMPS_MODE_PIN);
gpio_set_dir(PICO_SMPS_MODE_PIN, GPIO_OUT);
gpio_put(PICO_SMPS_MODE_PIN, 1);
#endif
xmin = -100;
xmax = VGA_MODE.width - 30;
ymin = -100;
ymax = VGA_MODE.height - 30;
for (int i = 0; i < N_BERRIES; ++i) {
berry[i].x = rand() % (xmax - xmin + 1) - xmin;
berry[i].y = rand() % (ymax - ymin + 1) - ymin;
berry[i].img = raspberry_128x128_flip;
berry[i].log_size = 7;
berry[i].has_opacity_metadata = true;
vx[i] = random_velocity();
vy[i] = random_velocity();
}
return vga_main();
}

Wyświetl plik

@ -0,0 +1,23 @@
PROJECT(textmode)
if (TARGET pico_scanvideo_dpi)
add_executable(textmode
textmode.c
font6.c
font8.c
font10.c
lcd.c
)
target_compile_definitions(textmode PRIVATE
PICO_SCANVIDEO_SCANLINE_BUFFER_COUNT=4
PICO_SCANVIDEO_PLANE1_FIXED_FRAGMENT_DMA=true
)
target_link_libraries(textmode PRIVATE
pico_multicore
pico_stdlib
pico_scanvideo_dpi
render)
pico_add_extra_outputs(textmode)
endif()

Wyświetl plik

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FONT_H
#define _FONT_H
#include "pico/types.h"
typedef struct {
uint16_t bitmap_index;
uint16_t adv_w;
int8_t box_w, box_h, ofs_x, ofs_y;
} __attribute__((packed)) lv_font_fmt_txt_glyph_dsc_t;
typedef struct {
uint16_t range_start, range_length, glyph_id_start, list_length;
void *unicode_list, *glyph_id_ofs_list;
enum {
LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
} type;
} lv_font_fmt_txt_cmap_t;
typedef struct {
const uint8_t *glyph_bitmap;
const lv_font_fmt_txt_glyph_dsc_t *glyph_dsc;
const lv_font_fmt_txt_cmap_t *cmaps;
uint8_t cmap_num, bpp, kern_scale, kern_classes;
void *kern_dsc;
} lv_font_fmt_txt_dsc_t;
typedef struct {
lv_font_fmt_txt_dsc_t *dsc;
uint8_t line_height, base_line;
} lv_font_t;
extern const lv_font_t ubuntu_mono6;
extern const lv_font_t ubuntu_mono8;
extern const lv_font_t ubuntu_mono10;
extern const lv_font_t lcd;
#endif //SOFTWARE_FONT_H

Wyświetl plik

@ -0,0 +1,880 @@
#include "font.h"
/*******************************************************************************
* Size: 20 px
* Bpp: 4
* Opts:
******************************************************************************/
#ifndef UBUNTU_MONO
#define UBUNTU_MONO 1
#endif
#if UBUNTU_MONO
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static const uint8_t gylph_bitmap[] = {
/* U+20 " " */
/* U+21 "!" */
0xff, 0xf, 0xf0, 0xff, 0xf, 0xf0, 0xff, 0xd,
0xd0, 0xcc, 0x0, 0x0, 0x0, 0x9, 0xf8, 0xff,
0xf9, 0xf9,
/* U+22 "\"" */
0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0,
0xff, 0xcc, 0x0, 0xcc, 0xaa, 0x0, 0xaa,
/* U+23 "#" */
0xe, 0xf2, 0xf, 0xf2, 0x9, 0xf7, 0xf, 0xf7,
0x3, 0xfc, 0xf, 0xfc, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x3, 0xfd, 0x3f, 0xfd,
0x9, 0xf7, 0x9f, 0xf7, 0xe, 0xf2, 0xef, 0xf2,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xf, 0xf0, 0xcf, 0xf0, 0xf, 0xf0, 0x4f, 0xf0,
/* U+24 "$" */
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x5, 0xcf, 0xfe, 0xa0, 0x7f, 0xff, 0xff, 0xc0,
0xef, 0x70, 0x0, 0x0, 0xff, 0x10, 0x0, 0x0,
0xdf, 0xd6, 0x20, 0x0, 0x3f, 0xff, 0xf9, 0x20,
0x1, 0x9e, 0xff, 0xe3, 0x0, 0x0, 0x4d, 0xfc,
0x0, 0x0, 0x1, 0xff, 0xa5, 0x20, 0x16, 0xfe,
0xff, 0xff, 0xff, 0xf8, 0x4b, 0xff, 0xfd, 0x60,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
/* U+25 "%" */
0x3d, 0xd3, 0x0, 0x8, 0xbd, 0x76, 0xb0, 0x3,
0xf1, 0xf0, 0xf, 0x0, 0xd5, 0xf, 0x0, 0xf0,
0x7c, 0x0, 0xc7, 0x6c, 0x2e, 0x20, 0x3, 0xee,
0x3c, 0x70, 0x0, 0x0, 0x7, 0xc3, 0xdd, 0x30,
0x2, 0xe2, 0xd6, 0x7b, 0x0, 0xc7, 0xf, 0x0,
0xf0, 0x5c, 0x0, 0xf0, 0xf, 0x1e, 0x30, 0xd,
0x67, 0xcb, 0x80, 0x0, 0x3e, 0xe3,
/* U+26 "&" */
0x1, 0x9f, 0xfb, 0x30, 0x0, 0xcf, 0xff, 0xfd,
0x0, 0xf, 0xf3, 0x3f, 0xf0, 0x0, 0xcf, 0x34,
0xf8, 0x0, 0x3, 0xfe, 0xf9, 0x0, 0x0, 0x8f,
0xfd, 0x1f, 0xe0, 0x5f, 0x8a, 0xfc, 0xce, 0xd,
0xf1, 0xa, 0xff, 0xb0, 0xff, 0x10, 0xb, 0xf9,
0xf, 0xf9, 0x16, 0xef, 0xe1, 0x8f, 0xff, 0xfd,
0x8f, 0x70, 0x8f, 0xfa, 0x12, 0xfc,
/* U+27 "'" */
0xff, 0xff, 0xff, 0xcc, 0xbb,
/* U+28 "(" */
0x0, 0x1, 0x87, 0x0, 0x3c, 0xf9, 0x1, 0xdf,
0x60, 0xc, 0xf6, 0x0, 0x4f, 0xc0, 0x0, 0xbf,
0x50, 0x0, 0xdf, 0x20, 0x0, 0xff, 0x0, 0x0,
0xdf, 0x10, 0x0, 0xbf, 0x60, 0x0, 0x4f, 0xb0,
0x0, 0xc, 0xf7, 0x0, 0x1, 0xdf, 0x60, 0x0,
0x3d, 0xf8, 0x0, 0x1, 0x97,
/* U+29 ")" */
0x88, 0x0, 0x0, 0x9f, 0xc3, 0x0, 0x6, 0xfc,
0x10, 0x0, 0x7f, 0xb0, 0x0, 0xc, 0xf4, 0x0,
0x5, 0xfb, 0x0, 0x1, 0xfc, 0x0, 0x0, 0xff,
0x0, 0x2, 0xff, 0x0, 0x6, 0xfb, 0x0, 0xc,
0xf5, 0x0, 0x7f, 0xc0, 0x6, 0xff, 0x20, 0x9f,
0xe3, 0x0, 0x8a, 0x10, 0x0,
/* U+2A "*" */
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x99, 0x2c, 0xc2, 0x99, 0xef, 0xfd, 0xdf, 0xfd,
0x24, 0x8f, 0xf9, 0x42, 0x5, 0xec, 0xce, 0x50,
0x8, 0xc1, 0x1c, 0x80,
/* U+2B "+" */
0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0xff, 0xff,
0xff, 0xf0, 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0, 0x0,
/* U+2C "," */
0x8, 0xf8, 0xf, 0xfe, 0xa, 0xff, 0x1, 0xea,
0x2a, 0xf2, 0xda, 0x20,
/* U+2D "-" */
0xff, 0xff, 0xff, 0xff,
/* U+2E "." */
0x9f, 0x9f, 0xff, 0x9f, 0x90,
/* U+2F "/" */
0x0, 0x0, 0x5, 0xfc, 0x0, 0x0, 0xa, 0xf6,
0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0x5f, 0x90,
0x0, 0x0, 0xbf, 0x20, 0x0, 0x0, 0xfc, 0x0,
0x0, 0x6, 0xf5, 0x0, 0x0, 0xb, 0xe0, 0x0,
0x0, 0x1f, 0x80, 0x0, 0x0, 0x6f, 0x10, 0x0,
0x0, 0xcb, 0x0, 0x0, 0x1, 0xf4, 0x0, 0x0,
0x7, 0xe0, 0x0, 0x0, 0xc, 0x70, 0x0, 0x0,
0x2f, 0x10, 0x0, 0x0, 0x7a, 0x0, 0x0, 0x0,
0xd4, 0x0, 0x0, 0x0,
/* U+30 "0" */
0x1, 0xad, 0xda, 0x10, 0xd, 0xff, 0xff, 0xc0,
0x6f, 0xd2, 0x2d, 0xf6, 0xbf, 0x50, 0x6, 0xfb,
0xdf, 0x1c, 0xb1, 0xfc, 0xff, 0xf, 0xf0, 0xff,
0xff, 0xc, 0xc0, 0xff, 0xdf, 0x10, 0x1, 0xfd,
0xbf, 0x50, 0x6, 0xfb, 0x6f, 0xc2, 0x2c, 0xf6,
0xd, 0xff, 0xff, 0xd0, 0x1, 0xae, 0xeb, 0x10,
/* U+31 "1" */
0x0, 0x3, 0xef, 0x0, 0x0, 0x5e, 0xff, 0x0,
0x4b, 0xfb, 0xff, 0x0, 0xbb, 0x40, 0xff, 0x0,
0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0,
0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0,
0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0,
0xf, 0xff, 0xff, 0xff, 0xf, 0xff, 0xff, 0xff,
/* U+32 "2" */
0x17, 0xdf, 0xc7, 0x10, 0xdf, 0xff, 0xff, 0x90,
0x78, 0x11, 0xaf, 0xe0, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x0, 0x2f, 0x90, 0x0, 0x0, 0xbd, 0x10,
0x0, 0xa, 0xd1, 0x0, 0x0, 0xad, 0x10, 0x0,
0xa, 0xd1, 0x0, 0x0, 0x6f, 0x30, 0x0, 0x0,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* U+33 "3" */
0x29, 0xef, 0xd7, 0x0, 0xef, 0xff, 0xff, 0x90,
0x86, 0x1, 0x8f, 0xe0, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x1, 0x9f, 0x90, 0x0, 0xff, 0xf8, 0x0,
0x0, 0xff, 0xfe, 0x71, 0x0, 0x0, 0x4b, 0xf9,
0x0, 0x0, 0x0, 0xff, 0xa4, 0x0, 0x29, 0xfe,
0xff, 0xff, 0xff, 0xf6, 0x6b, 0xff, 0xfb, 0x40,
/* U+34 "4" */
0x0, 0xc, 0xff, 0xf0, 0x0, 0x6f, 0xff, 0xf0,
0x1, 0xef, 0xff, 0xf0, 0x8, 0xff, 0x7f, 0xf0,
0xe, 0xfa, 0xf, 0xf0, 0x6f, 0xe1, 0xf, 0xf0,
0xcf, 0x40, 0xf, 0xf0, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0,
/* U+35 "5" */
0x8, 0xff, 0xff, 0xff, 0x9, 0xff, 0xff, 0xff,
0xc, 0xf4, 0x0, 0x0, 0xc, 0xf0, 0x0, 0x0,
0xc, 0xfe, 0xb7, 0x10, 0xf, 0xff, 0xff, 0xe1,
0x0, 0x3, 0x6e, 0xfb, 0x0, 0x0, 0x2, 0xfd,
0x0, 0x0, 0x1, 0xff, 0xa4, 0x0, 0x2a, 0xfc,
0xff, 0xff, 0xff, 0xf3, 0x6b, 0xff, 0xea, 0x30,
/* U+36 "6" */
0x0, 0x4, 0x9d, 0xe0, 0x1, 0xaf, 0xff, 0xf0,
0xb, 0xfc, 0x52, 0x0, 0x4f, 0xb0, 0x0, 0x0,
0xaf, 0xbe, 0xfd, 0x60, 0xef, 0xff, 0xff, 0xf6,
0xff, 0x50, 0xa, 0xfc, 0xff, 0x0, 0x0, 0xff,
0xcf, 0x30, 0x1, 0xff, 0x9f, 0xb1, 0x19, 0xfb,
0x2f, 0xff, 0xff, 0xf3, 0x2, 0xbe, 0xfd, 0x30,
/* U+37 "7" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x6, 0xf9, 0x0, 0x0, 0x2e, 0xe1,
0x0, 0x0, 0xaf, 0x50, 0x0, 0x2, 0xfe, 0x0,
0x0, 0xa, 0xf6, 0x0, 0x0, 0xf, 0xf1, 0x0,
0x0, 0x5f, 0xb0, 0x0, 0x0, 0x9f, 0x70, 0x0,
0x0, 0xcf, 0x40, 0x0, 0x0, 0xff, 0x0, 0x0,
/* U+38 "8" */
0x5, 0xaf, 0xfc, 0x60, 0x5f, 0xff, 0xff, 0xf9,
0xef, 0x70, 0x7, 0xfe, 0xff, 0x10, 0x0, 0xfe,
0xbf, 0xc4, 0x19, 0xf5, 0x3f, 0xff, 0xff, 0x50,
0xb, 0xfe, 0xff, 0xe3, 0x8f, 0x40, 0x2b, 0xfb,
0xff, 0x0, 0x1, 0xfe, 0xff, 0x60, 0x7, 0xfd,
0x9f, 0xff, 0xff, 0xf7, 0x8, 0xdf, 0xfc, 0x60,
/* U+39 "9" */
0x3, 0xcf, 0xda, 0x10, 0x3e, 0xff, 0xff, 0xe1,
0xbf, 0xa1, 0x2d, 0xf8, 0xff, 0x10, 0x3, 0xfc,
0xff, 0x0, 0x0, 0xff, 0xdf, 0x90, 0x5, 0xff,
0x6f, 0xff, 0xff, 0xfc, 0x7, 0xef, 0xfc, 0xfa,
0x0, 0x0, 0xb, 0xf4, 0x0, 0x25, 0xbf, 0xb0,
0xf, 0xff, 0xfb, 0x10, 0xf, 0xca, 0x40, 0x0,
/* U+3A ":" */
0x9f, 0x9f, 0xff, 0x9f, 0x90, 0x0, 0x0, 0x0,
0x0, 0x9f, 0x9f, 0xff, 0x9f, 0x90,
/* U+3B ";" */
0x9, 0xf9, 0xf, 0xff, 0x9, 0xf9, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x8, 0xf8, 0xf, 0xfe,
0xa, 0xff, 0x1, 0xea, 0x2a, 0xf2, 0xda, 0x20,
/* U+3C "<" */
0x0, 0x0, 0x4, 0x9a, 0x0, 0x27, 0xdf, 0xa3,
0x6b, 0xfd, 0x61, 0x0, 0xff, 0x60, 0x0, 0x0,
0x8f, 0xf7, 0x10, 0x0, 0x1, 0x8f, 0xe6, 0x0,
0x0, 0x1, 0x8f, 0xd4, 0x0, 0x0, 0x1, 0x8b,
/* U+3D "=" */
0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff,
/* U+3E ">" */
0xb9, 0x40, 0x0, 0x0, 0x3a, 0xfd, 0x72, 0x0,
0x0, 0x16, 0xef, 0xb5, 0x0, 0x0, 0x6, 0xff,
0x0, 0x1, 0x8f, 0xf8, 0x0, 0x7e, 0xf8, 0x10,
0x4d, 0xf8, 0x10, 0x0, 0xb8, 0x10, 0x0, 0x0,
/* U+3F "?" */
0x4a, 0xff, 0xd9, 0x1e, 0xff, 0xff, 0xfb, 0x96,
0x0, 0x7f, 0xf0, 0x0, 0x1, 0xf9, 0x0, 0x3,
0xcb, 0x10, 0x6, 0xfb, 0x0, 0x0, 0xff, 0x10,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x9, 0xf8, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x9,
0xf9, 0x0,
/* U+40 "@" */
0x0, 0x7d, 0xfb, 0x50, 0x7, 0xff, 0xff, 0xf4,
0x2e, 0xf4, 0x1b, 0xfb, 0x7f, 0x90, 0x3, 0xfe,
0xcf, 0x40, 0x0, 0xff, 0xef, 0x11, 0xbf, 0xff,
0xff, 0xb, 0xff, 0xff, 0xff, 0xf, 0xf2, 0xff,
0xff, 0xf, 0xf1, 0xff, 0xdf, 0x4b, 0xff, 0xff,
0xaf, 0x81, 0xbf, 0xfd, 0x5f, 0xd1, 0x0, 0x0,
0xd, 0xfc, 0x20, 0x10, 0x3, 0xff, 0xff, 0xf0,
0x0, 0x2a, 0xff, 0xc0,
/* U+41 "A" */
0x0, 0x8, 0xff, 0x60, 0x0, 0x0, 0xef, 0xfb,
0x0, 0x0, 0x3f, 0x7f, 0xe0, 0x0, 0x9, 0xf1,
0xff, 0x30, 0x0, 0xee, 0xc, 0xf7, 0x0, 0x3f,
0xa0, 0x8f, 0xb0, 0x8, 0xf6, 0x4, 0xfd, 0x0,
0xdf, 0x20, 0x2f, 0xf1, 0x1f, 0xff, 0xff, 0xff,
0x56, 0xff, 0xff, 0xff, 0xf8, 0xaf, 0x80, 0x0,
0x7f, 0xce, 0xf4, 0x0, 0x3, 0xfe,
/* U+42 "B" */
0xdf, 0xff, 0xc7, 0x0, 0xff, 0xff, 0xff, 0x90,
0xff, 0x0, 0x8f, 0xe0, 0xff, 0x0, 0xf, 0xf0,
0xff, 0x1, 0x7f, 0x90, 0xff, 0xff, 0xf8, 0x0,
0xff, 0xff, 0xff, 0x81, 0xff, 0x0, 0x19, 0xfa,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x29, 0xfd,
0xff, 0xff, 0xff, 0xf6, 0xcf, 0xff, 0xdb, 0x40,
/* U+43 "C" */
0x0, 0x4a, 0xff, 0xa3, 0x6, 0xff, 0xff, 0xff,
0x3f, 0xf8, 0x21, 0x6a, 0xaf, 0xa0, 0x0, 0x0,
0xef, 0x30, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xef, 0x30, 0x0, 0x0,
0xbf, 0xa0, 0x0, 0x0, 0x4f, 0xf7, 0x20, 0x5a,
0xa, 0xff, 0xff, 0xfe, 0x0, 0x6d, 0xff, 0xb4,
/* U+44 "D" */
0xcf, 0xfe, 0xa4, 0x0, 0xff, 0xff, 0xff, 0x70,
0xff, 0x2, 0x7f, 0xf4, 0xff, 0x0, 0x8, 0xfa,
0xff, 0x0, 0x4, 0xfd, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x3, 0xfe,
0xff, 0x0, 0x8, 0xfa, 0xff, 0x1, 0x6f, 0xf4,
0xff, 0xff, 0xff, 0x80, 0xcf, 0xff, 0xb4, 0x0,
/* U+45 "E" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0,
0x0, 0xf, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff,
0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
/* U+46 "F" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0,
0x0, 0xf, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff,
0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x0,
/* U+47 "G" */
0x0, 0x4b, 0xff, 0xa4, 0x6, 0xff, 0xff, 0xfe,
0x3f, 0xfa, 0x20, 0x59, 0xaf, 0xb0, 0x0, 0x0,
0xef, 0x30, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0xff, 0xef, 0x30, 0x0, 0xff,
0xaf, 0x80, 0x0, 0xff, 0x4f, 0xf6, 0x1, 0xff,
0x9, 0xff, 0xff, 0xff, 0x0, 0x6d, 0xff, 0xda,
/* U+48 "H" */
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
/* U+49 "I" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff,
0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0,
0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0,
0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
/* U+4A "J" */
0xf, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0,
0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x2f, 0xf9,
0x50, 0x1a, 0xfd, 0xef, 0xff, 0xff, 0x53, 0xbf,
0xfd, 0x50,
/* U+4B "K" */
0xff, 0x0, 0x1d, 0xfc, 0xff, 0x0, 0x8f, 0xf2,
0xff, 0x2, 0xff, 0x80, 0xff, 0xc, 0xfd, 0x10,
0xff, 0x8f, 0xf3, 0x0, 0xff, 0xff, 0x80, 0x0,
0xff, 0xaf, 0x90, 0x0, 0xff, 0xd, 0xf8, 0x0,
0xff, 0x2, 0xff, 0x40, 0xff, 0x0, 0x8f, 0xd0,
0xff, 0x0, 0x1f, 0xf6, 0xff, 0x0, 0x8, 0xfc,
/* U+4C "L" */
0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0,
0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
/* U+4D "M" */
0x3f, 0xe0, 0xf, 0xf4, 0x4f, 0xf2, 0x2f, 0xf4,
0x6f, 0xf5, 0x6f, 0xf7, 0x8f, 0xc9, 0x9c, 0xf8,
0x8f, 0x8c, 0xc8, 0xf8, 0xbf, 0x4f, 0xf4, 0xfc,
0xcf, 0x2d, 0xd0, 0xfc, 0xcf, 0x0, 0x0, 0xfc,
0xcf, 0x0, 0x0, 0xfc, 0xff, 0x0, 0x0, 0xfd,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
/* U+4E "N" */
0xff, 0x20, 0x0, 0xff, 0xff, 0xa0, 0x0, 0xff,
0xff, 0xf2, 0x0, 0xff, 0xff, 0x8a, 0x0, 0xff,
0xff, 0x1f, 0x20, 0xff, 0xff, 0x8, 0x90, 0xff,
0xff, 0x2, 0xf1, 0xff, 0xff, 0x0, 0xa6, 0xff,
0xff, 0x0, 0x3c, 0xff, 0xff, 0x0, 0xd, 0xff,
0xff, 0x0, 0x6, 0xff, 0xff, 0x0, 0x1, 0xff,
/* U+4F "O" */
0x2, 0xaf, 0xfa, 0x10, 0x1c, 0xff, 0xff, 0xc0,
0x7f, 0xd2, 0x2e, 0xf7, 0xcf, 0x60, 0x6, 0xfc,
0xff, 0x10, 0x1, 0xfe, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x10, 0x1, 0xff,
0xcf, 0x60, 0x6, 0xfc, 0x7f, 0xc2, 0x2d, 0xf6,
0x1d, 0xff, 0xff, 0xd0, 0x2, 0xbf, 0xfb, 0x10,
/* U+50 "P" */
0xcf, 0xff, 0xe9, 0x30, 0xff, 0xff, 0xff, 0xf3,
0xff, 0x0, 0x4c, 0xfb, 0xff, 0x0, 0x3, 0xff,
0xff, 0x0, 0x1, 0xff, 0xff, 0x0, 0x2a, 0xfb,
0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xeb, 0x20,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
/* U+51 "Q" */
0x2, 0xaf, 0xfa, 0x10, 0x1c, 0xff, 0xff, 0xc0,
0x7f, 0xd2, 0x2e, 0xf6, 0xcf, 0x60, 0x6, 0xfc,
0xff, 0x10, 0x1, 0xfe, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xef, 0x10, 0x1, 0xff,
0xcf, 0x50, 0x6, 0xfc, 0x7f, 0xc2, 0x2d, 0xf7,
0x1e, 0xff, 0xff, 0xf1, 0x3, 0xcf, 0xfe, 0x30,
0x0, 0xe, 0xf7, 0x30, 0x0, 0x3, 0xff, 0xff,
0x0, 0x0, 0x17, 0xcc,
/* U+52 "R" */
0xcf, 0xff, 0xc9, 0x20, 0xf, 0xff, 0xff, 0xfe,
0x30, 0xff, 0x0, 0x2a, 0xfb, 0xf, 0xf0, 0x0,
0x1f, 0xd0, 0xff, 0x0, 0x1, 0xff, 0xf, 0xf0,
0x2, 0x9f, 0xd0, 0xff, 0xff, 0xff, 0xf6, 0xf,
0xff, 0xff, 0xfb, 0x0, 0xff, 0x0, 0xaf, 0xe1,
0xf, 0xf0, 0x1, 0xef, 0xa0, 0xff, 0x0, 0x6,
0xff, 0x4f, 0xf0, 0x0, 0xe, 0xfb,
/* U+53 "S" */
0x4, 0xae, 0xfe, 0xa4, 0x6f, 0xff, 0xff, 0xfe,
0xdf, 0x81, 0x2, 0x88, 0xff, 0x10, 0x0, 0x0,
0xcf, 0xd5, 0x10, 0x0, 0x3f, 0xff, 0xf9, 0x20,
0x1, 0x8e, 0xff, 0xe3, 0x0, 0x0, 0x3b, 0xfc,
0x0, 0x0, 0x1, 0xff, 0x96, 0x20, 0x17, 0xfd,
0xff, 0xff, 0xff, 0xf6, 0x2a, 0xef, 0xfb, 0x60,
/* U+54 "T" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
/* U+55 "U" */
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x20, 0x3, 0xff, 0xcf, 0xa1, 0x1a, 0xfb,
0x5f, 0xff, 0xff, 0xf5, 0x5, 0xdf, 0xfd, 0x50,
/* U+56 "V" */
0xef, 0x40, 0x0, 0x3f, 0xea, 0xf9, 0x0, 0x6,
0xfa, 0x6f, 0xc0, 0x0, 0xaf, 0x62, 0xff, 0x20,
0xe, 0xf2, 0xd, 0xf7, 0x2, 0xfd, 0x0, 0x9f,
0xc0, 0x6f, 0x90, 0x4, 0xff, 0x2b, 0xf3, 0x0,
0xf, 0xf9, 0xff, 0x0, 0x0, 0xaf, 0xff, 0xa0,
0x0, 0x5, 0xff, 0xf5, 0x0, 0x0, 0xf, 0xff,
0x0, 0x0, 0x0, 0xbf, 0xa0, 0x0,
/* U+57 "W" */
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0xd, 0xc0, 0xff,
0xff, 0x1f, 0xf1, 0xff, 0xff, 0x6b, 0xb6, 0xff,
0xff, 0xa7, 0x7a, 0xff, 0xff, 0xf3, 0x2f, 0xff,
0xff, 0xe0, 0xe, 0xff, 0xff, 0xa0, 0x9, 0xff,
/* U+58 "X" */
0xcf, 0x70, 0x8, 0xfb, 0x2f, 0xc0, 0xe, 0xf2,
0x8, 0xf3, 0x4f, 0x80, 0x1, 0xf9, 0xae, 0x10,
0x0, 0x6d, 0xe5, 0x0, 0x0, 0xd, 0xd0, 0x0,
0x0, 0x4f, 0xf3, 0x0, 0x0, 0xc7, 0x8b, 0x0,
0x6, 0xe0, 0xe, 0x60, 0xe, 0x60, 0x6, 0xd0,
0x6e, 0x0, 0x0, 0xf6, 0xd7, 0x0, 0x0, 0x8c,
/* U+59 "Y" */
0xdf, 0x80, 0x0, 0x8, 0xfc, 0x6f, 0xe1, 0x0,
0x1e, 0xf6, 0xe, 0xf8, 0x0, 0x8f, 0xe0, 0x6,
0xfe, 0x22, 0xef, 0x50, 0x0, 0xdf, 0xab, 0xfc,
0x0, 0x0, 0x4f, 0xff, 0xf3, 0x0, 0x0, 0xb,
0xff, 0x90, 0x0, 0x0, 0x1, 0xff, 0x10, 0x0,
0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff,
0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0x0, 0xff, 0x0, 0x0,
/* U+5A "Z" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x1e, 0xf9, 0x0, 0x0, 0xcf, 0xd0,
0x0, 0x7, 0xff, 0x30, 0x0, 0x2e, 0xf8, 0x0,
0x0, 0xcf, 0xd0, 0x0, 0x6, 0xff, 0x40, 0x0,
0x1e, 0xfa, 0x0, 0x0, 0x8f, 0xf1, 0x0, 0x0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* U+5B "[" */
0xff, 0xff, 0xff, 0xf0, 0x0, 0xff, 0x0, 0xf,
0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0, 0x0, 0xff,
0x0, 0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0,
0x0, 0xff, 0x0, 0xf, 0xf0, 0x0, 0xff, 0x0,
0xf, 0xf0, 0x0, 0xff, 0xff, 0xf0,
/* U+5C "\\" */
0xcf, 0x50, 0x0, 0x0, 0x6f, 0xa0, 0x0, 0x0,
0xe, 0xf0, 0x0, 0x0, 0x9, 0xf5, 0x0, 0x0,
0x2, 0xfb, 0x0, 0x0, 0x0, 0xcf, 0x0, 0x0,
0x0, 0x5f, 0x60, 0x0, 0x0, 0xe, 0xb0, 0x0,
0x0, 0x8, 0xf1, 0x0, 0x0, 0x1, 0xf6, 0x0,
0x0, 0x0, 0xbc, 0x0, 0x0, 0x0, 0x5f, 0x10,
0x0, 0x0, 0xe, 0x70, 0x0, 0x0, 0x8, 0xc0,
0x0, 0x0, 0x1, 0xf2, 0x0, 0x0, 0x0, 0xb7,
0x0, 0x0, 0x0, 0x4d,
/* U+5D "]" */
0xff, 0xff, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0,
0x0, 0xff, 0x0, 0xf, 0xf0, 0x0, 0xff, 0x0,
0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0, 0x0,
0xff, 0x0, 0xf, 0xf0, 0x0, 0xff, 0x0, 0xf,
0xf0, 0x0, 0xff, 0xff, 0xff, 0xf0,
/* U+5E "^" */
0x0, 0x9, 0xf9, 0x0, 0x0, 0x3, 0xff, 0xf3,
0x0, 0x0, 0xcf, 0x2f, 0xb0, 0x0, 0x6f, 0x50,
0x5f, 0x50, 0x1d, 0xb0, 0x0, 0xbd, 0x18, 0xf1,
0x0, 0x1, 0xf8, 0xb5, 0x0, 0x0, 0x5, 0xb0,
/* U+5F "_" */
0xff, 0xff, 0xff, 0xff, 0xff,
/* U+60 "`" */
0x65, 0xb, 0xd1, 0x1e, 0x80, 0x3b,
/* U+61 "a" */
0xb, 0xef, 0xfc, 0x70, 0xe, 0xff, 0xff, 0xf9,
0x0, 0x0, 0x5, 0xfe, 0x8, 0xcf, 0xfc, 0xff,
0x9f, 0x91, 0x1, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x71, 0x0, 0xff, 0x9f, 0xff, 0xff, 0xff,
0x8, 0xdf, 0xff, 0xdc,
/* U+62 "b" */
0xcf, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0xaf, 0xfa, 0x30,
0xff, 0xff, 0xff, 0xe3, 0xff, 0x70, 0x2c, 0xfa,
0xff, 0x0, 0x2, 0xfe, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x3, 0xff, 0xff, 0x0, 0x4c, 0xfa,
0xff, 0xff, 0xff, 0xf1, 0xad, 0xff, 0xea, 0x10,
/* U+63 "c" */
0x1, 0x6c, 0xff, 0xea, 0x1c, 0xff, 0xff, 0xfc,
0x9f, 0xf6, 0x10, 0x0, 0xff, 0x40, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x40, 0x0, 0x0,
0xaf, 0xd4, 0x0, 0x0, 0x1d, 0xff, 0xff, 0xfc,
0x1, 0x8d, 0xff, 0xea,
/* U+64 "d" */
0x0, 0x0, 0x0, 0xcf, 0x0, 0x0, 0x0, 0xff,
0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff,
0x0, 0x0, 0x0, 0xff, 0x3, 0xaf, 0xfa, 0xff,
0x3e, 0xff, 0xff, 0xff, 0xaf, 0xc2, 0x7, 0xff,
0xff, 0x20, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x30, 0x0, 0xff, 0xaf, 0xc4, 0x0, 0xff,
0x1f, 0xff, 0xff, 0xff, 0x1, 0xae, 0xff, 0xda,
/* U+65 "e" */
0x1, 0x9e, 0xfc, 0x50, 0x1e, 0xff, 0xff, 0xf7,
0xaf, 0x71, 0x5, 0xfc, 0xff, 0xff, 0xff, 0xff,
0xff, 0x10, 0x0, 0x0, 0xff, 0x60, 0x0, 0x0,
0xaf, 0xe5, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xd0,
0x2, 0xaf, 0xff, 0xb0,
/* U+66 "f" */
0x0, 0x5, 0xcf, 0xfb, 0x50, 0x5, 0xff, 0xff,
0xff, 0x0, 0xdf, 0xa1, 0x5, 0x90, 0xf, 0xf1,
0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf, 0xff,
0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0,
0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff,
0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0,
/* U+67 "g" */
0x1, 0x9e, 0xff, 0xc9, 0x1e, 0xff, 0xff, 0xff,
0xaf, 0xd3, 0x1, 0xff, 0xef, 0x40, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x20, 0x0, 0xff,
0xbf, 0xb1, 0x5, 0xff, 0x3f, 0xff, 0xff, 0xff,
0x4, 0xcf, 0xf9, 0xff, 0x0, 0x0, 0x16, 0xfc,
0xcf, 0xff, 0xff, 0xf4, 0xae, 0xff, 0xdb, 0x40,
/* U+68 "h" */
0xcf, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0xcf, 0xfc, 0x50,
0xff, 0xff, 0xff, 0xf6, 0xff, 0x20, 0x1b, 0xfc,
0xff, 0x0, 0x2, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
/* U+69 "i" */
0x0, 0xd, 0xc0, 0x0, 0x0, 0xd, 0xd0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0,
0xff, 0xff, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf6, 0x0,
0x0, 0xb, 0xff, 0xfd, 0x0, 0x3, 0xcf, 0xfb,
/* U+6A "j" */
0x0, 0x0, 0xdc, 0x0, 0x0, 0xd, 0xd0, 0x0,
0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xf, 0xff,
0xff, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x0, 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xff, 0x43, 0x0, 0x8f, 0xfd, 0xff, 0xff,
0xf8, 0x6c, 0xff, 0xe8, 0x0,
/* U+6B "k" */
0xcf, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x3e, 0xfa,
0xff, 0x1, 0xcf, 0xd1, 0xff, 0x1c, 0xfd, 0x10,
0xff, 0xcf, 0xf1, 0x0, 0xff, 0xff, 0xb0, 0x0,
0xff, 0x3f, 0xf9, 0x0, 0xff, 0x6, 0xff, 0x70,
0xff, 0x0, 0xbf, 0xf3, 0xff, 0x0, 0x1f, 0xfb,
/* U+6C "l" */
0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf6, 0x0,
0x0, 0xb, 0xff, 0xfd, 0x0, 0x2, 0xcf, 0xfb,
/* U+6D "m" */
0xbf, 0xfb, 0x8e, 0xd3, 0xff, 0xff, 0xff, 0xfc,
0xff, 0x1f, 0xf3, 0xff, 0xff, 0xf, 0xf0, 0xff,
0xff, 0xf, 0xf0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff,
/* U+6E "n" */
0xbb, 0xff, 0xeb, 0x50, 0xff, 0xff, 0xff, 0xf5,
0xff, 0x10, 0x1a, 0xfc, 0xff, 0x0, 0x2, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff,
/* U+6F "o" */
0x3, 0xaf, 0xfa, 0x20, 0x2e, 0xff, 0xff, 0xe2,
0xaf, 0xc2, 0x2c, 0xfa, 0xff, 0x20, 0x2, 0xfe,
0xff, 0x0, 0x0, 0xff, 0xff, 0x20, 0x2, 0xff,
0xaf, 0xb2, 0x2b, 0xfa, 0x2f, 0xff, 0xff, 0xf2,
0x3, 0xbf, 0xfb, 0x20,
/* U+70 "p" */
0xbc, 0xff, 0xd9, 0x10, 0xff, 0xff, 0xff, 0xc1,
0xff, 0x0, 0x4d, 0xfa, 0xff, 0x0, 0x4, 0xfd,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x2, 0xff,
0xff, 0x40, 0x2b, 0xfa, 0xff, 0xff, 0xff, 0xf3,
0xff, 0xbf, 0xfb, 0x30, 0xff, 0x0, 0x0, 0x0,
0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
/* U+71 "q" */
0x1, 0x9d, 0xff, 0xc9, 0x1e, 0xff, 0xff, 0xff,
0xaf, 0xd4, 0x0, 0xff, 0xff, 0x40, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x20, 0x0, 0xff,
0xaf, 0xc2, 0x5, 0xff, 0x2f, 0xff, 0xff, 0xff,
0x3, 0xbf, 0xfa, 0xff, 0x0, 0x0, 0x0, 0xff,
0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff,
/* U+72 "r" */
0x7a, 0xcf, 0xff, 0xbf, 0xff, 0xff, 0xfc, 0xff,
0x40, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0,
0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0,
0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0,
/* U+73 "s" */
0x17, 0xcf, 0xfd, 0xaa, 0xff, 0xff, 0xfc, 0xff,
0x50, 0x0, 0xe, 0xfe, 0x95, 0x0, 0x3c, 0xff,
0xfc, 0x30, 0x4, 0x9e, 0xfc, 0x94, 0x0, 0x4f,
0xff, 0xff, 0xff, 0xfb, 0x6c, 0xff, 0xe9, 0x10,
/* U+74 "t" */
0x0, 0xcf, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0,
0x0, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0,
0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0,
0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x60, 0x0,
0x0, 0xbf, 0xff, 0xfc, 0x0, 0x1b, 0xff, 0xfa,
/* U+75 "u" */
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff,
0xff, 0x0, 0x0, 0xff, 0xff, 0x20, 0x0, 0xff,
0xdf, 0xb2, 0x1, 0xff, 0x5f, 0xff, 0xff, 0xff,
0x5, 0xdf, 0xff, 0xdb,
/* U+76 "v" */
0xef, 0x40, 0x4, 0xfe, 0x9f, 0x80, 0x8, 0xf9,
0x3f, 0xc0, 0xc, 0xf3, 0xe, 0xe0, 0xf, 0xe0,
0x9, 0xf4, 0x4f, 0x90, 0x2, 0xf8, 0x9f, 0x20,
0x0, 0xcc, 0xdc, 0x0, 0x0, 0x5f, 0xf5, 0x0,
0x0, 0xe, 0xe0, 0x0,
/* U+77 "w" */
0xff, 0x0, 0x0, 0xf, 0xfd, 0xf2, 0x0, 0x2,
0xfc, 0xcf, 0x41, 0xc0, 0x4f, 0xc8, 0xf5, 0x5f,
0x16, 0xf8, 0x7f, 0x88, 0xc5, 0x8f, 0x64, 0xfa,
0xc5, 0xab, 0xf4, 0xf, 0xdf, 0xc, 0xcf, 0x0,
0xdf, 0xb0, 0x9f, 0xd0, 0xa, 0xf7, 0x3, 0xf9,
0x0,
/* U+78 "x" */
0xaf, 0xb0, 0xc, 0xfa, 0xd, 0xf4, 0x3f, 0xd1,
0x1, 0xfb, 0xaf, 0x20, 0x0, 0x3f, 0xf5, 0x0,
0x0, 0xe, 0xe2, 0x0, 0x0, 0xae, 0xac, 0x0,
0x6, 0xf3, 0x1e, 0x90, 0x2e, 0x70, 0x4, 0xf4,
0xcc, 0x0, 0x0, 0xbb,
/* U+79 "y" */
0xef, 0x50, 0x4, 0xfe, 0xaf, 0x90, 0x6, 0xfa,
0x6f, 0xd0, 0x9, 0xf6, 0x1f, 0xf3, 0xc, 0xf1,
0xd, 0xf8, 0xf, 0xd0, 0x6, 0xfd, 0x3f, 0x70,
0x1, 0xff, 0xaf, 0x20, 0x0, 0xaf, 0xfd, 0x0,
0x0, 0x4f, 0xf7, 0x0, 0x1, 0x9f, 0xf1, 0x0,
0xef, 0xff, 0x70, 0x0, 0xdf, 0xe6, 0x0, 0x0,
/* U+7A "z" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0,
0x6, 0xff, 0x60, 0x3, 0xef, 0xa0, 0x1, 0xef,
0xc0, 0x0, 0xcf, 0xf1, 0x0, 0x8f, 0xf5, 0x0,
0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
/* U+7B "{" */
0x0, 0x1a, 0xff, 0xf0, 0xb, 0xf5, 0x0, 0x0,
0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0,
0x0, 0x7f, 0x80, 0x0, 0xff, 0xb0, 0x0, 0x0,
0x7f, 0x80, 0x0, 0x0, 0xfe, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x0, 0xff, 0x0, 0x0, 0xb, 0xf5, 0x0,
0x0, 0x2b, 0xff, 0xf0,
/* U+7C "|" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff,
/* U+7D "}" */
0xff, 0xfa, 0x10, 0x0, 0x5, 0xfb, 0x0, 0x0,
0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf,
0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xf, 0xf0,
0x0, 0x0, 0x8f, 0x70, 0x0, 0x0, 0xcf, 0xf0,
0x0, 0x8f, 0x70, 0x0, 0xf, 0xf0, 0x0, 0x0,
0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff,
0x0, 0x0, 0xf, 0xf0, 0x0, 0x5, 0xfb, 0x0,
0xff, 0xfb, 0x10, 0x0,
/* U+7E "~" */
0x9, 0xfc, 0x40, 0x2, 0xb6, 0xff, 0xff, 0x70,
0x9c, 0xc9, 0x8, 0xff, 0xff, 0x6c, 0x20, 0x4,
0xdf, 0x90
};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 160, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 160, .box_h = 12, .box_w = 3, .ofs_x = 4, .ofs_y = 0},
{.bitmap_index = 18, .adv_w = 160, .box_h = 5, .box_w = 6, .ofs_x = 3, .ofs_y = 9},
{.bitmap_index = 33, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 81, .adv_w = 160, .box_h = 16, .box_w = 8, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 145, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 199, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 253, .adv_w = 160, .box_h = 5, .box_w = 2, .ofs_x = 4, .ofs_y = 9},
{.bitmap_index = 258, .adv_w = 160, .box_h = 15, .box_w = 6, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 303, .adv_w = 160, .box_h = 15, .box_w = 6, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 348, .adv_w = 160, .box_h = 7, .box_w = 8, .ofs_x = 1, .ofs_y = 5},
{.bitmap_index = 376, .adv_w = 160, .box_h = 9, .box_w = 7, .ofs_x = 1, .ofs_y = 1},
{.bitmap_index = 408, .adv_w = 160, .box_h = 6, .box_w = 4, .ofs_x = 3, .ofs_y = -3},
{.bitmap_index = 420, .adv_w = 160, .box_h = 2, .box_w = 4, .ofs_x = 3, .ofs_y = 4},
{.bitmap_index = 424, .adv_w = 160, .box_h = 3, .box_w = 3, .ofs_x = 4, .ofs_y = 0},
{.bitmap_index = 429, .adv_w = 160, .box_h = 17, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 497, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 545, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 593, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 641, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 689, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 737, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 785, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 833, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 881, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 929, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 977, .adv_w = 160, .box_h = 9, .box_w = 3, .ofs_x = 4, .ofs_y = 0},
{.bitmap_index = 991, .adv_w = 160, .box_h = 12, .box_w = 4, .ofs_x = 3, .ofs_y = -3},
{.bitmap_index = 1015, .adv_w = 160, .box_h = 8, .box_w = 8, .ofs_x = 1, .ofs_y = 1},
{.bitmap_index = 1047, .adv_w = 160, .box_h = 4, .box_w = 8, .ofs_x = 1, .ofs_y = 3},
{.bitmap_index = 1063, .adv_w = 160, .box_h = 8, .box_w = 8, .ofs_x = 1, .ofs_y = 1},
{.bitmap_index = 1095, .adv_w = 160, .box_h = 12, .box_w = 7, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1137, .adv_w = 160, .box_h = 15, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 1197, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1251, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1299, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1347, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1395, .adv_w = 160, .box_h = 12, .box_w = 7, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 1437, .adv_w = 160, .box_h = 12, .box_w = 7, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 1479, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1527, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1575, .adv_w = 160, .box_h = 12, .box_w = 6, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 1611, .adv_w = 160, .box_h = 12, .box_w = 7, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1653, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1701, .adv_w = 160, .box_h = 12, .box_w = 7, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 1743, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1791, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1839, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1887, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1935, .adv_w = 160, .box_h = 15, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 1995, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2049, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2097, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2145, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2193, .adv_w = 160, .box_h = 12, .box_w = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 2247, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2295, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2343, .adv_w = 160, .box_h = 12, .box_w = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 2403, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2451, .adv_w = 160, .box_h = 15, .box_w = 5, .ofs_x = 3, .ofs_y = -3},
{.bitmap_index = 2489, .adv_w = 160, .box_h = 17, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2557, .adv_w = 160, .box_h = 15, .box_w = 5, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 2595, .adv_w = 160, .box_h = 7, .box_w = 9, .ofs_x = 1, .ofs_y = 5},
{.bitmap_index = 2627, .adv_w = 160, .box_h = 1, .box_w = 10, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 2632, .adv_w = 160, .box_h = 4, .box_w = 3, .ofs_x = 4, .ofs_y = 10},
{.bitmap_index = 2638, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2674, .adv_w = 160, .box_h = 14, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2730, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2766, .adv_w = 160, .box_h = 14, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2822, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2858, .adv_w = 160, .box_h = 14, .box_w = 9, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2921, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2969, .adv_w = 160, .box_h = 14, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3025, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3073, .adv_w = 160, .box_h = 15, .box_w = 7, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 3126, .adv_w = 160, .box_h = 14, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3182, .adv_w = 160, .box_h = 14, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3238, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3274, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3310, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3346, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 3394, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 3442, .adv_w = 160, .box_h = 9, .box_w = 7, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 3474, .adv_w = 160, .box_h = 9, .box_w = 7, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 3506, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3554, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3590, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3626, .adv_w = 160, .box_h = 9, .box_w = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 3667, .adv_w = 160, .box_h = 9, .box_w = 8, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3703, .adv_w = 160, .box_h = 12, .box_w = 8, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 3751, .adv_w = 160, .box_h = 9, .box_w = 7, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3783, .adv_w = 160, .box_h = 17, .box_w = 7, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 3843, .adv_w = 160, .box_h = 17, .box_w = 2, .ofs_x = 4, .ofs_y = -3},
{.bitmap_index = 3860, .adv_w = 160, .box_h = 17, .box_w = 7, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 3920, .adv_w = 160, .box_h = 4, .box_w = 9, .ofs_x = 1, .ofs_y = 4}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
.range_start = 32, .range_length = 95, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY,
.glyph_id_start = 1, .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0
}
};
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
/*Store all the custom data of the font*/
static lv_font_fmt_txt_dsc_t font_dsc = {
.glyph_bitmap = gylph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.cmap_num = 1,
.bpp = 4,
.kern_scale = 0,
.kern_dsc = NULL,
.kern_classes = 0,
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
const lv_font_t ubuntu_mono10 = {
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
// .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
// .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.line_height = 19, /*The maximum line height required by the font*/
.base_line = 4, /*Baseline measured from the bottom of the line*/
};
#endif /*#if UBUNTU_MONO*/

Wyświetl plik

@ -0,0 +1,530 @@
#include "font.h"
/*******************************************************************************
* Size: 10 px
* Bpp: 4
* Opts:
******************************************************************************/
#ifndef UBUNTU_MONO
#define UBUNTU_MONO 1
#endif
#if UBUNTU_MONO
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static const uint8_t gylph_bitmap[] = {
/* U+20 " " */
/* U+21 "!" */
0xff, 0xfc, 0xc,
/* U+22 "\"" */
0xf0, 0xff, 0xf, 0xb0, 0xa0,
/* U+23 "#" */
0x1f, 0x1f, 0x4c, 0x4c, 0xff, 0xff, 0x97, 0x97,
0xff, 0xff, 0xf1, 0xf1,
/* U+24 "$" */
0xf, 0x9, 0xfe, 0xf1, 0xe, 0xb2, 0x2b, 0xd0,
0x1f, 0xff, 0x90, 0xf0,
/* U+25 "%" */
0xaf, 0xcc, 0xf4, 0xf4, 0xaf, 0xc0, 0xc, 0xf9,
0x4f, 0x4f, 0xcd, 0xfa,
/* U+26 "&" */
0x9f, 0xa0, 0xf2, 0xf0, 0xca, 0x60, 0xcc, 0x7e,
0xf2, 0xf6, 0xaf, 0x8c,
/* U+27 "'" */
0xff, 0xb0,
/* U+28 "(" */
0x3, 0xb3, 0xe1, 0xa6, 0xf, 0x0, 0xf0, 0xa,
0x60, 0x3e, 0x10, 0x3b,
/* U+29 ")" */
0xb3, 0x2, 0xe3, 0x6, 0xa0, 0xf, 0x0, 0xf0,
0x6b, 0x1e, 0x3c, 0x30,
/* U+2A "*" */
0x0, 0xf0, 0xc, 0x9d, 0x9b, 0x1a, 0xea, 0x10,
0xb2, 0xb0,
/* U+2B "+" */
0x0, 0xf0, 0x0, 0xf, 0x0, 0xff, 0xff, 0xf0,
0xf, 0x0, 0x0, 0xf0, 0x0,
/* U+2C "," */
0xd, 0xf7,
/* U+2D "-" */
0xff,
/* U+2E "." */
0xc0,
/* U+2F "/" */
0x2, 0xe0, 0x6b, 0x9, 0x70, 0xd4, 0xf, 0x4,
0xd0, 0x79, 0xb, 0x60, 0xe2, 0x0,
/* U+30 "0" */
0x3d, 0xd3, 0xc4, 0x5b, 0xfd, 0xef, 0xf0, 0xf,
0xc5, 0x5c, 0x3e, 0xe3,
/* U+31 "1" */
0x5e, 0x9, 0xf0, 0xf, 0x0, 0xf0, 0xf, 0xf,
0xff,
/* U+32 "2" */
0x8f, 0x98, 0x1f, 0x2, 0xc1, 0xb1, 0x94, 0xf,
0xff,
/* U+33 "3" */
0xcf, 0x90, 0x2f, 0xf, 0x50, 0x3f, 0x3, 0xfe,
0xf7,
/* U+34 "4" */
0x9, 0xf0, 0x4e, 0xf0, 0xca, 0xf0, 0xff, 0xff,
0x0, 0xf0, 0x0, 0xf0,
/* U+35 "5" */
0xcf, 0xff, 0xd0, 0x0, 0xff, 0xa3, 0x1, 0x7e,
0x0, 0x4f, 0xdf, 0xe6,
/* U+36 "6" */
0x6, 0xcf, 0x7b, 0x30, 0xee, 0xf7, 0xf1, 0x3f,
0xe4, 0x3f, 0x4e, 0xf6,
/* U+37 "7" */
0xff, 0xf0, 0x3d, 0x8, 0x80, 0xb4, 0xe, 0x20,
0xf0,
/* U+38 "8" */
0x8f, 0x9f, 0x2f, 0xda, 0xac, 0xbc, 0xf2, 0xfa,
0xf9,
/* U+39 "9" */
0x7f, 0x6f, 0x3e, 0xf2, 0xf9, 0xfe, 0x17, 0xaf,
0xa1,
/* U+3A ":" */
0xc0, 0xc,
/* U+3B ";" */
0xc, 0x0, 0x0, 0xd, 0xf7,
/* U+3C "<" */
0x0, 0x4b, 0x2b, 0xc4, 0xfa, 0x31, 0x5, 0xad,
/* U+3D "=" */
0xff, 0xff, 0x0, 0x0, 0xff, 0xff,
/* U+3E ">" */
0xc4, 0x0, 0x4c, 0xb2, 0x13, 0xaf, 0xda, 0x50,
/* U+3F "?" */
0xcf, 0xf8, 0x0, 0x2f, 0x1, 0xa5, 0xd, 0x30,
0x0, 0x0, 0xc, 0x0,
/* U+40 "@" */
0x3d, 0xf6, 0xb7, 0x2f, 0xf1, 0xcf, 0xf0, 0xff,
0xe2, 0xbf, 0x9c, 0x20, 0x9, 0xff,
/* U+41 "A" */
0x1f, 0xf0, 0x4e, 0xd3, 0x7b, 0xa6, 0x98, 0x89,
0xcf, 0xfc, 0xf2, 0x2f,
/* U+42 "B" */
0xff, 0xe6, 0xf0, 0x3f, 0xff, 0xf5, 0xf0, 0x3f,
0xf0, 0x3f, 0xff, 0xe6,
/* U+43 "C" */
0x1b, 0xfd, 0xb9, 0x0, 0xf1, 0x0, 0xf0, 0x0,
0xb7, 0x0, 0x3c, 0xfd,
/* U+44 "D" */
0xff, 0xb2, 0xf0, 0x8b, 0xf0, 0xf, 0xf0, 0xf,
0xf0, 0x8b, 0xff, 0xc2,
/* U+45 "E" */
0xff, 0xff, 0xf0, 0x0, 0xff, 0xf0, 0xf0, 0x0,
0xf0, 0x0, 0xff, 0xff,
/* U+46 "F" */
0xff, 0xff, 0xf0, 0x0, 0xf0, 0x0, 0xff, 0xff,
0xf0, 0x0, 0xf0, 0x0,
/* U+47 "G" */
0x1b, 0xfd, 0xba, 0x0, 0xf1, 0x0, 0xf0, 0xf,
0xb7, 0xf, 0x3c, 0xfe,
/* U+48 "H" */
0xf0, 0xf, 0xf0, 0xf, 0xff, 0xff, 0xf0, 0xf,
0xf0, 0xf, 0xf0, 0xf,
/* U+49 "I" */
0xff, 0xf0, 0xf0, 0xf, 0x0, 0xf0, 0xf, 0xf,
0xff,
/* U+4A "J" */
0xf, 0xf0, 0xf, 0x0, 0xf0, 0xf, 0x3, 0xfd,
0xf8,
/* U+4B "K" */
0xf0, 0xcc, 0xf7, 0xf2, 0xff, 0x70, 0xf7, 0x90,
0xf0, 0xc5, 0xf0, 0x5c,
/* U+4C "L" */
0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0,
0xf0, 0x0, 0xff, 0xff,
/* U+4D "M" */
0x9c, 0xf9, 0xcc, 0xfc, 0xcc, 0xfc, 0xdc, 0xfc,
0xf0, 0xf, 0xf0, 0xf,
/* U+4E "N" */
0xf6, 0xf, 0xfb, 0xf, 0xf8, 0x4f, 0xf1, 0xaf,
0xf0, 0xaf, 0xf0, 0x6f,
/* U+4F "O" */
0x3e, 0xe3, 0xd5, 0x5c, 0xf0, 0xf, 0xf0, 0xf,
0xd5, 0x5d, 0x4f, 0xf3,
/* U+50 "P" */
0xff, 0xe6, 0xf0, 0x5f, 0xf0, 0x3f, 0xff, 0xf6,
0xf0, 0x0, 0xf0, 0x0,
/* U+51 "Q" */
0x4e, 0xe3, 0xd5, 0x5c, 0xf0, 0xf, 0xf0, 0xf,
0xe5, 0x5c, 0x8f, 0xe3, 0xd, 0x61, 0x2, 0xad,
/* U+52 "R" */
0xff, 0xd5, 0xf0, 0x3f, 0xf0, 0x3f, 0xff, 0xf6,
0xf0, 0xc6, 0xf0, 0x4d,
/* U+53 "S" */
0x6e, 0xfc, 0xf2, 0x0, 0xcc, 0x61, 0x6, 0xcb,
0x0, 0x2f, 0xcf, 0xf6,
/* U+54 "T" */
0xff, 0xff, 0xf0, 0xf, 0x0, 0x0, 0xf0, 0x0,
0xf, 0x0, 0x0, 0xf0, 0x0, 0xf, 0x0,
/* U+55 "U" */
0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf,
0xf3, 0x3f, 0x6f, 0xf6,
/* U+56 "V" */
0xe3, 0x1e, 0xb7, 0x4b, 0x7c, 0x77, 0x2f, 0xc2,
0xe, 0xe0, 0x9, 0x90,
/* U+57 "W" */
0xc4, 0x4, 0xcc, 0x40, 0x4c, 0xca, 0xfa, 0xcc,
0xcc, 0xcc, 0xcf, 0x8f, 0xcc, 0xf0, 0xfc,
/* U+58 "X" */
0xc6, 0x5b, 0x2b, 0x92, 0x8, 0x80, 0xa, 0xb0,
0x49, 0xa5, 0xc4, 0x6c,
/* U+59 "Y" */
0xc6, 0x6, 0xc4, 0xe0, 0xe4, 0xc, 0xdc, 0x0,
0x3f, 0x20, 0x0, 0xf0, 0x0, 0xf, 0x0,
/* U+5A "Z" */
0xff, 0xf0, 0x8c, 0xe, 0x46, 0xe0, 0xc7, 0xf,
0xff,
/* U+5B "[" */
0xff, 0xff, 0x0, 0xf0, 0xf, 0x0, 0xf0, 0xf,
0x0, 0xf0, 0xf, 0xff,
/* U+5C "\\" */
0xe2, 0xb, 0x60, 0x79, 0x4, 0xc0, 0xf, 0x0,
0xd3, 0x9, 0x70, 0x6a, 0x2, 0xe0,
/* U+5D "]" */
0xff, 0xf0, 0xf, 0x0, 0xf0, 0xf, 0x0, 0xf0,
0xf, 0x0, 0xff, 0xff,
/* U+5E "^" */
0x5, 0xf5, 0x3, 0xe4, 0xe2, 0xb5, 0x5, 0xb0,
/* U+5F "_" */
0xff, 0xff, 0xf0,
/* U+60 "`" */
0xa1, 0x19,
/* U+61 "a" */
0xff, 0x80, 0x1f, 0xaf, 0xff, 0x2f, 0xaf, 0xf0,
/* U+62 "b" */
0xf0, 0xf, 0x0, 0xfe, 0x8f, 0x3f, 0xf0, 0xff,
0x2e, 0xff, 0x60,
/* U+63 "c" */
0x5e, 0xee, 0x40, 0xf0, 0xe, 0x40, 0x6f, 0xf0,
/* U+64 "d" */
0x0, 0xf0, 0xf, 0x8e, 0xff, 0x3f, 0xf0, 0xfe,
0x2f, 0x6f, 0xf0,
/* U+65 "e" */
0x6f, 0x7e, 0x3e, 0xff, 0xfe, 0x30, 0x5f, 0xf0,
/* U+66 "f" */
0x8, 0xfd, 0xf, 0x10, 0xff, 0xf0, 0xf, 0x0,
0xf, 0x0, 0xf, 0x0, 0xf, 0x0,
/* U+67 "g" */
0x3d, 0xfd, 0xe5, 0xf, 0xf0, 0xf, 0xe4, 0x1f,
0x6f, 0xff, 0x0, 0x4e, 0xdf, 0xe4,
/* U+68 "h" */
0xf0, 0xf, 0x0, 0xff, 0x9f, 0x1f, 0xf0, 0xff,
0xf, 0xf0, 0xf0,
/* U+69 "i" */
0xc, 0x0, 0x0, 0xff, 0x0, 0xf0, 0xf, 0x0,
0xf1, 0xc, 0xf0,
/* U+6A "j" */
0xc, 0x0, 0x0, 0xff, 0xf0, 0xf, 0x0, 0xf0,
0xf, 0x0, 0xf1, 0x2f, 0xef, 0x80,
/* U+6B "k" */
0xf0, 0xf, 0x0, 0xf0, 0x3f, 0x66, 0xff, 0x2f,
0x38, 0xf0, 0x40,
/* U+6C "l" */
0xff, 0x0, 0xf0, 0xf, 0x0, 0xf0, 0xf, 0x0,
0xf1, 0xc, 0xf0,
/* U+6D "m" */
0xef, 0xdb, 0xf1, 0xff, 0xf0, 0xff, 0xf0, 0xf,
0xf0, 0xf,
/* U+6E "n" */
0xef, 0x8f, 0x1f, 0xf0, 0xff, 0xf, 0xf0, 0xf0,
/* U+6F "o" */
0x6f, 0x6e, 0x4e, 0xf0, 0xfe, 0x4e, 0x6f, 0x60,
/* U+70 "p" */
0xef, 0x6f, 0x2e, 0xf0, 0xff, 0x3f, 0xff, 0x8f,
0x0, 0xf0, 0x0,
/* U+71 "q" */
0x6f, 0xde, 0x2f, 0xf0, 0xff, 0x3f, 0x8f, 0xf0,
0xf, 0x0, 0xf0,
/* U+72 "r" */
0xdf, 0xff, 0x10, 0xf0, 0xf, 0x0, 0xf0, 0x0,
/* U+73 "s" */
0x9f, 0xef, 0x30, 0x8f, 0x80, 0x3f, 0xef, 0xa0,
/* U+74 "t" */
0xf, 0xf, 0xff, 0xf, 0x0, 0xf0, 0xf, 0x10,
0xcf,
/* U+75 "u" */
0xf0, 0xff, 0xf, 0xf0, 0xff, 0x2f, 0x8f, 0xe0,
/* U+76 "v" */
0xf3, 0x2f, 0xc6, 0x5b, 0x8a, 0x98, 0x4d, 0xe3,
0xf, 0xf0,
/* U+77 "w" */
0xf0, 0x0, 0xfd, 0x6f, 0x6d, 0xcb, 0xfa, 0xc8,
0xd9, 0xe8, 0x6f, 0x8f, 0x50,
/* U+78 "x" */
0xb8, 0x6b, 0x1d, 0xd1, 0x8, 0x90, 0x2e, 0xc4,
0xc6, 0x7b,
/* U+79 "y" */
0xe4, 0x3, 0xea, 0x80, 0x9a, 0x5c, 0xe, 0x50,
0xf6, 0xf0, 0xa, 0xf9, 0x0, 0x8f, 0x20, 0xff,
0x60, 0x0,
/* U+7A "z" */
0xff, 0xf0, 0x9b, 0x3f, 0x2c, 0xa0, 0xff, 0xf0,
/* U+7B "{" */
0x9, 0xff, 0xf, 0x10, 0xf, 0x0, 0x1f, 0x0,
0xf9, 0x0, 0x1f, 0x0, 0xf, 0x0, 0xf, 0x10,
0x9, 0xff,
/* U+7C "|" */
0xff, 0xff, 0xff, 0xff, 0xf0,
/* U+7D "}" */
0xff, 0x80, 0x1, 0xf0, 0x0, 0xf0, 0x0, 0xf1,
0x0, 0x9f, 0x0, 0xf1, 0x0, 0xf0, 0x1, 0xf0,
0xff, 0x90,
/* U+7E "~" */
0x9b, 0x3d, 0xe3, 0xd9
};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 80, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 80, .box_h = 6, .box_w = 1, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 3, .adv_w = 80, .box_h = 3, .box_w = 3, .ofs_x = 1, .ofs_y = 4},
{.bitmap_index = 8, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 20, .adv_w = 80, .box_h = 8, .box_w = 3, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 32, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 44, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 56, .adv_w = 80, .box_h = 3, .box_w = 1, .ofs_x = 2, .ofs_y = 4},
{.bitmap_index = 58, .adv_w = 80, .box_h = 8, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 70, .adv_w = 80, .box_h = 8, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 82, .adv_w = 80, .box_h = 4, .box_w = 5, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 92, .adv_w = 80, .box_h = 5, .box_w = 5, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 105, .adv_w = 80, .box_h = 2, .box_w = 2, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 107, .adv_w = 80, .box_h = 1, .box_w = 2, .ofs_x = 1, .ofs_y = 2},
{.bitmap_index = 108, .adv_w = 80, .box_h = 1, .box_w = 1, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 109, .adv_w = 80, .box_h = 9, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 123, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 135, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 144, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 153, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 162, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 174, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 186, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 198, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 207, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 216, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 225, .adv_w = 80, .box_h = 4, .box_w = 1, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 227, .adv_w = 80, .box_h = 5, .box_w = 2, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 232, .adv_w = 80, .box_h = 4, .box_w = 4, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 240, .adv_w = 80, .box_h = 3, .box_w = 4, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 246, .adv_w = 80, .box_h = 4, .box_w = 4, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 254, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 266, .adv_w = 80, .box_h = 7, .box_w = 4, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 280, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 292, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 304, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 316, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 328, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 340, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 352, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 364, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 376, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 385, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 394, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 406, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 418, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 430, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 442, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 454, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 466, .adv_w = 80, .box_h = 8, .box_w = 4, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 482, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 494, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 506, .adv_w = 80, .box_h = 6, .box_w = 5, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 521, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 533, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 545, .adv_w = 80, .box_h = 6, .box_w = 5, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 560, .adv_w = 80, .box_h = 6, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 572, .adv_w = 80, .box_h = 6, .box_w = 5, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 587, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 596, .adv_w = 80, .box_h = 8, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 608, .adv_w = 80, .box_h = 9, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 622, .adv_w = 80, .box_h = 8, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 634, .adv_w = 80, .box_h = 3, .box_w = 5, .ofs_x = 0, .ofs_y = 3},
{.bitmap_index = 642, .adv_w = 80, .box_h = 1, .box_w = 5, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 645, .adv_w = 80, .box_h = 2, .box_w = 2, .ofs_x = 1, .ofs_y = 5},
{.bitmap_index = 647, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 655, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 666, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 674, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 685, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 693, .adv_w = 80, .box_h = 7, .box_w = 4, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 707, .adv_w = 80, .box_h = 7, .box_w = 4, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 721, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 732, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 743, .adv_w = 80, .box_h = 9, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 757, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 768, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 779, .adv_w = 80, .box_h = 5, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 789, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 797, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 805, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 816, .adv_w = 80, .box_h = 7, .box_w = 3, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 827, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 835, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 843, .adv_w = 80, .box_h = 6, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 852, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 860, .adv_w = 80, .box_h = 5, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 870, .adv_w = 80, .box_h = 5, .box_w = 5, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 883, .adv_w = 80, .box_h = 5, .box_w = 4, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 893, .adv_w = 80, .box_h = 7, .box_w = 5, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 911, .adv_w = 80, .box_h = 5, .box_w = 3, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 919, .adv_w = 80, .box_h = 9, .box_w = 4, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 937, .adv_w = 80, .box_h = 9, .box_w = 1, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 942, .adv_w = 80, .box_h = 9, .box_w = 4, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 960, .adv_w = 80, .box_h = 2, .box_w = 4, .ofs_x = 0, .ofs_y = 2}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
.range_start = 32, .range_length = 95, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY,
.glyph_id_start = 1, .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0
}
};
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
/*Store all the custom data of the font*/
static lv_font_fmt_txt_dsc_t font_dsc = {
.glyph_bitmap = gylph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.cmap_num = 1,
.bpp = 4,
.kern_scale = 0,
.kern_dsc = NULL,
.kern_classes = 0,
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
const lv_font_t ubuntu_mono6 = {
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
// .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
// .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.line_height = 10, /*The maximum line height required by the font*/
.base_line = 2, /*Baseline measured from the bottom of the line*/
};
#endif /*#if UBUNTU_MONO*/

Wyświetl plik

@ -0,0 +1,713 @@
#include "font.h"
/*******************************************************************************
* Size: 16 px
* Bpp: 4
* Opts:
******************************************************************************/
#ifndef UBUNTU_MONO
#define UBUNTU_MONO 1
#endif
#if UBUNTU_MONO
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static const uint8_t gylph_bitmap[] = {
/* U+20 " " */
/* U+21 "!" */
0xff, 0xff, 0xff, 0xf9, 0xc,
/* U+22 "\"" */
0xf0, 0xff, 0xf, 0xf0, 0xf9, 0x9,
/* U+23 "#" */
0x0, 0xf0, 0xf, 0x0, 0x3d, 0x3, 0xd0, 0x4,
0xc0, 0x4c, 0xf, 0xff, 0xff, 0xff, 0x8, 0x80,
0x88, 0x0, 0x88, 0x8, 0x80, 0xff, 0xff, 0xff,
0xf0, 0xc4, 0xc, 0x40, 0xd, 0x30, 0xd3, 0x0,
0xf0, 0xf, 0x0,
/* U+24 "$" */
0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x3c, 0xff,
0xb0, 0xe6, 0x0, 0x0, 0xf1, 0x0, 0x0, 0xac,
0x40, 0x0, 0x6, 0xde, 0x70, 0x0, 0x2, 0xca,
0x0, 0x0, 0x1f, 0xb4, 0x0, 0x7c, 0xaf, 0xfd,
0x91, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
/* U+25 "%" */
0x4e, 0xe4, 0x7, 0xce, 0x44, 0xe1, 0xe2, 0xf0,
0xf, 0xa8, 0xe, 0x44, 0xff, 0x10, 0x4f, 0xff,
0x60, 0x0, 0x6, 0xee, 0xe4, 0x1, 0xef, 0x44,
0xe0, 0x8a, 0xf0, 0xf, 0x2f, 0x1e, 0x44, 0xec,
0x70, 0x5f, 0xf4,
/* U+26 "&" */
0x4, 0xde, 0x60, 0x0, 0xe5, 0x3f, 0x0, 0xf,
0x0, 0xf0, 0x0, 0xd4, 0x7a, 0x0, 0x5, 0xef,
0x20, 0x1, 0xbe, 0xa0, 0xf0, 0xa8, 0xa, 0x9f,
0xf, 0x0, 0xa, 0xc0, 0xd8, 0x13, 0xcf, 0x33,
0xcf, 0xf9, 0x5c,
/* U+27 "'" */
0xff, 0xfa,
/* U+28 "(" */
0x0, 0x58, 0x4, 0xf6, 0x1d, 0x70, 0x6c, 0x0,
0xb6, 0x0, 0xf2, 0x0, 0xf0, 0x0, 0xf1, 0x0,
0xb5, 0x0, 0x6b, 0x0, 0x1e, 0x70, 0x4, 0xf6,
0x0, 0x59,
/* U+29 ")" */
0x94, 0x0, 0x6f, 0x40, 0x7, 0xd1, 0x0, 0xc6,
0x0, 0x5b, 0x0, 0x1e, 0x0, 0xf, 0x0, 0x2f,
0x0, 0x6c, 0x0, 0xc6, 0x7, 0xe1, 0x6f, 0x40,
0xa6, 0x0,
/* U+2A "*" */
0x0, 0xf0, 0xb, 0x48, 0x4a, 0x69, 0xf9, 0x60,
0xba, 0xa0, 0x9e, 0xe, 0x96, 0x80, 0x86,
/* U+2B "+" */
0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf, 0x0, 0xf, 0xff, 0xff, 0xff, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0,
0x0,
/* U+2C "," */
0xd, 0x2d, 0xf4,
/* U+2D "-" */
0xff, 0xff,
/* U+2E "." */
0xc0,
/* U+2F "/" */
0x0, 0x0, 0x3d, 0x0, 0x0, 0x97, 0x0, 0x0,
0xe2, 0x0, 0x4, 0xc0, 0x0, 0xa, 0x60, 0x0,
0xe, 0x10, 0x0, 0x5b, 0x0, 0x0, 0xb5, 0x0,
0x1, 0xe0, 0x0, 0x6, 0xa0, 0x0, 0xc, 0x40,
0x0, 0x2e, 0x0, 0x0, 0x79, 0x0, 0x0, 0xd3,
0x0, 0x0,
/* U+30 "0" */
0x6, 0xdd, 0x60, 0x4d, 0x22, 0xd4, 0xa5, 0x0,
0x5a, 0xe1, 0x0, 0x1d, 0xf0, 0xdc, 0xf, 0xf0,
0xdd, 0xf, 0xe1, 0x0, 0x1d, 0xa5, 0x0, 0x5a,
0x4d, 0x22, 0xc4, 0x6, 0xee, 0x60,
/* U+31 "1" */
0x3, 0xe0, 0x4, 0xef, 0x0, 0xc5, 0xf0, 0x0,
0xf, 0x0, 0x0, 0xf0, 0x0, 0xf, 0x0, 0x0,
0xf0, 0x0, 0xf, 0x0, 0x0, 0xf0, 0xf, 0xff,
0xff,
/* U+32 "2" */
0x4b, 0xfe, 0x91, 0xa7, 0x10, 0x8b, 0x0, 0x0,
0xf, 0x0, 0x0, 0x4e, 0x0, 0x3, 0xe4, 0x0,
0x3e, 0x60, 0x6, 0xf4, 0x0, 0x3f, 0x30, 0x0,
0xc3, 0x0, 0x0, 0xff, 0xff, 0xff,
/* U+33 "3" */
0x8e, 0xff, 0xa3, 0x0, 0x1, 0x8b, 0x0, 0x0,
0xf, 0x0, 0x1, 0x9c, 0x0, 0xff, 0xf4, 0x0,
0x2, 0xbb, 0x0, 0x0, 0x1f, 0x0, 0x0, 0x1f,
0x0, 0x2, 0x9a, 0xaf, 0xfe, 0x91,
/* U+34 "4" */
0x0, 0xa, 0xf0, 0x0, 0x7f, 0xf0, 0x2, 0xe4,
0xf0, 0xb, 0xa0, 0xf0, 0x4f, 0x10, 0xf0, 0xc8,
0x0, 0xf0, 0xff, 0xff, 0xff, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
/* U+35 "5" */
0xc, 0xff, 0xff, 0xc, 0x40, 0x0, 0xc, 0x20,
0x0, 0xc, 0x0, 0x0, 0xf, 0xeb, 0x50, 0x0,
0x15, 0xd8, 0x0, 0x0, 0x2e, 0x0, 0x0, 0x1f,
0x0, 0x2, 0x9a, 0xbf, 0xff, 0xa1,
/* U+36 "6" */
0x0, 0x6c, 0xf0, 0xa, 0xd5, 0x0, 0x4e, 0x10,
0x0, 0xb6, 0x0, 0x0, 0xfc, 0xff, 0x91, 0xf3,
0x0, 0xab, 0xf0, 0x0, 0xf, 0xc3, 0x0, 0x1f,
0x6c, 0x11, 0x9a, 0x9, 0xef, 0xa1,
/* U+37 "7" */
0xff, 0xff, 0xff, 0x0, 0x0, 0x69, 0x0, 0x3,
0xd0, 0x0, 0xc, 0x30, 0x0, 0x6a, 0x0, 0x0,
0xc3, 0x0, 0x3, 0xd0, 0x0, 0x8, 0x80, 0x0,
0xc, 0x40, 0x0, 0xf, 0x0, 0x0,
/* U+38 "8" */
0x19, 0xff, 0xa1, 0xc9, 0x11, 0xab, 0xf0, 0x0,
0xf, 0xc6, 0x0, 0x7c, 0x3e, 0xa9, 0xc1, 0x5f,
0x6a, 0xe3, 0xe4, 0x0, 0x5c, 0xf0, 0x0, 0xf,
0xc8, 0x11, 0x8b, 0x2b, 0xff, 0xb1,
/* U+39 "9" */
0x19, 0xfd, 0x70, 0xaa, 0x12, 0xd6, 0xf1, 0x0,
0x3c, 0xf0, 0x0, 0xf, 0xb9, 0x0, 0x3f, 0x1b,
0xff, 0xdd, 0x0, 0x0, 0x7b, 0x0, 0x1, 0xc4,
0x0, 0x5b, 0xa0, 0xf, 0xc7, 0x0,
/* U+3A ":" */
0xc0, 0x0, 0xc,
/* U+3B ";" */
0xc, 0x0, 0x0, 0x0, 0x0, 0xd, 0x2d, 0xf4,
/* U+3C "<" */
0x0, 0x0, 0x6a, 0x0, 0x6d, 0xd4, 0x6d, 0xe6,
0x0, 0xfd, 0x20, 0x0, 0x6e, 0xd5, 0x0, 0x0,
0x6e, 0xc4, 0x0, 0x0, 0x6b,
/* U+3D "=" */
0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xff, 0xff, 0xff,
/* U+3E ">" */
0xb5, 0x0, 0x0, 0x4d, 0xd5, 0x0, 0x0, 0x6e,
0xd5, 0x0, 0x2, 0xdf, 0x0, 0x6d, 0xe6, 0x4c,
0xe6, 0x0, 0xb6, 0x0, 0x0,
/* U+3F "?" */
0xcf, 0xd3, 0x0, 0x7c, 0x0, 0xf, 0x0, 0x2f,
0x0, 0xb8, 0x5, 0xe1, 0xd, 0x60, 0xf, 0x0,
0x0, 0x0, 0xc, 0x0,
/* U+40 "@" */
0x3, 0xdf, 0xa1, 0x1e, 0x40, 0x8a, 0x78, 0x0,
0x1e, 0xc4, 0x1b, 0xff, 0xf0, 0xb7, 0xf, 0xf0,
0xf0, 0xf, 0xf0, 0xf0, 0xf, 0xf2, 0xb7, 0xf,
0xb5, 0x3e, 0xfe, 0x6a, 0x0, 0x0, 0xd, 0x60,
0x20, 0x1, 0xcf, 0xf0,
/* U+41 "A" */
0x0, 0x6f, 0x60, 0x0, 0xb, 0xcb, 0x0, 0x1,
0xf3, 0xf1, 0x0, 0x5d, 0xd, 0x50, 0xa, 0x90,
0x89, 0x0, 0xe4, 0x4, 0xd0, 0x2f, 0xff, 0xff,
0x26, 0xc0, 0x0, 0xb6, 0xa7, 0x0, 0x7, 0xae,
0x30, 0x0, 0x3e,
/* U+42 "B" */
0xef, 0xff, 0xa2, 0xf0, 0x1, 0x6c, 0xf0, 0x0,
0xf, 0xf0, 0x2, 0x6c, 0xff, 0xff, 0xf4, 0xf0,
0x2, 0x8c, 0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf,
0xf0, 0x2, 0x79, 0xef, 0xfd, 0x81,
/* U+43 "C" */
0x3, 0xaf, 0xe7, 0x1e, 0x60, 0x4a, 0x98, 0x0,
0x0, 0xe3, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xe3, 0x0, 0x0, 0xa8, 0x0, 0x0,
0x2f, 0x50, 0x29, 0x3, 0xdf, 0xf9,
/* U+44 "D" */
0xef, 0xfa, 0x30, 0xf0, 0x28, 0xf2, 0xf0, 0x0,
0x8a, 0xf0, 0x0, 0x4d, 0xf0, 0x0, 0xf, 0xf0,
0x0, 0xf, 0xf0, 0x0, 0x3e, 0xf0, 0x0, 0x8a,
0xf0, 0x16, 0xf2, 0xef, 0xfb, 0x30,
/* U+45 "E" */
0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xff, 0xff, 0xff,
/* U+46 "F" */
0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
/* U+47 "G" */
0x3, 0xbf, 0xe8, 0x1e, 0x70, 0x49, 0x98, 0x0,
0x0, 0xd3, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0xf, 0xe3, 0x0, 0xf, 0xa8, 0x0, 0xf,
0x2f, 0x60, 0x1f, 0x3, 0xdf, 0xfb,
/* U+48 "H" */
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0,
0xf, 0xf0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0,
0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf,
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf,
/* U+49 "I" */
0xff, 0xff, 0xf0, 0xf, 0x0, 0x0, 0xf0, 0x0,
0xf, 0x0, 0x0, 0xf0, 0x0, 0xf, 0x0, 0x0,
0xf0, 0x0, 0xf, 0x0, 0x0, 0xf0, 0xf, 0xff,
0xff,
/* U+4A "J" */
0xf, 0xff, 0xff, 0x0, 0x0, 0xf, 0x0, 0x0,
0xf, 0x0, 0x0, 0xf, 0x0, 0x0, 0xf, 0x0,
0x0, 0xf, 0x0, 0x0, 0xf, 0x0, 0x0, 0x2f,
0x95, 0x1, 0xaa, 0x8e, 0xff, 0xa1,
/* U+4B "K" */
0xf0, 0x0, 0xca, 0xf0, 0x8, 0xd1, 0xf0, 0x6f,
0x20, 0xf4, 0xf3, 0x0, 0xfe, 0x40, 0x0, 0xf7,
0xd1, 0x0, 0xf0, 0x7b, 0x0, 0xf0, 0xb, 0x90,
0xf0, 0x1, 0xf4, 0xf0, 0x0, 0x8b,
/* U+4C "L" */
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xff, 0xff, 0xff,
/* U+4D "M" */
0x4d, 0x0, 0xe5, 0x8f, 0x22, 0xf8, 0x8e, 0x66,
0xe8, 0xa9, 0xab, 0x7c, 0xc1, 0xfe, 0x1c, 0xc0,
0xdd, 0xc, 0xc0, 0x0, 0xc, 0xf0, 0x0, 0xf,
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf,
/* U+4E "N" */
0xf6, 0x0, 0xf, 0xfe, 0x10, 0xf, 0xfc, 0x80,
0xf, 0xf2, 0xf2, 0xf, 0xf0, 0xaa, 0xf, 0xf0,
0x2f, 0x1f, 0xf0, 0xa, 0x8f, 0xf0, 0x2, 0xef,
0xf0, 0x0, 0xaf, 0xf0, 0x0, 0x4f,
/* U+4F "O" */
0x8, 0xee, 0x70, 0x5d, 0x22, 0xe4, 0xb6, 0x0,
0x6b, 0xf1, 0x0, 0x1e, 0xf0, 0x0, 0xf, 0xf0,
0x0, 0xf, 0xf1, 0x0, 0x2e, 0xb6, 0x0, 0x6b,
0x5d, 0x22, 0xd4, 0x8, 0xff, 0x80,
/* U+50 "P" */
0xef, 0xfe, 0x81, 0xf0, 0x4, 0xca, 0xf0, 0x0,
0x3f, 0xf0, 0x0, 0x1e, 0xf0, 0x2, 0xa9, 0xff,
0xfd, 0x80, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
/* U+51 "Q" */
0x8, 0xee, 0x70, 0x5d, 0x22, 0xe4, 0xb6, 0x0,
0x6b, 0xf1, 0x0, 0x1e, 0xf0, 0x0, 0xf, 0xf0,
0x0, 0xf, 0xf1, 0x0, 0x1e, 0xc5, 0x0, 0x6a,
0x7c, 0x22, 0xd4, 0xb, 0xfe, 0x50, 0x0, 0xc7,
0x30, 0x0, 0x17, 0xce,
/* U+52 "R" */
0xef, 0xfd, 0x71, 0xf, 0x0, 0x2a, 0x90, 0xf0,
0x0, 0x1f, 0xf, 0x0, 0x1, 0xf0, 0xf0, 0x2,
0x98, 0xf, 0xff, 0xf9, 0x0, 0xf0, 0x9, 0x90,
0xf, 0x0, 0xc, 0x60, 0xf0, 0x0, 0x2e, 0x2f,
0x0, 0x0, 0x8b,
/* U+53 "S" */
0x19, 0xef, 0xd8, 0xb8, 0x10, 0x6a, 0xf0, 0x0,
0x0, 0xe7, 0x0, 0x0, 0x3d, 0xd5, 0x10, 0x0,
0x4a, 0xf3, 0x0, 0x0, 0x6e, 0x0, 0x0, 0xf,
0xb4, 0x1, 0x7b, 0x8e, 0xff, 0xa1,
/* U+54 "T" */
0xff, 0xff, 0xff, 0xf0, 0x0, 0xf0, 0x0, 0x0,
0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf,
0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0, 0x0,
0x0, 0xf0, 0x0,
/* U+55 "U" */
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0,
0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0,
0x0, 0xf, 0xf0, 0x0, 0xf, 0xf2, 0x0, 0x2f,
0xa9, 0x11, 0x9a, 0x1a, 0xff, 0xa1,
/* U+56 "V" */
0xe3, 0x0, 0x2, 0xeb, 0x70, 0x0, 0x4b, 0x7b,
0x0, 0x8, 0x72, 0xf0, 0x0, 0xc2, 0xe, 0x50,
0xd, 0x0, 0xaa, 0x2, 0xa0, 0x5, 0xe0, 0x65,
0x0, 0x1f, 0x5a, 0x10, 0x0, 0xbb, 0x90, 0x0,
0x7, 0xf6, 0x0,
/* U+57 "W" */
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0,
0xf, 0xf0, 0x0, 0xf, 0xf0, 0xdc, 0xf, 0xf2,
0xee, 0x2f, 0xf7, 0xaa, 0x7f, 0xfc, 0x55, 0xcf,
0xff, 0x0, 0xff, 0xfa, 0x0, 0xaf,
/* U+58 "X" */
0xc8, 0x0, 0x7, 0xc2, 0xf2, 0x2, 0xe2, 0xa,
0xa0, 0xc9, 0x0, 0x1f, 0x9f, 0x10, 0x0, 0x9f,
0x70, 0x0, 0xd, 0xfb, 0x0, 0x6, 0xe2, 0xf6,
0x0, 0xe6, 0x8, 0xd0, 0x6e, 0x0, 0x1f, 0x6d,
0x60, 0x0, 0x8c,
/* U+59 "Y" */
0xd5, 0x0, 0x5, 0xd6, 0xb0, 0x0, 0xc6, 0x1f,
0x20, 0x4f, 0x0, 0x8a, 0xc, 0x80, 0x1, 0xf8,
0xe1, 0x0, 0x7, 0xf6, 0x0, 0x0, 0xf, 0x0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0, 0x0,
0x0, 0xf0, 0x0,
/* U+5A "Z" */
0xff, 0xff, 0xff, 0x0, 0x0, 0x89, 0x0, 0x3,
0xf1, 0x0, 0xd, 0x60, 0x0, 0x7c, 0x0, 0x1,
0xe3, 0x0, 0x9, 0xa0, 0x0, 0x2f, 0x20, 0x0,
0xa8, 0x0, 0x0, 0xff, 0xff, 0xff,
/* U+5B "[" */
0xff, 0xff, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0,
0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0,
0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0,
0xff, 0xff,
/* U+5C "\\" */
0xd3, 0x0, 0x0, 0x79, 0x0, 0x0, 0x2e, 0x0,
0x0, 0xc, 0x40, 0x0, 0x6, 0xa0, 0x0, 0x1,
0xe0, 0x0, 0x0, 0xb5, 0x0, 0x0, 0x6b, 0x0,
0x0, 0xe, 0x10, 0x0, 0xa, 0x60, 0x0, 0x5,
0xc0, 0x0, 0x0, 0xe2, 0x0, 0x0, 0x97, 0x0,
0x0, 0x4d,
/* U+5D "]" */
0xff, 0xff, 0x0, 0xf, 0x0, 0xf, 0x0, 0xf,
0x0, 0xf, 0x0, 0xf, 0x0, 0xf, 0x0, 0xf,
0x0, 0xf, 0x0, 0xf, 0x0, 0xf, 0x0, 0xf,
0xff, 0xff,
/* U+5E "^" */
0x0, 0x7f, 0x70, 0x0, 0x2e, 0xce, 0x20, 0xc,
0xc0, 0xcb, 0x5, 0xf1, 0x1, 0xf5, 0xb5, 0x0,
0x5, 0xb0,
/* U+5F "_" */
0xff, 0xff, 0xff, 0xff,
/* U+60 "`" */
0xa6, 0x6, 0xf3, 0x3, 0xb0,
/* U+61 "a" */
0xd, 0xff, 0xc3, 0x0, 0x0, 0x8d, 0x0, 0x0,
0xf, 0x3a, 0xff, 0xef, 0xf6, 0x0, 0xf, 0xf5,
0x0, 0xf, 0x3d, 0xff, 0xfc,
/* U+62 "b" */
0xe0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xfb, 0xfe, 0x70, 0xf5,
0x2, 0xc8, 0xf0, 0x0, 0x2e, 0xf0, 0x0, 0xf,
0xf0, 0x0, 0x4e, 0xf1, 0x4, 0xc8, 0xcf, 0xfe,
0x80,
/* U+63 "c" */
0x6, 0xcf, 0xfc, 0x7d, 0x40, 0x0, 0xe3, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xe2, 0x0, 0x0, 0x8c,
0x30, 0x0, 0x6, 0xdf, 0xfd,
/* U+64 "d" */
0x0, 0x0, 0xe, 0x0, 0x0, 0xf, 0x0, 0x0,
0xf, 0x0, 0x0, 0xf, 0x8, 0xef, 0xcf, 0x8c,
0x20, 0x5f, 0xe2, 0x0, 0xf, 0xf0, 0x0, 0xf,
0xe3, 0x0, 0xf, 0x8c, 0x40, 0xf, 0x8, 0xef,
0xfc,
/* U+65 "e" */
0x8, 0xee, 0x91, 0x8d, 0x21, 0xaa, 0xe2, 0x0,
0x1e, 0xff, 0xff, 0xff, 0xe2, 0x0, 0x0, 0x89,
0x10, 0x0, 0x9, 0xff, 0xe0,
/* U+66 "f" */
0x0, 0x1a, 0xff, 0xb0, 0xa, 0x90, 0x0, 0x0,
0xf1, 0x0, 0x0, 0xf, 0x0, 0x0, 0xff, 0xff,
0xff, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0,
/* U+67 "g" */
0x8, 0xef, 0xfb, 0x8d, 0x30, 0x1f, 0xe3, 0x0,
0xf, 0xf0, 0x0, 0xf, 0xe2, 0x0, 0xf, 0x8b,
0x20, 0x5f, 0x9, 0xff, 0xdf, 0x0, 0x0, 0x1e,
0x0, 0x1, 0x99, 0xbf, 0xfe, 0x81,
/* U+68 "h" */
0xe0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xfd, 0xfe, 0x91, 0xf2,
0x1, 0xab, 0xf0, 0x0, 0x1f, 0xf0, 0x0, 0xf,
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0,
0xf,
/* U+69 "i" */
0x0, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xe5, 0x0,
0x0, 0x5f, 0xfd,
/* U+6A "j" */
0x0, 0xc, 0x0, 0x0, 0x0, 0xf, 0xff, 0xf0,
0x0, 0xf, 0x0, 0x0, 0xf0, 0x0, 0xf, 0x0,
0x0, 0xf0, 0x0, 0xf, 0x0, 0x0, 0xf0, 0x0,
0xf, 0x42, 0x7, 0xca, 0xff, 0xd3,
/* U+6B "k" */
0xe0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xf0, 0x3, 0xe6, 0xf0,
0x4e, 0x60, 0xf7, 0xe3, 0x0, 0xff, 0x70, 0x0,
0xf1, 0xd9, 0x0, 0xf0, 0x1c, 0x90, 0xf0, 0x1,
0xd9,
/* U+6C "l" */
0xff, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0,
0x0, 0xf0, 0x0, 0x0, 0xd4, 0x0, 0x0, 0x5e,
0xfd,
/* U+6D "m" */
0xdf, 0xea, 0xf7, 0xf0, 0x3f, 0x3f, 0xf0, 0xf,
0xf, 0xf0, 0xf, 0xf, 0xf0, 0x0, 0xf, 0xf0,
0x0, 0xf, 0xf0, 0x0, 0xf,
/* U+6E "n" */
0xce, 0xfe, 0x91, 0xf1, 0x1, 0xab, 0xf0, 0x0,
0x1f, 0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0,
0x0, 0xf, 0xf0, 0x0, 0xf,
/* U+6F "o" */
0x9, 0xee, 0x80, 0x8c, 0x22, 0xc8, 0xe2, 0x0,
0x2e, 0xf0, 0x0, 0xf, 0xe2, 0x0, 0x2e, 0x8b,
0x22, 0xb8, 0x9, 0xff, 0x90,
/* U+70 "p" */
0xcf, 0xfd, 0x70, 0xf1, 0x4, 0xd8, 0xf0, 0x0,
0x4e, 0xf0, 0x0, 0xf, 0xf0, 0x0, 0x2e, 0xf4,
0x2, 0xb8, 0xfd, 0xff, 0x80, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
/* U+71 "q" */
0x8, 0xdf, 0xfb, 0x8d, 0x40, 0xf, 0xe4, 0x0,
0xf, 0xf0, 0x0, 0xf, 0xe2, 0x0, 0xf, 0x8c,
0x20, 0x4f, 0x8, 0xff, 0xdf, 0x0, 0x0, 0xf,
0x0, 0x0, 0xf, 0x0, 0x0, 0xf,
/* U+72 "r" */
0xad, 0xff, 0xdf, 0x30, 0x0, 0xf0, 0x0, 0xf,
0x0, 0x0, 0xf0, 0x0, 0xf, 0x0, 0x0, 0xf0,
0x0, 0x0,
/* U+73 "s" */
0x3a, 0xff, 0xfc, 0xe7, 0x10, 0x0, 0xd9, 0x30,
0x0, 0x18, 0xdd, 0x71, 0x0, 0x2, 0x8d, 0xb5,
0x0, 0x6e, 0xae, 0xff, 0xc3,
/* U+74 "t" */
0x0, 0xe0, 0x0, 0x0, 0xf0, 0x0, 0xff, 0xff,
0xff, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xe4, 0x0,
0x0, 0x6f, 0xfd,
/* U+75 "u" */
0xf0, 0x0, 0xf, 0xf0, 0x0, 0xf, 0xf0, 0x0,
0xf, 0xf0, 0x0, 0xf, 0xf1, 0x0, 0xf, 0xb9,
0x10, 0xf, 0x1b, 0xff, 0xfc,
/* U+76 "v" */
0xd5, 0x0, 0x3, 0xd7, 0xa0, 0x0, 0xa7, 0x2f,
0x20, 0x1f, 0x10, 0xa8, 0x8, 0xa0, 0x4, 0xf2,
0xe2, 0x0, 0xc, 0xda, 0x0, 0x0, 0x4f, 0x20,
0x0,
/* U+77 "w" */
0xf0, 0x0, 0x0, 0xfc, 0x30, 0x0, 0x3c, 0xb4,
0x2a, 0x4, 0xb8, 0x88, 0xf4, 0x88, 0x5b, 0xe8,
0xeb, 0x52, 0xfd, 0x9, 0xf2, 0xf, 0x40, 0x1c,
0x0,
/* U+78 "x" */
0xac, 0x0, 0xa, 0xa0, 0xc9, 0x7, 0xd0, 0x1,
0xeb, 0xf1, 0x0, 0x8, 0xfa, 0x0, 0x4, 0xf5,
0xd7, 0x2, 0xe6, 0x4, 0xf3, 0xca, 0x0, 0xb,
0xb0,
/* U+79 "y" */
0xe3, 0x0, 0x3e, 0xa7, 0x0, 0x7a, 0x6c, 0x0,
0xd5, 0x1f, 0x12, 0xf0, 0xb, 0x77, 0xa0, 0x6,
0xde, 0x50, 0x0, 0xfe, 0x0, 0x0, 0xb8, 0x0,
0x3, 0xe2, 0x0, 0xff, 0x60, 0x0,
/* U+7A "z" */
0xff, 0xff, 0xff, 0x0, 0x1, 0xc6, 0x0, 0x1c,
0x60, 0x1, 0xc9, 0x0, 0xa, 0xa0, 0x0, 0x8d,
0x10, 0x0, 0xff, 0xff, 0xff,
/* U+7B "{" */
0x0, 0x3d, 0xff, 0x0, 0xe5, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0, 0x0, 0x0,
0xf0, 0x0, 0x7, 0xd0, 0x0, 0xff, 0x60, 0x0,
0x6, 0xe0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0xf0, 0x0, 0x0, 0xf4, 0x0, 0x0,
0x6e, 0xff,
/* U+7C "|" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* U+7D "}" */
0xff, 0xd3, 0x0, 0x0, 0x5e, 0x0, 0x0, 0xf,
0x0, 0x0, 0xf, 0x0, 0x0, 0xf, 0x0, 0x0,
0xf, 0x0, 0x0, 0xd, 0x60, 0x0, 0x6, 0xff,
0x0, 0xe, 0x50, 0x0, 0xf, 0x0, 0x0, 0xf,
0x0, 0x0, 0xf, 0x0, 0x0, 0x4f, 0x0, 0xff,
0xe5, 0x0,
/* U+7E "~" */
0x6e, 0xe7, 0x24, 0xdd, 0x42, 0x8f, 0xf6
};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 128, .box_h = 0, .box_w = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 128, .box_h = 10, .box_w = 1, .ofs_x = 3, .ofs_y = 0},
{.bitmap_index = 5, .adv_w = 128, .box_h = 4, .box_w = 3, .ofs_x = 2, .ofs_y = 7},
{.bitmap_index = 11, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 46, .adv_w = 128, .box_h = 13, .box_w = 6, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 85, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 120, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 155, .adv_w = 128, .box_h = 4, .box_w = 1, .ofs_x = 3, .ofs_y = 7},
{.bitmap_index = 157, .adv_w = 128, .box_h = 13, .box_w = 4, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 183, .adv_w = 128, .box_h = 13, .box_w = 4, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 209, .adv_w = 128, .box_h = 6, .box_w = 5, .ofs_x = 1, .ofs_y = 4},
{.bitmap_index = 224, .adv_w = 128, .box_h = 7, .box_w = 7, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 249, .adv_w = 128, .box_h = 3, .box_w = 2, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 252, .adv_w = 128, .box_h = 1, .box_w = 4, .ofs_x = 2, .ofs_y = 3},
{.bitmap_index = 254, .adv_w = 128, .box_h = 1, .box_w = 1, .ofs_x = 3, .ofs_y = 0},
{.bitmap_index = 255, .adv_w = 128, .box_h = 14, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 297, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 327, .adv_w = 128, .box_h = 10, .box_w = 5, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 352, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 382, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 412, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 442, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 472, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 502, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 532, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 562, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 592, .adv_w = 128, .box_h = 6, .box_w = 1, .ofs_x = 3, .ofs_y = 0},
{.bitmap_index = 595, .adv_w = 128, .box_h = 8, .box_w = 2, .ofs_x = 2, .ofs_y = -2},
{.bitmap_index = 603, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 1},
{.bitmap_index = 624, .adv_w = 128, .box_h = 4, .box_w = 6, .ofs_x = 1, .ofs_y = 2},
{.bitmap_index = 636, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 1},
{.bitmap_index = 657, .adv_w = 128, .box_h = 10, .box_w = 4, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 677, .adv_w = 128, .box_h = 12, .box_w = 6, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 713, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 748, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 778, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 808, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 838, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 868, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 898, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 928, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 958, .adv_w = 128, .box_h = 10, .box_w = 5, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 983, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1013, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1043, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1073, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1103, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1133, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1163, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1193, .adv_w = 128, .box_h = 12, .box_w = 6, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 1229, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1264, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1294, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1329, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1359, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1394, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1424, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1459, .adv_w = 128, .box_h = 10, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1494, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1524, .adv_w = 128, .box_h = 13, .box_w = 4, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 1550, .adv_w = 128, .box_h = 14, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 1592, .adv_w = 128, .box_h = 13, .box_w = 4, .ofs_x = 2, .ofs_y = -3},
{.bitmap_index = 1618, .adv_w = 128, .box_h = 5, .box_w = 7, .ofs_x = 1, .ofs_y = 5},
{.bitmap_index = 1636, .adv_w = 128, .box_h = 1, .box_w = 8, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 1640, .adv_w = 128, .box_h = 3, .box_w = 3, .ofs_x = 2, .ofs_y = 8},
{.bitmap_index = 1645, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1666, .adv_w = 128, .box_h = 11, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1699, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1720, .adv_w = 128, .box_h = 11, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1753, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1774, .adv_w = 128, .box_h = 11, .box_w = 7, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1813, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 1843, .adv_w = 128, .box_h = 11, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1876, .adv_w = 128, .box_h = 9, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1903, .adv_w = 128, .box_h = 12, .box_w = 5, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 1933, .adv_w = 128, .box_h = 11, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1966, .adv_w = 128, .box_h = 11, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1999, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2020, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2041, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2062, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2092, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2122, .adv_w = 128, .box_h = 7, .box_w = 5, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2140, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2161, .adv_w = 128, .box_h = 9, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2188, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2209, .adv_w = 128, .box_h = 7, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 2234, .adv_w = 128, .box_h = 7, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 2259, .adv_w = 128, .box_h = 7, .box_w = 7, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 2284, .adv_w = 128, .box_h = 10, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2314, .adv_w = 128, .box_h = 7, .box_w = 6, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2335, .adv_w = 128, .box_h = 14, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2377, .adv_w = 128, .box_h = 14, .box_w = 1, .ofs_x = 3, .ofs_y = -3},
{.bitmap_index = 2384, .adv_w = 128, .box_h = 14, .box_w = 6, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 2426, .adv_w = 128, .box_h = 2, .box_w = 7, .ofs_x = 1, .ofs_y = 3}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
.range_start = 32, .range_length = 95, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY,
.glyph_id_start = 1, .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0
}
};
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
/*Store all the custom data of the font*/
static lv_font_fmt_txt_dsc_t font_dsc = {
.glyph_bitmap = gylph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.cmap_num = 1,
.bpp = 4,
.kern_scale = 0,
.kern_dsc = NULL,
.kern_classes = 0,
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
const lv_font_t ubuntu_mono8 = {
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
// .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
// .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.line_height = 15, /*The maximum line height required by the font*/
.base_line = 3, /*Baseline measured from the bottom of the line*/
};
#endif /*#if UBUNTU_MONO*/

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,524 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico.h"
#include "pico/stdlib.h"
#include "pico/scanvideo.h"
#include "pico/scanvideo/composable_scanline.h"
#include "pico/multicore.h"
#include "pico/sync.h"
#include "font.h"
#if PICO_ON_DEVICE
#include "hardware/structs/bus_ctrl.h"
#endif
CU_REGISTER_DEBUG_PINS(frame_gen)
//CU_SELECT_DEBUG_PINS(frame_gen)
typedef bool (*render_scanline_func)(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_test_pattern(struct scanvideo_scanline_buffer *dest, int core);
bool render_scanline_bg(struct scanvideo_scanline_buffer *dest, int core);
#define vga_mode vga_mode_640x480_60
//#define vga_mode vga_mode_320x240_60
//#define vga_mode vga_mode_213x160_60
//#define vga_mode vga_mode_160x120_60
////#define vga_mode vga_mode_tft_800x480_50
//#define vga_mode vga_mode_tft_400x240_50
#define COUNT ((vga_mode.width/8)-1)
// for now we want to see second counter on native and don't need both cores
#if PICO_ON_DEVICE
// todo there is a bug in multithreaded rendering atm
#define RENDER_ON_CORE0
#endif
#define RENDER_ON_CORE1
//#define IRQS_ON_CORE1
render_scanline_func render_scanline = render_scanline_bg;
#define COORD_SHIFT 3
int vspeed = 1 * 1;
int hspeed = 1 << COORD_SHIFT;
int hpos;
int vpos;
static const int input_pin0 = 22;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
//auto_init_mutex(frame_logic_mutex);
struct mutex frame_logic_mutex;
static int left = 0;
static int top = 0;
static int x_sprites = 1;
void go_core1(void (*execute)());
void init_render_state(int core);
// ok this is going to be the beginning of retained mode
//
void render_loop() {
static uint8_t last_input = 0;
static uint32_t last_frame_num = 0;
int core_num = get_core_num();
assert(core_num >= 0 && core_num < 2);
printf("Rendering on core %d\n", core_num);
#if DEBUG_PINS_ENABLED(frame_gen)
if (core_num == 1) {
gpio_init(PICO_DEBUG_PIN_BASE + 1);
gpio_set_dir_out_masked(2 << PICO_DEBUG_PIN_BASE); // steal debug pin 2 for this core
}
#endif
while (true) {
struct scanvideo_scanline_buffer *scanline_buffer = scanvideo_begin_scanline_generation(true);
// if (scanline_buffer->data_used) {
// // validate the previous scanline to make sure noone corrupted it
// validate_scanline(scanline_buffer->data, scanline_buffer->data_used, vga_mode.width, vga_mode.width);
// }
// do any frame related logic
// todo probably a race condition here ... thread dealing with last line of a frame may end
// todo up waiting on the next frame...
mutex_enter_blocking(&frame_logic_mutex);
uint32_t frame_num = scanvideo_frame_number(scanline_buffer->scanline_id);
// note that with multiple cores we may have got here not for the first scanline, however one of the cores will do this logic first before either does the actual generation
if (frame_num != last_frame_num) {
// this could should be during vblank as we try to create the next line
// todo should we ignore if we aren't attempting the next line
last_frame_num = frame_num;
hpos += hspeed;
// if (hpos < 0) {
// hpos = 0;
// hspeed = -hspeed;
// } else if (hpos >= (level0_map_width*8 - vga_mode.width) << COORD_SHIFT) {
// hpos = (level0_map_width*8 - vga_mode.width) << COORD_SHIFT;
// hspeed = -hspeed;
// }
uint8_t new_input = gpio_get(input_pin0);
if (last_input && !new_input) {
static int foo = 1;
foo++;
#if PICO_ON_DEVICE
bus_ctrl_hw->priority = (foo & 1u) << BUSCTRL_BUS_PRIORITY_DMA_R_LSB;
#endif
hpos++;
}
last_input = new_input;
static int bar = 1;
#if PICO_ON_DEVICE
// if (bar >= 800 && bar <= 802)
// bus_ctrl_hw->priority = (bar&1u) << BUSCTRL_BUS_PRIORITY_DMA_R_LSB;
// bar++;
#endif
}
mutex_exit(&frame_logic_mutex);
DEBUG_PINS_SET(frame_gen, core_num ? 2 : 4);
render_scanline(scanline_buffer, core_num);
DEBUG_PINS_CLR(frame_gen, core_num ? 2 : 4);
#if PICO_SCANVIDEO_PLANE_COUNT > 2
assert(false);
#endif
// release the scanline into the wild
scanvideo_end_scanline_generation(scanline_buffer);
// do this outside mutex and scanline generation
}
}
struct semaphore video_setup_complete;
void setup_video() {
scanvideo_setup(&vga_mode);
scanvideo_timing_enable(true);
sem_release(&video_setup_complete);
}
void core1_func() {
#ifdef IRQS_ON_CORE1
setup_video();
#endif
#ifdef RENDER_ON_CORE1
render_loop();
#endif
}
#define TEST_WAIT_FOR_SCANLINE
#ifdef TEST_WAIT_FOR_SCANLINE
volatile uint32_t scanline_color = 0;
#endif
uint8_t pad[65536];
#if PICO_ON_DEVICE
uint32_t *font_raw_pixels;
#else
uint32_t font_raw_pixels[16384];
#endif
#define FRAGMENT_WORDS 4
//#define FRAGMENT_WORDS 5
#define FONT_WIDTH_WORDS FRAGMENT_WORDS
#if FRAGMENT_WORDS == 5
const lv_font_t *font = &ubuntu_mono10;
//const lv_font_t *font = &lcd;
#elif FRAGMENT_WORDS == 4
const lv_font_t *font = &ubuntu_mono8;
#else
const lv_font_t *font = &ubuntu_mono6;
#endif
#define FONT_HEIGHT (font->line_height)
#define FONT_SIZE_WORDS (FONT_HEIGHT * FONT_WIDTH_WORDS)
void build_font() {
uint16_t colors[16];
for (int i = 0; i < count_of(colors); i++) {
colors[i] = PICO_SCANVIDEO_PIXEL_FROM_RGB5(1, 1, 1) * ((i * 3) / 2);
if (i) i != 0x8000;
}
#if PICO_ON_DEVICE
font_raw_pixels = (uint32_t *) calloc(4, font->dsc->cmaps->range_length * FONT_SIZE_WORDS);
#endif
uint32_t *p = font_raw_pixels;
assert(font->line_height == FONT_HEIGHT);
for (int c = 0; c < font->dsc->cmaps->range_length; c++) {
// inefficient but simple
const lv_font_fmt_txt_glyph_dsc_t *g = &font->dsc->glyph_dsc[c + 1];
const uint8_t *b = font->dsc->glyph_bitmap + g->bitmap_index;
int bi = 0;
for (int y = 0; y < FONT_HEIGHT; y++) {
int ey = y - FONT_HEIGHT + font->base_line + g->ofs_y + g->box_h;
for (int x = 0; x < FONT_WIDTH_WORDS * 2; x++) {
uint32_t pixel;
int ex = x - g->ofs_x;
if (ex >= 0 && ex < g->box_w && ey >= 0 && ey < g->box_h) {
pixel = bi & 1 ? colors[b[bi >> 1] & 0xf] : colors[b[bi >> 1] >> 4];
bi++;
} else {
pixel = 0;
}
// printf("%d", !!pixel);
// uint q = 7 - (c%7);
// pixel = (q&4)*0x0f00 + (q&2) * 0x0f0 + (q&1)*0x0f;
// if ((c%16) == 1 || (c%16) == 2) pixel = 0xffff;
if (!(x & 1)) {
*p = pixel;
} else {
*p++ |= pixel << 16;
}
}
if (ey >= 0 && ey < g->box_h) {
for (int x = FONT_WIDTH_WORDS * 2 - g->ofs_x; x < g->box_w; x++) {
bi++;
}
}
// printf("\n");
}
// printf("\n");
}
printf("%p %p\n", p, font_raw_pixels + font->dsc->cmaps->range_length * FONT_SIZE_WORDS);
}
int video_main(void) {
mutex_init(&frame_logic_mutex);
// set 18-22 to RIO for debugging
for (int i = PICO_DEBUG_PIN_BASE; i < 22; ++i)
gpio_init(i);
// gpio_set_function(i, 8);
gpio_init(24);
gpio_init(22);
// just from this core
gpio_set_dir_out_masked(0x01380000);
gpio_set_dir_in_masked(0x00400000);
//gpio_set_function(22, 0);
// debug pin
gpio_put(24, 0);
printf("%d\n", pad[0]);
#if 0
printf("Press button to start\n");
// todo NOTE THAT ON STARTUP RIGHT NOW WITH RESET ISSUES ON FPGA, THIS CURRENTLY DOES NOT STOP!!! if you make last_input static, then it never releases instead :-(
uint8_t last_input = 0;
while (true) {
uint8_t new_input = gpio_get(input_pin0);
if (last_input && !new_input) {
break;
}
last_input = new_input;
yield();
}
#endif
// go for launch (debug pin)
gpio_put(24, 1);
build_font();
sem_init(&video_setup_complete, 0, 1);
#ifndef IRQS_ON_CORE1
setup_video();
#endif
#if PICO_ON_DEVICE
// bus_ctrl_hw->priority = 1u << BUSCTRL_BUS_PRIORITY_DMA_R_LSB;
#endif
init_render_state(0);
#ifdef RENDER_ON_CORE1
init_render_state(1);
#endif
#if defined(RENDER_ON_CORE1) || defined(IRQS_ON_CORE1)
go_core1(core1_func);
#endif
#ifdef RENDER_ON_CORE0
render_loop();
#else
sem_acquire_blocking(&video_setup_complete);
while (true) {
#ifndef TEST_WAIT_FOR_SCANLINE
// Just use vblank to print out a value every second
static int i=0, s=0;
video_wait_for_vblank();
if (++i == 60) {
printf("%d\n", s++);
i = 0;
}
#else
static uint32_t sl = 0;
sl = scanvideo_wait_for_scanline_complete(sl);
scanline_color = (scanline_color + 0x10u) & 0xffu;
#endif
}
#endif
__builtin_unreachable();
}
//struct palette16 *opaque_pi_palette = NULL;
// must not be called concurrently
void init_render_state(int core) {
// todo we should of course have a wide solid color span that overlaps
// todo we can of course also reuse these
}
#if PICO_SCANVIDEO_PLANE1_FRAGMENT_DMA
static __not_in_flash("x") uint16_t beginning_of_line[] = {
// todo we need to be able to shift scanline to absorb these extra pixels
#if FRAGMENT_WORDS == 5
COMPOSABLE_RAW_1P, 0,
#endif
#if FRAGMENT_WORDS >= 4
COMPOSABLE_RAW_1P, 0,
#endif
COMPOSABLE_RAW_1P, 0,
// main run, 2 more black pixels
COMPOSABLE_RAW_RUN, 0,
0/*COUNT * 2 * FRAGMENT_WORDS -3 + 2*/, 0
};
static __not_in_flash("y") uint16_t end_of_line[] = {
#if FRAGMENT_WORDS == 5 || FRAGMENT_WORDS == 3
COMPOSABLE_RAW_1P, 0,
#endif
#if FRAGMENT_WORDS == 3
COMPOSABLE_RAW_1P, 0,
#endif
#if FRAGMENT_WORDS >= 4
COMPOSABLE_RAW_2P, 0,
0, COMPOSABLE_RAW_1P_SKIP_ALIGN,
0, 0,
#endif
COMPOSABLE_EOL_SKIP_ALIGN, 0xffff // eye catcher
};
#endif
bool render_scanline_bg(struct scanvideo_scanline_buffer *dest, int core) {
// 1 + line_num red, then white
uint32_t *buf = dest->data;
size_t buf_length = dest->data_max;
int y = scanvideo_scanline_number(dest->scanline_id) + vpos;
int x = hpos;
//y = (y + frame_number(dest->scanline_id)) % (level0_map_height * 8);
#if !PICO_SCANVIDEO_PLANE1_FRAGMENT_DMA
uint16_t *output = (uint16_t*)buf;
// raw run has an inline first pixel, so we need to handle that here
// todo shift the video mode over by a pixel to account for this
*output++ = COMPOSABLE_RAW_RUN;
*output++ = 0;
#undef COUNT
#define COUNT 10
//(320/FRAGMENT_WORDS)
*output++ = 2 + COUNT * 2 * FRAGMENT_WORDS - 3;
*output++ = 0;
uint32_t *dbase = font_raw_pixels + FONT_WIDTH_WORDS * (y % FONT_HEIGHT);
for(int i=0;i<COUNT;i++) {
int ch = 33 + i;
uint32_t *data = (uint16_t *)(dbase + ch * FONT_HEIGHT * FONT_WIDTH_WORDS);
for(int j=0;j<FRAGMENT_WORDS;j++) {
*((uint32_t*)output) = *data++;
output += 2;
}
}
// todo fix so we don't need whole scanline
*output++ = COMPOSABLE_COLOR_RUN;
*output++ = 0;
*output++ = vga_mode.width - COUNT * 2 * FRAGMENT_WORDS - 2 - 3;
// end of line stuff
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
if (2 & (intptr_t)output) {
// we are unaligned
*output++ = COMPOSABLE_EOL_ALIGN;
} else {
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff; // eye catcher
}
assert(0 == (3u & (intptr_t)output));
assert((uint32_t*)output <= (buf + dest->data_max));
dest->data_used = (uint16_t)(((uint32_t*)output) - buf);
#else
// we handle both ends separately
// static const uint32_t end_of_line[] = {
// COMPOSABLE_RAW_1P | (0u<<16),
// COMPOSABLE_EOL_SKIP_ALIGN | (0xffff << 16) // eye catcher ffff
// };
#undef COUNT
// todo for SOME REASON, 80 is the max we can do without starting to really get bus delays (even with priority)... not sure how this could be
// todo actually it seems it can work, it just mostly starts incorrectly synced!?
#define COUNT MIN(vga_mode.width/(FRAGMENT_WORDS*2)-1, 80)//MAX_SCANLINE_BUFFER_WORDS / 2 - 2)
#undef COUNT
#define COUNT 79
// we need to take up 5 words, since we have fixed width
#if PICO_SCANVIDEO_PLANE1_FIXED_FRAGMENT_DMA
dest->fragment_words = FRAGMENT_WORDS;
#endif
beginning_of_line[FRAGMENT_WORDS * 2 - 2] = COUNT * 2 * FRAGMENT_WORDS - 3 + 2;
assert(FRAGMENT_WORDS * 2 == count_of(beginning_of_line));
assert(FRAGMENT_WORDS * 2 == count_of(end_of_line));
uint32_t *output32 = buf;
#if PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA
*output32++ = FRAGMENT_WORDS;
#endif
*output32++ = host_safe_hw_ptr(beginning_of_line);
uint32_t *dbase = font_raw_pixels + FONT_WIDTH_WORDS * (y % FONT_HEIGHT);
int cmax = font->dsc->cmaps[0].range_length;
int ch = 0;
// __breakpoint();
for (int i = 0; i < COUNT; i++) {
ch++;
if (ch == cmax) ch = 1;
#if PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA
*output32++ = FRAGMENT_WORDS;
#endif
*output32++ = host_safe_hw_ptr(dbase + ch * FONT_HEIGHT * FONT_WIDTH_WORDS);
}
#if PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA
*output32++ = FRAGMENT_WORDS;
#endif
*output32++ = host_safe_hw_ptr(end_of_line);
*output32++ = 0; // end of chain
#if PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA
*output32++ = 0; // end of chain
#endif
assert(0 == (3u & (intptr_t) output32));
assert((uint32_t *) output32 <= (buf + dest->data_max));
dest->data_used = (uint16_t) (output32 -
buf); // todo we don't want to include the off the end data in the "size" for the dma
#endif
// why was this here, it is buf anyway!
// dest->data = buf;
#if PICO_SCANVIDEO_PLANE_COUNT > 1
#if !PICO_SCANVIDEO_PLANE2_VARIABLE_FRAGMENT_DMA
assert(false);
#endif
buf = dest->data2;
output32 = buf;
uint32_t *inline_data = output32 + PICO_SCANVIDEO_MAX_SCANLINE_BUFFER2_WORDS / 2;
output = (uint16_t *)inline_data;
uint32_t *base = (uint32_t *)output;
#define MAKE_SEGMENT \
assert(0 == (3u & (intptr_t)output)); \
*output32++ = (uint32_t*)output - base; \
*output32++ = host_safe_hw_ptr(base); \
base = (uint32_t *)output;
int wibble = (frame_number(dest->scanline_id)>>2)%7;
for(int q = 0; q < x_sprites; q++) {
// nice if we can do two black pixel before
*output++ = COMPOSABLE_RAW_RUN;
*output++ = 0;
*output++ = galaga_tile_data.width + 2 - 3;
*output++ = 0;
MAKE_SEGMENT;
span_offsets = galaga_tile_data.span_offsets + (q+wibble) * galaga_tile_data.height + (y - vpos);//(y%galaga_tile_data.count 7u);
off = span_offsets[0];
data = (uint16_t *) (galaga_tile_data.blob.bytes + off);
*output32++ = galaga_tile_data.width / 2;
*output32++ = host_safe_hw_ptr(data);
}
*output++ = COMPOSABLE_RAW_1P;
*output++ = 0;
*output++ = COMPOSABLE_EOL_SKIP_ALIGN;
*output++ = 0xffff;
MAKE_SEGMENT;
// end of dma chain
*output32++ = 0;
*output32++ = 0;
assert(output32 < inline_data);
assert((uint32_t*)output <= (buf + dest->data2_max));
dest->data2_used = (uint16_t)(output32 - buf); // todo we don't want to include the inline data in the "size" for the dma
#endif
dest->status = SCANLINE_OK;
return true;
}
void go_core1(void (*execute)()) {
multicore_launch_core1(execute);
}
int main(void) {
set_sys_clock_48mhz();
gpio_put(27, 0);
setup_default_uart();
#if !PICO_ON_DEVICE
//#include <math.h>
// for(int i = 0; i<64;i++) {
// printf("%d, ", (int)(0x7f*cos(i*M_PI/32)));
// }
// printf("\n");
#endif
return video_main();
}

Wyświetl plik

@ -0,0 +1,4 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(hello_dormant)
add_subdirectory(hello_sleep)
endif ()

Wyświetl plik

@ -0,0 +1,8 @@
add_executable(hello_dormant
hello_dormant.c
)
target_link_libraries(hello_dormant pico_stdlib hardware_sleep)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_dormant)

Wyświetl plik

@ -0,0 +1,36 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/sleep.h"
int main() {
stdio_init_all();
printf("Hello Dormant!\n");
printf("Switching to XOSC\n");
uart_default_tx_wait_blocking();
// UART will be reconfigured by sleep_run_from_xosc
sleep_run_from_xosc();
printf("Running from XOSC\n");
uart_default_tx_wait_blocking();
printf("XOSC going dormant\n");
uart_default_tx_wait_blocking();
// Go to sleep until we see a high edge on GPIO 10
sleep_goto_dormant_until_edge_high(10);
uint i = 0;
while (1) {
printf("XOSC awake %d\n", i++);
}
return 0;
}

Wyświetl plik

@ -0,0 +1,8 @@
add_executable(hello_sleep
hello_sleep.c
)
target_link_libraries(hello_sleep pico_stdlib hardware_sleep)
# create map/bin/hex file etc.
pico_add_extra_outputs(hello_sleep)

Wyświetl plik

@ -0,0 +1,77 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/sleep.h"
#include "hardware/rtc.h"
static bool awake;
static void sleep_callback(void) {
printf("RTC woke us up\n");
awake = true;
}
static void rtc_sleep(void) {
// Start on Friday 5th of June 2020 15:45:00
datetime_t t = {
.year = 2020,
.month = 06,
.day = 05,
.dotw = 5, // 0 is Sunday, so 5 is Friday
.hour = 15,
.min = 45,
.sec = 00
};
// Alarm 30 seconds later
datetime_t t_alarm = {
.year = 2020,
.month = 06,
.day = 05,
.dotw = 5, // 0 is Sunday, so 5 is Friday
.hour = 15,
.min = 45,
.sec = 10
};
// Start the RTC
rtc_init();
rtc_set_datetime(&t);
printf("Sleeping for 10 seconds\n");
uart_default_tx_wait_blocking();
sleep_goto_sleep_until(&t_alarm, &sleep_callback);
}
int main() {
stdio_init_all();
printf("Hello Sleep!\n");
printf("Switching to XOSC\n");
// Wait for the fifo to be drained so we get reliable output
uart_default_tx_wait_blocking();
// UART will be reconfigured by sleep_run_from_xosc
sleep_run_from_xosc();
printf("Switched to XOSC\n");
awake = false;
rtc_sleep();
// Make sure we don't wake
while (!awake) {
printf("Should be sleeping\n");
}
return 0;
}

Wyświetl plik

@ -0,0 +1,3 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(pio)
endif ()

Wyświetl plik

@ -0,0 +1,8 @@
add_executable(stdio_pio)
pico_generate_pio_header(stdio_pio ${CMAKE_CURRENT_LIST_DIR}/uart_tx.pio)
target_sources(stdio_pio PRIVATE stdio_pio.c)
target_link_libraries(stdio_pio PRIVATE pico_stdlib hardware_pio)
pico_add_extra_outputs(stdio_pio)

Wyświetl plik

@ -0,0 +1,71 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Example of how to attach a custom interface to the stdout plumbing, so that
// printf(), puts() etc will have their output directed there. This example
// uses PIO to add an extra UART output on GPIO 2, which is not normally
// usable for UART TX.
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/stdio/driver.h"
#include "hardware/pio.h"
#include "uart_tx.pio.h"
#define SERIAL_TX_PIN 2
#define SERIAL_BAUD 115200
// Shim function for directing characters to a fixed SM.
PIO print_pio;
uint print_sm;
void pio_out_chars(const char *buf, int len) {
for (int i = 0; i < len; ++i) {
uart_tx_program_putc(print_pio, print_sm, buf[i]);
}
}
// Data structure for registering this function with the stdio plumbing (we
// only provide output here, but stdin can be hooked up in the same way.)
stdio_driver_t stdio_pio = {
.out_chars = pio_out_chars,
#ifdef PICO_STDIO_ENABLE_CRLF_SUPPORT
.crlf_enabled = PICO_STDIO_DEFAULT_CRLF
#endif
};
int main() {
stdio_init_all();
// This text will go to all the regular stdout outputs enabled on this
// build (any/all of UART, USB and semihosting)
printf("PIO stdio example! PIO isn't set up yet.\n");
// Get the state machine ready to print characters
print_pio = pio0;
print_sm = pio_claim_unused_sm(print_pio, true);
uint offset = pio_add_program(print_pio, &uart_tx_program);
uart_tx_program_init(print_pio, print_sm, offset, SERIAL_TX_PIN, SERIAL_BAUD);
while (true) {
// Register the print function with stdio
stdio_set_driver_enabled(&stdio_pio, true);
printf("\n\n1. PIO driver enabled -- this text should go to all outputs.\n");
// Direct stdout *only* to PIO
stdio_filter_driver(&stdio_pio);
printf("2. PIO driver filtered -- this text should go *only* to PIO on GPIO %d\n", SERIAL_TX_PIN);
// Remove filter to send text to all outputs once more
stdio_filter_driver(NULL);
printf("3. Filter removed -- this text should go to all outputs.\n");
stdio_set_driver_enabled(&stdio_pio, false);
printf("4. PIO driver removed -- this text should go only to the standard outputs.\n");
sleep_ms(1000);
}
}

Wyświetl plik

@ -0,0 +1,61 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program uart_tx
.side_set 1 opt
; An 8n1 UART transmit program.
; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
pull side 1 [7] ; Assert stop bit, or stall with line in idle state
set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks
bitloop: ; This loop will run 8 times (8n1 UART)
out pins, 1 ; Shift 1 bit from OSR to the first OUT pin
jmp x-- bitloop [6] ; Each loop iteration is 8 cycles.
% c-sdk {
#include "hardware/clocks.h"
static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
// Tell PIO to initially drive output-high on the selected pin, then map PIO
// onto that pin with the IO muxes.
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_gpio_init(pio, pin_tx);
pio_sm_config c = uart_tx_program_get_default_config(offset);
// OUT shifts to right, no autopull
sm_config_set_out_shift(&c, true, false, 32);
// We are mapping both OUT and side-set to the same pin, because sometimes
// we need to assert user data onto the pin (with OUT) and sometimes
// assert constant values (start/stop bit)
sm_config_set_out_pins(&c, pin_tx, 1);
sm_config_set_sideset_pins(&c, pin_tx);
// We only need TX, so get an 8-deep FIFO!
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
static inline void uart_tx_program_putc(PIO pio, uint sm, char c) {
pio_sm_put_blocking(pio, sm, (uint32_t)c);
}
static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) {
while (*s)
uart_tx_program_putc(pio, sm, *s++);
}
%}