From 1cc907c276755902c8dc7fb78faa583f0c7952a9 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Sun, 11 Feb 2018 02:48:18 +0800 Subject: [PATCH] Brightness control for pi-top. --- MiSTer.vcxproj | 2 + MiSTer.vcxproj.filters | 6 + brightness.c | 252 +++++++++++++++++++++++++++++++++++++++++ brightness.h | 11 ++ user_io.c | 19 ++++ 5 files changed, 290 insertions(+) create mode 100644 brightness.c create mode 100644 brightness.h diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index b84e58f9..3d760b25 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -40,6 +40,7 @@ + @@ -63,6 +64,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index dc884086..3ca656a1 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -74,6 +74,9 @@ Source Files + + Source Files + @@ -163,6 +166,9 @@ Header Files + + Header Files + diff --git a/brightness.c b/brightness.c new file mode 100644 index 00000000..3b6ee0f7 --- /dev/null +++ b/brightness.c @@ -0,0 +1,252 @@ +/* + * brightness.c + * + * Copyright 2016 rricharz + * MiSTer port. Copyright 2018 Sorgelig + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "brightness.h" + +#define MAXCOUNT 10 // maximum number of spi transfer attemps + +#define LIDBITMASK 0x04 +#define SCREENOFFMASK 0x02 +#define PARITYMASK 0x80 +#define BRIGHTNESSMASK 0x78 +#define SHUTDOWNMASK 0X01 + +/////////////////////////////////////////////////// + +static uint32_t spiSpeed; +static int spiFd = -1; + +static const uint8_t spiBPW = 8; +static const uint16_t spiDelay = 0; + +static int spi_rw(unsigned char *data, int len) +{ + struct spi_ioc_transfer spi; + + memset (&spi, 0, sizeof (spi)); + + spi.tx_buf = (unsigned long)data; + spi.rx_buf = (unsigned long)data; + spi.len = len; + spi.delay_usecs = spiDelay; + spi.speed_hz = spiSpeed; + spi.bits_per_word = spiBPW; + + return ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi); +} + +static int spi_open(int speed, int mode) +{ + int fd ; + mode &= 3; // Mode is 0, 1, 2 or 3 + + if ((fd = open ("/dev/spidev32766.0", O_RDWR)) < 0) + { + printf("Unable to open SPI device: %s\n", strerror (errno)); + return -1; + } + + if (ioctl (fd, SPI_IOC_WR_MODE, &mode) >= 0) + { + if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) >= 0) + { + if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) >= 0) + { + spiSpeed = speed; + spiFd = fd; + return fd; + } + else + { + printf ("SPI Speed Change failure: %s\n", strerror (errno)); + } + } + else + { + printf ("SPI BPW Change failure: %s\n", strerror (errno)); + } + } + else + { + printf ("SPI Mode Change failure: %s\n", strerror (errno)); + } + + close(fd); + fd = -1; + return -1; +} + +static int spi_close() +{ + if(spiFd >= 0) close(spiFd); + spiFd = -1; +} + +/////////////////////////////////////////////////// + +static int lidbit; +static int screenoffbit; +static int parity; +static int brightness = 6; +static int shutdown; + +////////////////////////////// +// Calclate the parity of bits 0 - 6 +static int parity7(unsigned char data) +{ + int i; + int p = 0; + for (i = 0; i < 7; i++) { + if (data & 1) p = !p; + data = data >> 1; + } + return p; +} + +/////////////////////////////// +// analyze data byte and set global variables +// return 1 of parity is ok +// Sending: bit 8 = parity of bit 1-7 +static int analyze(unsigned char data) +{ + lidbit = (data & LIDBITMASK) != 0; + screenoffbit = (data & SCREENOFFMASK) != 0; + parity = (data & PARITYMASK) != 0; + brightness = (data & BRIGHTNESSMASK) >> 3; + shutdown = (data & SHUTDOWNMASK) != 0; + + // printf("lid = %d, screen = %d, parity = %d, shutdown = %d, brightness = %d\n", lidbit, screenoffbit, parity, shutdown, brightness); + + return (parity7(data) == parity); +} + +/////////////// +// Calculate data byte using global variables +// Set brightness and status parity bits +// Receiving: bit 8 = brightness parity, bit 3 = status parity +static int calculate() +{ + int data = brightness << 3; + if (parity7(brightness)) data += PARITYMASK; + if (shutdown) data += SHUTDOWNMASK; + if (screenoffbit) data += SCREENOFFMASK; + if (parity7(data & 3)) data += LIDBITMASK; // parity ofthe two state bits + return data; +} + +void setBrightness(int cmd, int val) +{ + unsigned char data, new_data; + int count, ok; + + if (spi_open(9600, 0) < 0) + { + printf("Cannot initialize spi driver\n"); + return; + } + + // send 0xFF and receive current status of pi-top-hub + count = 0; + data = 0xff; + printf("Brighntess sending: 0x%X\n", data); + do + { + data = 0xff; + ok = spi_rw(&data, 1); + if (ok) ok = analyze(data); + } + while ((!ok) && (count++ < MAXCOUNT)); + // printf("count = %d\n", count); + + if (ok) + { + printf("Brighntess receiving: 0x%X - ", data); + printf("Current brightness = %d, ", brightness); + //force to 0 as set to 1 if rebooted while in screenbitoff=0 + //the state is stored on pi-top-hub, but isn't reinitialised on reboot + screenoffbit=0; + if(cmd == BRIGHTNESS_UP) + { + brightness++; + } + else if (cmd == BRIGHTNESS_DOWN) + { + brightness--; + } + else if (cmd == BRIGHTNESS_SET) + { + if(!val) screenoffbit=1; + else screenoffbit = 0; + brightness = val; + } + + if (brightness < 1) brightness = 1; + if (brightness > 10) brightness = 10; + + printf("Requested brightness = %d, ", brightness); + printf("Requested off = %d\n", screenoffbit); + + // calculate data to send + shutdown = 0; + new_data = calculate(); + + // send new data until accepted + count = 0; + data = new_data; + printf("Brighntess sending: 0x%X\n", data); + do + { + data = new_data; + ok = spi_rw(&data, 1); + if (ok) ok = (data & BRIGHTNESSMASK) == (new_data & BRIGHTNESSMASK); + } + while ((!ok) && (count++ < MAXCOUNT)); + + // printf("count = %d\n", count); + if (ok) + { + printf("Brighntess receiving: 0x%X - ", data); + printf("New brightness = %d\n", brightness); + } + } + else printf("Reading current brightness not successful\n"); + + spi_close(); +} + +int getBrightness() +{ + if (screenoffbit) return 0; + return brightness; +} diff --git a/brightness.h b/brightness.h new file mode 100644 index 00000000..cb69188b --- /dev/null +++ b/brightness.h @@ -0,0 +1,11 @@ +#ifndef __BRIGHTNESS_H__ +#define __BRIGHTNESS_H__ + +#define BRIGHTNESS_SET 0 +#define BRIGHTNESS_UP 1 +#define BRIGHTNESS_DOWN 2 + +void setBrightness(int cmd, int val); +int getBrightness(); + +#endif diff --git a/user_io.c b/user_io.c index d09c03c4..0760c780 100644 --- a/user_io.c +++ b/user_io.c @@ -26,6 +26,7 @@ #include "minimig_boot.h" #include "minimig_fdd.h" #include "minimig_hdd.h" +#include "brightness.h" #define BREAK 0x8000 @@ -1850,6 +1851,24 @@ void user_io_kbd(uint16_t key, int press) } } else + if (key == 0xBE) + { + if (press) + { + setBrightness(BRIGHTNESS_DOWN, 0); + vol_set_timeout = GetTimer(1000); + } + } + else + if (key == 0xBF) + { + if (press) + { + setBrightness(BRIGHTNESS_UP, 0); + vol_set_timeout = GetTimer(1000); + } + } + else if ((core_type == CORE_TYPE_MINIMIG2) || (core_type == CORE_TYPE_MIST) || (core_type == CORE_TYPE_ARCHIE) ||