Files
Main/brightness.cpp
2019-06-29 00:57:18 +08:00

253 lines
5.7 KiB
C++

/*
* 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 <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#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 void 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;
}