/* * This file is part of the LED_screen project. * Copyright 2019 Edward V. Emelianov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include // memset, memcpy #include #include "fonts.h" #include "hardware.h" #include "screen.h" //#include "usb.h" // !!!FOR LITTLE-ENDIAN!!! // X coordinate - from left to right! // Y coordinate - from top to bottom! // (0,0) is top left corner // all-screen buffer static uint8_t screenbuf[SCREENBUF_SZ]; extern volatile uint32_t Tms; // time for FPS count static uint32_t FPS = 0, Tfps = 0; // approx FPS uint32_t getFPS(){return FPS;} static uint8_t fgColor = 0xff, bgColor = 0; // foreground and background colors void setBGcolor(uint8_t c){bgColor = c;} void setFGcolor(uint8_t c){fgColor = c;} /** * @brief FillScreen - fill screen buffer with current bgColor */ void ClearScreen(){ for(int i = 0; i < SCREENBUF_SZ; ++i) screenbuf[i] = bgColor; for(int i = 0; i < 32; ++i){ DrawPix(0,i,0b11111111); // white DrawPix(27,i,0b11100000); // red DrawPix(34,i,0b00011100); // green DrawPix(63,i,0b00000011); // blue } // memset -> halt //memset(screenbuf, pattern, SCREENBUF_SZ); } /** * @brief DrawPix - set or clear pixel * @param X, Y - pixel coordinates (could be outside of screen) * @param pix - == pixel color (RRRGGGBB) */ void DrawPix(int16_t X, int16_t Y, uint8_t pix){ if(X < 0 || X > SCREEN_WIDTH-1 || Y < 0 || Y > SCREEN_HEIGHT-1) return; // outside of screen // now calculate coordinate of pixel screenbuf[Y*SCREEN_WIDTH + X] = pix; } void InvertPix(int16_t X, int16_t Y){ if(X < 0 || X > SCREEN_WIDTH-1 || Y < 0 || Y > SCREEN_HEIGHT-1) return; // outside of screen screenbuf[Y*SCREEN_WIDTH + X] = ~screenbuf[Y*SCREEN_WIDTH + X]; } void XORPix(int16_t X, int16_t Y, uint8_t pix){ if(X < 0 || X > SCREEN_WIDTH-1 || Y < 0 || Y > SCREEN_HEIGHT-1) return; // outside of screen screenbuf[Y*SCREEN_WIDTH + X] ^= pix; } /** * @brief DrawCharAt - draws character @ position X,Y (this point is left baseline corner of char!) * character will be drawn with current fg and bg colors * @param X, Y - started point * @param Char - char to draw * @return char width */ uint8_t DrawCharAt(int16_t X, int16_t Y, uint8_t Char){ const uint8_t *curchar = font_char(Char); if(!curchar) return 0; // now change Y coordinate to left upper corner of font Y += 1 - curfont->height + curfont->baseline; // height and width of letter in pixels uint8_t h = curfont->height, w = *curchar++; // now curchar is pointer to bits array uint8_t lw = curfont->bytes / h; // width of letter in bytes for(uint8_t row = 0; row <= h; ++row){ for(uint8_t col = 0; col < w; ++col){ if(curchar[row*lw + (col/8)] & (1 << (7 - (col%8)))) DrawPix(X + col, Y + row, fgColor); else DrawPix(X + col, Y + row, bgColor); } } return w; } /** * @brief PutStringAt - draw text string @ screen * @param X, Y - base coordinates * @param str - string to draw * @return - text width in pixels */ uint8_t PutStringAt(int16_t X, int16_t Y, const char *str){ if(!str) return 0; int16_t Xold = X; while(*str){ X += DrawCharAt(X, Y, (uint8_t)*str++); } return X - Xold; } uint8_t *getScreenBuf(){return screenbuf;} static screen_state ScrnState = SCREEN_RELAX; screen_state getScreenState(){return ScrnState;} static uint8_t currentB = 0; // current block number static uint8_t Ntick = 0; // tick number (0..7) for PWM color /** * @brief process_screen - screen state machine processing */ void process_screen(){ static uint32_t framecnt = 0; switch(ScrnState){ case SCREEN_ACTIVE: // transmission active if(transfer_done){ ScrnState = SCREEN_UPDATENXT; }else return; // fallthrough case SCREEN_UPDATENXT: ConvertScreenBuf(screenbuf, currentB, Ntick); // convert data TIM_DMA_transfer(currentB); // start transfer ScrnState = SCREEN_ACTIVE; if(++currentB >= NBLOCKS){ currentB = 0; // start again if(++Ntick >= 7){ Ntick = 0; ++framecnt; if(Tms - Tfps > 999){ FPS = framecnt; Tfps = Tms; framecnt = 0; } } } break; default: return; } } /** * @brief ShowScreen - turn on data transmission */ void ScreenON(){ ScrnState = SCREEN_UPDATENXT; Tfps = Tms; } void ScreenOFF(){ stopTIMDMA(); SET(nOE); ScrnState = SCREEN_RELAX; currentB = 0; Ntick = 0; } /** * @brief RGB2pack - convert RGB color to packed RRRGGGBB * @param RGB - color (each in range 0..8) * @return packed color */ uint8_t RGB2pack(const uint8_t *RGB){ uint8_t b = RGB[2] & 7; if(b) b = (b - 1) >> 1; return ((RGB[0] & 7)<<5 | (RGB[1] & 7) << 2 | b); } /** * @brief pack2RGB - convert packed color to array of RGB (0..8) * @param pack - packed color * @return RGB array */ uint8_t *pack2RGB(uint8_t pack){ static uint8_t RGB[3]; RGB[0] = pack >> 5; RGB[1] = (pack & 0x1c) >> 2; pack &= 3; if(pack) RGB[2] = (pack<<1) + 1; else RGB[2] = 0; return RGB; }