Skip to content

Commit

Permalink
Add details for colour modes
Browse files Browse the repository at this point in the history
  • Loading branch information
holmatic committed Jan 9, 2021
1 parent bb8eea5 commit af6b082
Show file tree
Hide file tree
Showing 12 changed files with 580 additions and 40 deletions.
2 changes: 1 addition & 1 deletion main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(COMPONENT_SRCS "main.c" "file_server.c" "signal_to_zx.c" "lcd_display.c" "vga_display.c" "led_matrix.c" "iis_videosig.c" "signal_from_zx.c" "zx_server.c" "zx_serv_dialog.c" "wifi_sta.c" "zx_file_img.c")
set(COMPONENT_SRCS "main.c" "file_server.c" "video_attr.c" "signal_to_zx.c" "lcd_display.c" "vga_display.c" "led_matrix.c" "iis_videosig.c" "signal_from_zx.c" "zx_server.c" "zx_serv_dialog.c" "wifi_sta.c" "zx_file_img.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")

set(COMPONENT_EMBED_FILES "favicon.ico" "upload_script.html")
Expand Down
4 changes: 3 additions & 1 deletion main/iis_videosig.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ static bool video_synced_state=false;
static int timeout_verbose=10;



bool vid_is_synced(){
return video_synced_state;
}

static IRAM_ATTR uint32_t vid_get_next_data()
{
Expand Down
1 change: 1 addition & 0 deletions main/iis_videosig.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// call once at startup
void vid_init();
void vid_cal_pixel_start();
bool vid_is_synced();
extern uint32_t vid_pixel_mem[];

/* number of top-header lines before actual standard-character screen starts*/
Expand Down
72 changes: 47 additions & 25 deletions main/lcd_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "esp_log.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "video_attr.h"
#include "iis_videosig.h"
#include "lcd_display.h"

Expand Down Expand Up @@ -62,9 +63,7 @@ typedef enum {



//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
/*
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
Expand All @@ -74,21 +73,15 @@ typedef enum {
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
//GUI颜色

#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
//以上三色为PANEL的颜色

#define LIGHTGREEN 0X841F //浅绿色
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
*/
// actual_colour=0x081F; // green
//actual_colour=0x03FF; // yellow

#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x1F00
#define GREEN 0xE007
#define RED 0x00F8


static uint16_t fg_colour=BLACK;
Expand Down Expand Up @@ -479,16 +472,37 @@ void lcd_set_colour_cmd(char cmd, uint16_t data)
}
}


static uint8_t *attr_mem_fg=NULL;
static uint8_t *attr_mem_bg=NULL;

static uint16_t trans_colour(uint8_t rgb_colour ){
uint16_t v=0;
if(rgb_colour&VIDATTR_RED) v|= RED;
if(rgb_colour&VIDATTR_GREEN) v|= GREEN;
if(rgb_colour&VIDATTR_BLUE) v|= BLUE;
return v;
}


static int32_t zx_attr_hash[30]; // attribute hash per line

