初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "h618_hub75.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
enum {
|
||||
PI_R1 = 1u << 0,
|
||||
PI_G1 = 1u << 1,
|
||||
PI_B1 = 1u << 2,
|
||||
PI_R2 = 1u << 3,
|
||||
PI_G2 = 1u << 4,
|
||||
PI_B2 = 1u << 5,
|
||||
};
|
||||
|
||||
static size_t word_index(unsigned row, unsigned plane, unsigned column) {
|
||||
return ((size_t)row * HUB75_PWM_BITS + plane) * HUB75_WIDTH + column;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
assert(strcmp(hub75_hardware_mapping(), HUB75_HARDWARE_MAPPING) == 0);
|
||||
assert(HUB75_INTERNAL_PWM_BITS == 11);
|
||||
assert(HUB75_PWM_PLANE_OFFSET == 4);
|
||||
assert(HUB75_SCANS_PER_FRAME == 1);
|
||||
assert(hub75_scans_per_frame_for_brightness(1) == 1);
|
||||
assert(hub75_scans_per_frame_for_brightness(20) == 1);
|
||||
assert(hub75_scans_per_frame_for_brightness(100) == 1);
|
||||
assert(hub75_scans_per_frame_for_brightness(0) == -1);
|
||||
assert(hub75_scans_per_frame_for_brightness(101) == -1);
|
||||
|
||||
uint16_t previous_mapped = 0;
|
||||
for (int brightness = 1; brightness <= 100; ++brightness) {
|
||||
uint16_t mapped = hub75_map_channel_for_brightness(255, brightness);
|
||||
assert(mapped >= previous_mapped);
|
||||
previous_mapped = mapped;
|
||||
for (unsigned plane = 0; plane < HUB75_PWM_BITS; ++plane) {
|
||||
uint64_t remainder = 123u;
|
||||
assert(hub75_oe_ticks_for_plane(
|
||||
10250000, brightness, plane, &remainder
|
||||
) == (1u << (plane + HUB75_PWM_PLANE_OFFSET)));
|
||||
assert(remainder == 0);
|
||||
}
|
||||
}
|
||||
assert(previous_mapped == 2047u);
|
||||
assert(hub75_map_channel_for_brightness(255, 0) == UINT16_MAX);
|
||||
uint64_t invalid_remainder = 0;
|
||||
assert(hub75_oe_ticks_for_plane(5000000, 0, 0, &invalid_remainder) == UINT32_MAX);
|
||||
assert(hub75_oe_ticks_for_plane(5000000, 1, HUB75_PWM_BITS, &invalid_remainder) == UINT32_MAX);
|
||||
uint64_t full_scale_remainder = 0;
|
||||
assert(hub75_oe_ticks_for_plane(
|
||||
10250000, 100, HUB75_PWM_BITS - 1, &full_scale_remainder
|
||||
) == 1024u);
|
||||
uint8_t *frame = calloc(1, HUB75_FRAME_BYTES);
|
||||
uint16_t *planes = calloc(HUB75_BITPLANE_WORDS, sizeof(*planes));
|
||||
assert(frame != NULL);
|
||||
assert(planes != NULL);
|
||||
|
||||
/* Compare extracted planes with the Raspberry-compatible 11-bit map. */
|
||||
frame[0] = 0xff;
|
||||
frame[1] = 0x80;
|
||||
frame[2] = 0x40;
|
||||
size_t bottom = (size_t)HUB75_SCAN_ROWS * HUB75_WIDTH * 3u;
|
||||
frame[bottom] = 0x20;
|
||||
frame[bottom + 1] = 0x10;
|
||||
frame[bottom + 2] = 0x08;
|
||||
assert(hub75_build_bitplanes(
|
||||
frame,
|
||||
HUB75_FRAME_BYTES,
|
||||
planes,
|
||||
HUB75_BITPLANE_WORDS
|
||||
) == 0);
|
||||
const uint8_t values[] = {0xff, 0x80, 0x40, 0x20, 0x10, 0x08};
|
||||
const uint16_t bits[] = {PI_R1, PI_G1, PI_B1, PI_R2, PI_G2, PI_B2};
|
||||
for (unsigned plane = 0; plane < HUB75_PWM_BITS; ++plane) {
|
||||
uint16_t expected = 0;
|
||||
for (unsigned component = 0; component < 6; ++component) {
|
||||
uint16_t mapped = hub75_map_channel_for_brightness(values[component], 100);
|
||||
if ((mapped >> (plane + HUB75_PWM_PLANE_OFFSET)) & 1u) {
|
||||
expected |= bits[component];
|
||||
}
|
||||
}
|
||||
assert(planes[word_index(0, plane, 0)] == expected);
|
||||
}
|
||||
|
||||
memset(frame, 0xff, HUB75_FRAME_BYTES);
|
||||
assert(hub75_build_bitplanes(
|
||||
frame,
|
||||
HUB75_FRAME_BYTES,
|
||||
planes,
|
||||
HUB75_BITPLANE_WORDS
|
||||
) == 0);
|
||||
for (size_t index = 0; index < HUB75_BITPLANE_WORDS; ++index) {
|
||||
assert(planes[index] == (PI_R1 | PI_G1 | PI_B1 | PI_R2 | PI_G2 | PI_B2));
|
||||
}
|
||||
|
||||
/* Brightness changes bitplane data rather than OE pulse duration. */
|
||||
memset(frame, 0, HUB75_FRAME_BYTES);
|
||||
frame[0] = 0xff;
|
||||
frame[1] = 0x4f;
|
||||
frame[2] = 0xa3;
|
||||
uint16_t low_planes[HUB75_BITPLANE_WORDS];
|
||||
assert(hub75_build_bitplanes_for_brightness(
|
||||
frame, HUB75_FRAME_BYTES, 100, planes, HUB75_BITPLANE_WORDS
|
||||
) == 0);
|
||||
assert(hub75_build_bitplanes_for_brightness(
|
||||
frame, HUB75_FRAME_BYTES, 20, low_planes, HUB75_BITPLANE_WORDS
|
||||
) == 0);
|
||||
assert(memcmp(low_planes, planes, sizeof(low_planes)) != 0);
|
||||
|
||||
assert(hub75_build_bitplanes(frame, 1, planes, HUB75_BITPLANE_WORDS) == -1);
|
||||
assert(hub75_build_bitplanes(frame, HUB75_FRAME_BYTES, planes, 1) == -1);
|
||||
|
||||
hub75_config config = {
|
||||
.brightness = 40,
|
||||
.refresh_rate_hz = 100,
|
||||
.cpu_affinity = 0,
|
||||
.realtime_priority = 1,
|
||||
.use_dev_mem = 0,
|
||||
};
|
||||
char error[512] = {0};
|
||||
hub75_context *context = hub75_create(&config, error, sizeof(error));
|
||||
assert(context != NULL);
|
||||
hub75_fake_registers registers;
|
||||
assert(hub75_get_fake_registers(context, ®isters) == 0);
|
||||
assert(((registers.mux1 >> ((14u - 8u) * 4u)) & 0xfu) == 0x5u);
|
||||
assert(((registers.mux1 >> ((15u - 8u) * 4u)) & 0xfu) == 0x1u);
|
||||
assert((registers.pwm_pccr45 & (1u << 4)) != 0);
|
||||
assert((registers.pwm_pccr45 & ((0xfu) | (1u << 5) | (0x3u << 7))) == 0);
|
||||
assert((registers.pwm_per & (1u << 4)) != 0);
|
||||
assert((registers.pwm_pcr4 & 0x1ffu) == 2u);
|
||||
assert((registers.pwm_pcr4 & (1u << 9)) != 0);
|
||||
assert(registers.pwm_ppr4 == (65535u << 16));
|
||||
hub75_stats stats;
|
||||
assert(hub75_get_stats(context, &stats) == 0);
|
||||
assert(strcmp(stats.oe_timing_backend, HUB75_OE_TIMING_BACKEND) == 0);
|
||||
assert(stats.oe_pulse_faults == 0);
|
||||
memset(frame, 0xff, HUB75_FRAME_BYTES);
|
||||
assert(hub75_submit_rgb(context, frame, HUB75_FRAME_BYTES) == 0);
|
||||
assert(hub75_set_brightness(context, 100) == 0);
|
||||
assert(hub75_start(context) == 0);
|
||||
struct timespec pulse_test_delay = {.tv_sec = 0, .tv_nsec = 100000000};
|
||||
nanosleep(&pulse_test_delay, NULL);
|
||||
assert(hub75_get_stats(context, &stats) == 0);
|
||||
assert(stats.max_programmed_oe_ns == 128000u);
|
||||
assert(stats.oe_pulse_faults == 0);
|
||||
assert(hub75_get_fake_registers(context, ®isters) == 0);
|
||||
assert((registers.pwm_pcr4 & (1u << 9)) != 0);
|
||||
assert((registers.pwm_pcr4 & (1u << 10)) == 0);
|
||||
assert((registers.pwm_per & (1u << 4)) != 0);
|
||||
assert((registers.pwm_ppr4 & 0xffffu) != 0);
|
||||
assert((registers.pwm_ppr4 >> 16) + 1u ==
|
||||
(registers.pwm_ppr4 & 0xffffu));
|
||||
hub75_destroy(context);
|
||||
|
||||
config.fake_pwm4_stuck = 1;
|
||||
context = hub75_create(&config, error, sizeof(error));
|
||||
assert(context != NULL);
|
||||
assert(hub75_start(context) == 0);
|
||||
struct timespec stuck_test_delay = {.tv_sec = 0, .tv_nsec = 100000000};
|
||||
nanosleep(&stuck_test_delay, NULL);
|
||||
assert(hub75_get_stats(context, &stats) == 0);
|
||||
assert(stats.oe_pulse_faults == 1);
|
||||
assert(stats.oe_forced_blanks == 1);
|
||||
assert(strstr(stats.oe_timing_error, "start bit did not clear") != NULL);
|
||||
assert(hub75_get_fake_registers(context, ®isters) == 0);
|
||||
assert((registers.pwm_per & (1u << 4)) == 0);
|
||||
assert(((registers.mux1 >> ((14u - 8u) * 4u)) & 0xfu) == 0x1u);
|
||||
hub75_destroy(context);
|
||||
config.fake_pwm4_stuck = 0;
|
||||
|
||||
config.fake_pwm5_mode = 1;
|
||||
context = hub75_create(&config, error, sizeof(error));
|
||||
assert(context != NULL);
|
||||
assert(hub75_get_fake_registers(context, ®isters) == 0);
|
||||
assert((registers.pwm_per & (1u << 5)) != 0);
|
||||
assert((registers.pwm_pccr45 & (1u << 6)) != 0);
|
||||
assert(registers.pwm_pcr5 == 0x100u);
|
||||
assert(registers.pwm_ppr5 == 0x000b0006u);
|
||||
hub75_destroy(context);
|
||||
|
||||
config.fake_pwm5_mode = 2;
|
||||
context = hub75_create(&config, error, sizeof(error));
|
||||
assert(context == NULL);
|
||||
assert(strstr(error, "incompatible shared PWM4/5 clock") != NULL);
|
||||
assert(hub75_force_safeoff(0, error, sizeof(error)) == 0);
|
||||
|
||||
free(planes);
|
||||
free(frame);
|
||||
puts("native_bitplane_tests=PASS");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user