Files
2015-09-03 01:20:11 -07:00

610 lines
17 KiB
C

/*
PokeMini - Pokémon-Mini Emulator
Copyright (C) 2009-2014 JustBurn
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 <http://www.gnu.org/licenses/>.
*/
#include "PokeMini.h"
#include "Video.h"
TMinxLCD MinxLCD;
int LCDDirty = 0;
uint8_t *LCDData = NULL;
uint8_t *LCDPixelsD = NULL;
uint8_t *LCDPixelsA = NULL;
uint8_t *LCDPixelsAS = NULL;
const int LCDDirtyPixels[4] = {
4, // LCDMODE_ANALOG
2, // LCDMODE_3SHADES
1, // LCDMODE_2SHADES
2 // LCDMODE_COLORS
};
//
// Functions
//
int MinxLCD_Create(void)
{
// Create LCD memory
LCDData = (uint8_t *)malloc(256*9);
if (!LCDData) return 0;
LCDPixelsD = (uint8_t *)malloc(96*64);
if (!LCDPixelsD) return 0;
LCDPixelsA = (uint8_t *)malloc(96*64*2);
if (!LCDPixelsA) return 0;
LCDPixelsAS = (uint8_t *)LCDPixelsA + 96*64;
// Reset
MinxLCD_Reset(1);
return 1;
}
void MinxLCD_Destroy(void)
{
if (LCDData) {
free(LCDData);
LCDData = NULL;
}
if (LCDPixelsD) {
free(LCDPixelsD);
LCDPixelsD = NULL;
}
if (LCDPixelsA) {
free(LCDPixelsA);
LCDPixelsA = NULL;
}
}
void MinxLCD_Reset(int hardreset)
{
// Clean up memory
memset(LCDData, 0x00, 256*9);
memset(LCDPixelsD, 0x00, 96*64);
memset(LCDPixelsA, 0x00, 96*64*2);
// Initialize State
memset((void *)&MinxLCD, 0, sizeof(TMinxLCD));
// Initialize variables
MinxLCD_SetContrast(0x1F);
}
int MinxLCD_LoadState(FILE *fi, uint32_t bsize)
{
POKELOADSS_START(256*9 + 96*64 + 96*64 + 64);
POKELOADSS_A(LCDData, 256*9);
POKELOADSS_A(LCDPixelsD, 96*64);
POKELOADSS_A(LCDPixelsA, 96*64);
POKELOADSS_32(MinxLCD.Pixel0Intensity);
POKELOADSS_32(MinxLCD.Pixel1Intensity);
POKELOADSS_8(MinxLCD.Column);
POKELOADSS_8(MinxLCD.StartLine);
POKELOADSS_8(MinxLCD.SetContrast);
POKELOADSS_8(MinxLCD.Contrast);
POKELOADSS_8(MinxLCD.SegmentDir);
POKELOADSS_8(MinxLCD.MaxContrast);
POKELOADSS_8(MinxLCD.SetAllPix);
POKELOADSS_8(MinxLCD.InvAllPix);
POKELOADSS_8(MinxLCD.DisplayOn);
POKELOADSS_8(MinxLCD.Page);
POKELOADSS_8(MinxLCD.RowOrder);
POKELOADSS_8(MinxLCD.ReadModifyMode);
POKELOADSS_8(MinxLCD.RequireDummyR);
POKELOADSS_8(MinxLCD.RMWColumn);
POKELOADSS_X(42);
POKELOADSS_END(256*9 + 96*64 + 96*64 + 64);
return 1;
}
int MinxLCD_SaveState(FILE *fi)
{
POKESAVESS_START(256*9 + 96*64 + 96*64 + 64);
POKESAVESS_A(LCDData, 256*9);
POKESAVESS_A(LCDPixelsD, 96*64);
POKESAVESS_A(LCDPixelsA, 96*64);
POKESAVESS_32(MinxLCD.Pixel0Intensity);
POKESAVESS_32(MinxLCD.Pixel1Intensity);
POKESAVESS_8(MinxLCD.Column);
POKESAVESS_8(MinxLCD.StartLine);
POKESAVESS_8(MinxLCD.SetContrast);
POKESAVESS_8(MinxLCD.Contrast);
POKESAVESS_8(MinxLCD.SegmentDir);
POKESAVESS_8(MinxLCD.MaxContrast);
POKESAVESS_8(MinxLCD.SetAllPix);
POKESAVESS_8(MinxLCD.InvAllPix);
POKESAVESS_8(MinxLCD.DisplayOn);
POKESAVESS_8(MinxLCD.Page);
POKESAVESS_8(MinxLCD.RowOrder);
POKESAVESS_8(MinxLCD.ReadModifyMode);
POKESAVESS_8(MinxLCD.RequireDummyR);
POKESAVESS_8(MinxLCD.RMWColumn);
POKESAVESS_X(42);
POKESAVESS_END(256*9 + 96*64 + 96*64 + 64);
}
uint8_t MinxLCD_ReadReg(int cpu, uint8_t reg)
{
// 0xFE to 0xFF
switch(reg) {
case 0xFE: // Read from LCD with Control Activated
return MinxLCD_LCDReadCtrl(cpu);
case 0xFF: // Read from LCD with Control Desactivated
return MinxLCD_LCDRead(cpu);
default: // Unused
return 0x00;
}
}
void MinxLCD_WriteReg(int cpu, uint8_t reg, uint8_t val)
{
// 0xFE to 0xFF
switch(reg) {
case 0xFE: // Write to LCD with Control Activated
MinxLCD_LCDWriteCtrl(val);
return;
case 0xFF: // Write to LCD with Control Desactivated
MinxLCD_LCDWrite(val);
return;
}
}
#define DECAY_A_OFF 64
#define DECAY_ARISE 50
#define DECAY_AFALL 30
#define DECAY_L_OFF 16
#define DECAY_LRISE 4
#define DECAY_LFALL 2
void MinxLCD_DecayRefreshOld(void)
{
int i, amt;
if (MinxLCD.DisplayOn) {
for (i=0; i<96*64; i++) {
if (LCDPixelsD[i]) {
amt = Interpolate8(LCDPixelsA[i], MinxLCD.Pixel1Intensity, DECAY_ARISE) + DECAY_LRISE;
if (amt > MinxLCD.Pixel1Intensity) amt = MinxLCD.Pixel1Intensity;
} else {
amt = Interpolate8(LCDPixelsA[i], MinxLCD.Pixel0Intensity, DECAY_AFALL) - DECAY_LFALL;
if (amt < MinxLCD.Pixel0Intensity) amt = MinxLCD.Pixel0Intensity;
}
LCDPixelsA[i] = amt;
}
} else {
for (i=0; i<96*64; i++) {
amt = Interpolate8(LCDPixelsA[i], 0, DECAY_A_OFF) - DECAY_L_OFF;
if (amt < MinxLCD.Pixel0Intensity) amt = MinxLCD.Pixel0Intensity;
LCDPixelsA[i] = amt;
}
}
}
static const uint8_t BitsActives[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
void MinxLCD_DecayRefresh(void)
{
int i, level;
uint8_t sh;
// This is tuned for 5 shades
if (MinxLCD.DisplayOn) {
for (i=0; i<96*64; i++) {
sh = (LCDPixelsD[i] ? 0x08 : 0x00) | (LCDPixelsAS[i] >> 1);
LCDPixelsAS[i] = sh;
level = BitsActives[sh];
LCDPixelsA[i] = (MinxLCD.Pixel0Intensity * (4 - level) + MinxLCD.Pixel1Intensity * level) >> 2;
}
} else {
for (i=0; i<96*64; i++) {
sh = (LCDPixelsAS[i] >> 1);
LCDPixelsAS[i] = sh;
level = BitsActives[sh];
LCDPixelsA[i] = (MinxLCD.Pixel0Intensity * (4 - level) + MinxLCD.Pixel1Intensity * level) >> 2;
}
}
}
void MinxLCD_Render(void)
{
uint8_t pixel;
int xC, yC, yP;
if (MinxLCD.DisplayOn) {
for (yC=0; yC<64; yC++) {
yP = (yC + MinxLCD.StartLine) & 63;
if (MinxLCD.RowOrder) yP = 63 - yP;
for (xC=0; xC<96; xC++) {
pixel = (LCDData[((yP >> 3) * 256) + xC] >> (yP & 7)) & 1;
LCDPixelsD[(yC * 96) + xC] = (pixel ^ MinxLCD.InvAllPix) | MinxLCD.SetAllPix;
}
}
} else for (yC=0; yC<96*64; yC++) LCDPixelsD[yC] = 0;
}
uint8_t MinxLCD_LCDReadCtrl(int cpu)
{
uint8_t data;
if (MinxLCD.SetContrast) {
MinxLCD.SetContrast = 0;
// Contrast query, cause incorrect value?
MinxLCD_SetContrast(0x3F);
data = 0;
} else {
// Get status
data = 0x40 | (MinxLCD.DisplayOn ? 0x20 : 0x00);
}
return data;
}
uint8_t MinxLCD_LCDRead(int cpu)
{
static uint8_t data = 0x40;
if (MinxLCD.SetContrast) {
MinxLCD.SetContrast = 0;
// Contrast query, cause incorrect value?
MinxLCD_SetContrast(0x3F);
data = 0;
} else {
// Get pixel
if (!MinxLCD.RequireDummyR && cpu) {
if (MinxLCD.SegmentDir) {
data = LCDData[131 - MinxLCD.Column + (MinxLCD.Page << 8)];
} else {
data = LCDData[MinxLCD.Column + (MinxLCD.Page << 8)];
}
if (MinxLCD.Page >= 8) data &= 0x01;
if (!MinxLCD.ReadModifyMode) {
MinxLCD.Column++;
if (MinxLCD.Column > 131) MinxLCD.Column = 131;
MinxLCD.RequireDummyR = 1;
}
} else MinxLCD.RequireDummyR = 0;
}
return data;
}
void MinxLCD_LCDWriteCtrl(uint8_t data)
{
if (MinxLCD.SetContrast) {
MinxLCD.SetContrast = 0;
MinxLCD_SetContrast(data & 0x3F);
return;
}
switch(data) {
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F:
if (!MinxLCD.ReadModifyMode) {
MinxLCD.Column = (MinxLCD.Column & 0xF0) | (data & 0x0F);
MinxLCD.RequireDummyR = 1;
}
return;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
if (!MinxLCD.ReadModifyMode) {
MinxLCD.Column = (MinxLCD.Column & 0x0F) | ((data & 0x0F) << 4);
MinxLCD.RequireDummyR = 1;
}
return;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
// Do nothing?
return;
case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
// Modify LCD voltage? (2F Default)
// 0x28 = Blank
// 0x29 = Blank
// 0x2A = Blue screen then blank
// 0x2B = Blank
// 0x2C = Blank
// 0x2D = Blank
// 0x2E = Blue screen (overpower?)
// 0x2F = Normal
// User shouldn't mess with this ones as may damage the LCD
return;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F:
// Do nothing?
return;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F:
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F:
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F:
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
// Set starting LCD scanline (cause warp around)
MinxLCD.StartLine = data - 0x40;
LCDDirty = MINX_DIRTYSCR;
return;
case 0x80:
// Do nothing?
return;
case 0x81:
// Set contrast at the next write
MinxLCD.SetContrast = 1;
return;
case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
// Do nothing?
return;
case 0xA0:
// Segment Driver Direction Select: Normal
MinxLCD.SegmentDir = 0;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xA1:
// Segment Driver Direction Select: Reverse
MinxLCD.SegmentDir = 1;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xA2:
// Max Contrast: Disable
MinxLCD.MaxContrast = 0;
MinxLCD_SetContrast(MinxLCD.Contrast);
return;
case 0xA3:
// Max Contrast: Enable
MinxLCD.MaxContrast = 1;
MinxLCD_SetContrast(MinxLCD.Contrast);
return;
case 0xA4:
// Set All Pixels: Disable
MinxLCD.SetAllPix = 0;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xA5:
// Set All Pixels: Enable
MinxLCD.SetAllPix = 1;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xA6:
// Invert All Pixels: Disable
MinxLCD.InvAllPix = 0;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xA7:
// Invert All Pixels: Enable
MinxLCD.InvAllPix = 1;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xA8: case 0xA9: case 0xAA: case 0xAB:
// Do nothing!?
return;
case 0xAC: case 0xAD:
// User shouldn't mess with this ones as may damage the LCD
return;
case 0xAE:
// Display Off
MinxLCD.DisplayOn = 0;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xAF:
// Display On
MinxLCD.DisplayOn = 1;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
case 0xB8:
// Set page (0-8, each page is 8px high)
MinxLCD.Page = data & 15;
return;
case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
// uh... do nothing?
return;
case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7:
// Display rows from top to bottom as 0 to 63
MinxLCD.RowOrder = 0;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
// Display rows from top to bottom as 63 to 0
MinxLCD.RowOrder = 1;
LCDDirty = MINX_DIRTYSCR;
return;
case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7:
case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
// Do nothing?
return;
case 0xE0:
// Start "Read Modify Write"
MinxLCD.ReadModifyMode = 1;
MinxLCD.RMWColumn = MinxLCD.Column;
return;
case 0xE2:
// Reset
MinxLCD.SetContrast = 0;
MinxLCD_SetContrast(0x20);
MinxLCD.Column = 0;
MinxLCD.StartLine = 0;
MinxLCD.SegmentDir = 0;
MinxLCD.MaxContrast = 0;
MinxLCD.SetAllPix = 0;
MinxLCD.InvAllPix = 0;
MinxLCD.DisplayOn = 0;
MinxLCD.Page = 0;
MinxLCD.RowOrder = 0;
MinxLCD.ReadModifyMode = 0;
MinxLCD.RequireDummyR = 1;
MinxLCD.RMWColumn = 0;
return;
case 0xE3:
// No operation
return;
case 0xEE:
// End "Read Modify Write"
MinxLCD.ReadModifyMode = 0;
MinxLCD.Column = MinxLCD.RMWColumn;
return;
case 0xE1: case 0xE4: case 0xE5: case 0xE6: case 0xE7:
case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEF:
// User shouldn't mess with this ones as may damage the LCD
return;
case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
// 0xF1 and 0xF5 freeze LCD and cause malfunction (need to power off the device to restore)
// User shouldn't mess with this ones as may damage the LCD
return;
case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF:
// Contrast voltage control, FC = Default
// User shouldn't mess with this ones as may damage the LCD
return;
}
}
void MinxLCD_LCDWrite(uint8_t data)
{
int addr;
if (MinxLCD.SetContrast) {
MinxLCD.SetContrast = 0;
// Set contrast
MinxLCD_SetContrast(data & 0x3F);
} else {
// Set pixel
if (MinxLCD.SegmentDir) {
addr = 131 - MinxLCD.Column + (MinxLCD.Page << 8);
} else {
addr = MinxLCD.Column + (MinxLCD.Page << 8);
}
LCDData[addr] = data;
if (PRCColorMap) MinxColorPRC_WriteLCD(addr, data);
MinxLCD.Column++;
if (MinxLCD.Column > 131) MinxLCD.Column = 131;
MinxLCD.RequireDummyR = 1;
LCDDirty = LCDDirtyPixels[CommandLine.lcdmode];
}
}
void MinxLCD_LCDWritefb(uint8_t *fb)
{
int i;
uint8_t *dst = (uint8_t *)LCDData, pages = 8;
if (MinxLCD.SegmentDir) {
while (pages--) {
for (i=0; i<96; i++) dst[131-i] = fb[i];
dst += 256; fb += 96;
}
} else {
while (pages--) {
memcpy(dst, fb, 96);
dst += 256; fb += 96;
}
}
MinxLCD.Page = 7;
MinxLCD.Column = 96;
MinxLCD.RequireDummyR = 1;
MinxLCD.ReadModifyMode = 0;
LCDDirty = LCDDirtyPixels[CommandLine.lcdmode];
}
// Contrast level on light and dark pixel
const uint8_t MinxLCD_ContrastLvl[64][2] = {
{ 0, 4}, // 0 (0x00)
{ 0, 4}, // 1 (0x01)
{ 0, 4}, // 2 (0x02)
{ 0, 4}, // 3 (0x03)
{ 0, 6}, // 4 (0x04)
{ 0, 11}, // 5 (0x05)
{ 0, 17}, // 6 (0x06)
{ 0, 24}, // 7 (0x07)
{ 0, 31}, // 8 (0x08)
{ 0, 40}, // 9 (0x09)
{ 0, 48}, // 10 (0x0A)
{ 0, 57}, // 11 (0x0B)
{ 0, 67}, // 12 (0x0C)
{ 0, 77}, // 13 (0x0D)
{ 0, 88}, // 14 (0x0E)
{ 0, 99}, // 15 (0x0F)
{ 0, 110}, // 16 (0x10)
{ 0, 122}, // 17 (0x11)
{ 0, 133}, // 18 (0x12)
{ 0, 146}, // 19 (0x13)
{ 0, 158}, // 20 (0x14)
{ 0, 171}, // 21 (0x15)
{ 0, 184}, // 22 (0x16)
{ 0, 198}, // 23 (0x17)
{ 0, 212}, // 24 (0x18)
{ 0, 226}, // 25 (0x19)
{ 0, 240}, // 26 (0x1A)
{ 0, 255}, // 27 (0x1B)
{ 2, 255}, // 28 (0x1C)
{ 5, 255}, // 29 (0x1D)
{ 10, 255}, // 30 (0x1E)
{ 15, 255}, // 31 (0x1F)
{ 21, 255}, // 32 (0x20)
{ 27, 255}, // 33 (0x21)
{ 34, 255}, // 34 (0x22)
{ 41, 255}, // 35 (0x23)
{ 48, 255}, // 36 (0x24)
{ 56, 255}, // 37 (0x25)
{ 64, 255}, // 38 (0x26)
{ 73, 255}, // 39 (0x27)
{ 81, 255}, // 40 (0x28)
{ 90, 255}, // 41 (0x29)
{100, 255}, // 42 (0x2A)
{109, 255}, // 43 (0x2B)
{119, 255}, // 44 (0x2C)
{129, 255}, // 45 (0x2D)
{139, 255}, // 46 (0x2E)
{149, 255}, // 47 (0x2F)
{160, 255}, // 48 (0x30)
{171, 255}, // 49 (0x31)
{182, 255}, // 50 (0x32)
{193, 255}, // 51 (0x33)
{204, 255}, // 52 (0x34)
{216, 255}, // 53 (0x35)
{228, 255}, // 54 (0x36)
{240, 255}, // 55 (0x37)
{240, 255}, // 56 (0x38)
{240, 255}, // 57 (0x39)
{240, 255}, // 58 (0x3A)
{240, 255}, // 59 (0x3B)
{240, 255}, // 60 (0x3C)
{240, 255}, // 61 (0x3D)
{240, 255}, // 62 (0x3E)
{240, 255}, // 63 (0x3F)
};
void MinxLCD_SetContrast(uint8_t value)
{
MinxLCD.Contrast = value & 0x3F;
if (MinxLCD.MaxContrast) {
MinxLCD.Pixel0Intensity = 240;
MinxLCD.Pixel1Intensity = 255;
} else {
MinxLCD.Pixel0Intensity = MinxLCD_ContrastLvl[MinxLCD.Contrast][0];
MinxLCD.Pixel1Intensity = MinxLCD_ContrastLvl[MinxLCD.Contrast][1];
}
LCDDirty = MINX_DIRTYSCR;
}