static bool zx_calc_lines(uint16_t *dest, int line, int frame, int linect)
{
bool update=false;
uint16_t val=0;
uint16_t fg,bg,val=0;
uint32_t m;
int ix;
/* first check if we need an update */
if(init_cnt) {update=true; init_cnt--; }
for (int y=line; y<line+linect; y++) {
if (update) break;
if((y&7)==0){
int aix=(40*(y/8));
int32_t hash=0;
for(int i=0;i<40;i++) { hash+=attr_mem_fg[aix]-attr_mem_bg[aix]; aix++; }
if(hash!=zx_attr_hash[y/8]) {update=true; break;};
}
for (int xw=0; xw<10; xw++) {
if (update) break;
ix=10*y+xw;
Expand All @@ -500,16 +514,23 @@ static bool zx_calc_lines(uint16_t *dest, int line, int frame, int linect)
if(!update) return false;
/* do the actual update */
for (int y=line; y<line+linect; y++) {
int aix=(40*(y/8));
for (int xw=0; xw<10; xw++) {
int32_t attrhash=0;
ix=10*y+xw;
m=zx_vid_hash[ix]=vid_pixel_mem[ix];
for (int b=0; b<32; b++) {
//val= (m & 0x80000000) ? 0x081F : 0x0000 ;
//val= (m & 0x80000000) ? 0x0000 : 0xFFFF ;
val= (m & 0x80000000) ? fg_colour : bg_colour ;
*dest++ = val ;
m<<=1;
}
for (int c=0; c<4; c++) {
attrhash+=attr_mem_fg[aix]-attr_mem_bg[aix];
fg=trans_colour(attr_mem_fg[aix]);
bg=trans_colour(attr_mem_bg[aix]);
for (int b=0; b<8; b++) {
val= (m & 0x80000000) ? fg:bg ;
*dest++ = val ;
m<<=1;
}
aix++;
}
zx_attr_hash[y/8]=attrhash;
}
}
return true;
Expand Down Expand Up @@ -568,6 +589,7 @@ static void display_pretty_colors(spi_device_handle_t spi)

void lcd_disp_init()
{
vidattr_get_mem(&attr_mem_fg, &attr_mem_bg);
get_colours_from_nv();
if(fg_colour==BLACK) actual_colour=bg_colour;
else actual_colour=fg_colour;
Expand Down
3 changes: 3 additions & 0 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "signal_to_zx.h"
#include "wifi_sta.h"
#include "iis_videosig.h"
#include "video_attr.h"
#include "led_matrix.h"
#include "lcd_display.h"
#include "vga_display.h"
Expand Down Expand Up @@ -210,6 +211,8 @@ void app_main()
lcd_disp_init();

if(0) ledmx_init(); /* support for 64x64 low-res-graphics LED panel display, highly experimental and non-optimized */

video_attr_init();
if(1) vga_disp_init();

wifi_sta_init(); /* needs nvs_sys_init */
Expand Down
142 changes: 136 additions & 6 deletions main/vga_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "driver/gpio.h"
#include "iis_videosig.h"
#include "video_attr.h"
#include "vga_display.h"

static const char *TAG="vga_disp";
Expand Down Expand Up @@ -335,10 +336,8 @@ static void play_stream(int freq, lldesc_t volatile * dmaBuffers)

static uint8_t *framebuf=NULL;
static volatile lldesc_t *dma_ll=NULL;


uint8_t attr_mem_fg[40*30]; // swapped words (ix^2)
uint8_t attr_mem_bg[40*30]; // swapped words (ix^2)
static uint8_t *attr_mem_fg=NULL;
static uint8_t *attr_mem_bg=NULL;


// this is with colours and needs 51us
Expand Down Expand Up @@ -492,8 +491,136 @@ static void stop_stream()
}


#define VBITMAP_IS_VALID_CHAR_L2 0x01
#define VBITMAP_IS_BLOCK_CHAR_L2 0x04
#define VBITMAP_IS_GREY_CHAR_L2 0x08
#define VBITMAP_IS_INV_CHAR_L2 0x02
#define VBITMAP_IS_BLOCK_CHAR_L6 0x40
#define VBITMAP_IS_GREY_CHAR_L6 0x80

/* For the standard ZX81 charset, every possible bit map pattern (when looking at line 2 or 6 of the character) maps to flags that show if this is a valid char, and possible also if it is graphics etc */


const uint8_t vbitm_flags[256]={0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x45};

static int avg_empty_cnt=0;
static int avg_invalid_cnt=0;
static int avg_dark_cnt=0;

static bool vmode_nochars=false;
static bool vmode_dark=false;


static void create_fancy_colours3()
{
uint8_t * pix_mem8=(uint8_t *)vid_pixel_mem;
int empty_cnt=0;
int invalid_cnt=0;
int dark_cnt=0;
static uint8_t switchmode_holdoff=2;
uint8_t *curr_attr= vmode_dark ? attr_mem_bg:attr_mem_fg;
for(int y=0;y<24;y++){
/* check for overscan */
if(pix_mem8[ ( (24+2+y*8)*40 + 3)^3 ]) invalid_cnt+=4;
for(int x=0;x<32;x++){
uint8_t pattern=pix_mem8[ ( (24+2+y*8)*40 +4+x)^3 ];
uint8_t fg=HSYNC_MASK|VSYNC_MASK;
uint8_t flags;
if(pattern!=0){
/* upper part not empty */
flags=vbitm_flags[pattern];
if(0 == (flags&VBITMAP_IS_VALID_CHAR_L2) ){
fg|=0x4; /* empty or normal text */
invalid_cnt++; /* maybe high-res or so, nothing that fancy colours work with.. */
} else if ( flags&VBITMAP_IS_BLOCK_CHAR_L2 ){
fg|=0xe; // blocks-> white
if(pattern==0xff) dark_cnt++;
} else if ( flags&VBITMAP_IS_INV_CHAR_L2 ){
fg|=0xc; // inverse text -> yellow
dark_cnt++;
} else if ( flags&VBITMAP_IS_GREY_CHAR_L6 ){
fg|=0x6; // chequered-> cyan
}else{
fg|=0x4; /* some normal text */
}
}else{
/* upper part just empty */
pattern=pix_mem8[ ( (24+6+y*8)*40 +4+x)^3 ];
if(pattern==0){
empty_cnt++;
fg|=0x4; /* empty or some normal text */
} else {
flags=vbitm_flags[pattern];
if ( flags&VBITMAP_IS_BLOCK_CHAR_L6 ){
fg|=0xe; // blocks-> white
if(pattern==0xff) dark_cnt++;
} else if ( flags&VBITMAP_IS_GREY_CHAR_L6 ){
fg|=0x6; // chequered-> cyan
}else{
fg|=0x4; /* empty or some normal text */
}
}
}
if(!vmode_nochars) curr_attr[(3+y)*40+4+x] = fg; // green on black
}
}

avg_empty_cnt= (7*avg_empty_cnt + empty_cnt) /8;
avg_invalid_cnt= (7*avg_invalid_cnt + invalid_cnt) /8;
avg_dark_cnt= (7*avg_dark_cnt + dark_cnt) /8;

if(switchmode_holdoff) {
switchmode_holdoff--;
} else {
if(vmode_nochars){
// check if screen looks like regular characters again
if(avg_invalid_cnt<2 || avg_invalid_cnt*16 < (768-avg_empty_cnt) ){
vmode_nochars=false;
switchmode_holdoff=50;
}
} else {
// check if screen looks like HRG or invalid
if(avg_invalid_cnt > 4 && avg_invalid_cnt*8 > (768-avg_empty_cnt) ){
vmode_nochars=true;
switchmode_holdoff=50;
// remove colour info
for(int i=0;i<30*40;i++){
attr_mem_fg[i] = HSYNC_MASK|VSYNC_MASK | (WHITE_MASK) ; // white on black
attr_mem_bg[i] = HSYNC_MASK|VSYNC_MASK ; // all-black
}
}
}

if(vmode_dark){
// check if screen looks normal/bright
if(avg_dark_cnt<284){
vmode_dark=false;
switchmode_holdoff=50;
// remove colour info
for(int i=0;i<30*40;i++){
attr_mem_fg[i] = HSYNC_MASK|VSYNC_MASK | (WHITE_MASK) ; // white on black
attr_mem_bg[i] = HSYNC_MASK|VSYNC_MASK ; // all-black
}
}
} else {
// check if screen looks dark by inverse
if(avg_dark_cnt > 484){
vmode_dark=true;
switchmode_holdoff=50;
for(int i=0;i<30*40;i++){
attr_mem_fg[i] = HSYNC_MASK|VSYNC_MASK ; // white on black
attr_mem_bg[i] = HSYNC_MASK|VSYNC_MASK | (WHITE_MASK) ;
}
}
}
}

}




static void create_fancy_colours()
static void create_fancy_colours_conventional()
{
uint8_t * pix_mem8=(uint8_t *)vid_pixel_mem;
for(int y=0;y<24;y++){
Expand Down Expand Up @@ -524,6 +651,7 @@ static void vga_task(void*arg)
esp_err_t ret;

ESP_LOGI(TAG, "VGA-Alloc ...");
vidattr_get_mem(&attr_mem_fg, &attr_mem_bg);
alloc_scrbuf();
init_stream();
play_stream(12600000,dma_ll);
Expand All @@ -533,9 +661,11 @@ static void vga_task(void*arg)
//ESP_LOGI(TAG, "hostspi_task ...");
vTaskDelay(1); // allow some startup and settling time (might help, not proven)
frames++;
create_fancy_colours();
//create_fancy_colours();
if(frames%1000==10){
ESP_LOGI(TAG, "VGA intcnt %d %d, duration %d us (%d%%)",int_c_cnt,int_fr_cnt,isr_time_us, isr_time_us/SCR_CHUNK_LINES*100/32 );
ESP_LOGI(TAG, "Avg - empty %d, dark %d, invalid %d",avg_empty_cnt,avg_dark_cnt,avg_invalid_cnt );
ESP_LOGI(TAG, "Vmode dark %d, nochar %d",vmode_dark?1:0,vmode_nochars?1:0);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion main/vga_display.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "esp_err.h"
#include <esp_types.h>
#include "esp_attr.h"
#include "freertos/queue.h"


// call once at startup
Expand Down
Loading

0 comments on commit af6b082

Please sign in to comment.