Initial Release
This commit is contained in:
commit
9195b8e21a
|
@ -0,0 +1,3 @@
|
|||
.idea
|
||||
.vscode
|
||||
cmake-*
|
|
@ -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)
|
|
@ -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.
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
add_subdirectory(popcorn)
|
||||
add_subdirectory(usb_sound_card)
|
|
@ -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()
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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*/
|
|
@ -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*/
|
File diff suppressed because it is too large
Load Diff
|
@ -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()
|
|
@ -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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -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.
|
|
@ -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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(sine_wave)
|
|
@ -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 ()
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(usb_host_webserver)
|
|
@ -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()
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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)
|
|
@ -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})
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(hello_reset)
|
|
@ -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 ()
|
|
@ -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[]
|
|
@ -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()
|
|
@ -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()
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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 ()
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
*.bin
|
||||
*.uf2
|
|
@ -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
|
Binary file not shown.
After Width: | Height: | Size: 476 KiB |
Binary file not shown.
After Width: | Height: | Size: 622 KiB |
Binary file not shown.
After Width: | Height: | Size: 526 KiB |
|
@ -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
|
|
@ -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()
|
|
@ -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()
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 ()
|
|
@ -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();
|
||||
}
|
|
@ -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()
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
This `render` library is entirely legacy - it just supports the example `demo1`
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 ()
|
|
@ -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();
|
||||
}
|
|
@ -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)
|
|
@ -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_
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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 ()
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
|
@ -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()
|
|
@ -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
|
|
@ -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*/
|
||||
|
||||
|
|
@ -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*/
|
|
@ -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*/
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
if (NOT PICO_NO_HARDWARE)
|
||||
add_subdirectory(hello_dormant)
|
||||
add_subdirectory(hello_sleep)
|
||||
endif ()
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
if (NOT PICO_NO_HARDWARE)
|
||||
add_subdirectory(pio)
|
||||
endif ()
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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++);
|
||||
}
|
||||
|
||||
%}
|
Loading…
Reference in New Issue