diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index 3d760b2..9cad680 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -40,6 +40,7 @@ + @@ -64,6 +65,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index 3ca656a..05f443b 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -77,6 +77,9 @@ Source Files + + Source Files + @@ -169,6 +172,9 @@ Header Files + + Header Files + diff --git a/battery.c b/battery.c new file mode 100644 index 0000000..4aaf9bf --- /dev/null +++ b/battery.c @@ -0,0 +1,212 @@ +/* + + * battery.c + * display pi-top battery status + * + * Copyright 2016, 2017 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 "battery.h" + +#define MAX_COUNT 20 // Maximum number of trials +#define SLEEP_TIME 500 // time between two i2cget in microsec + +/////////////////////////////////////////////////////////////////////// +// I2C definitions + +#define I2C_SLAVE 0x0703 +#define I2C_SMBUS 0x0720 /* SMBus-level access */ + +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +// SMBus transaction types + +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + +// SMBus messages + +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ + +// Structures used in the ioctl() calls + +union i2c_smbus_data +{ + uint8_t byte; + int8_t sbyte; + uint16_t word; + int16_t sword; + uint8_t block [I2C_SMBUS_BLOCK_MAX + 2]; // block [0] is used for length + one more for PEC +}; + +struct i2c_smbus_ioctl_data +{ + char read_write; + uint8_t command; + int size; + union i2c_smbus_data *data; +}; + +static int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + + args.read_write = rw; + args.command = command; + args.size = size; + args.data = data; + return ioctl (fd, I2C_SMBUS, &args); +} + +static int i2c_smbus_write_quick(int fd, uint8_t value) +{ + return i2c_smbus_access(fd, value, 0, I2C_SMBUS_QUICK, NULL); +} + +/////////////////////////////////////////////////////////////////////// + +static int i2c_handle = -1; + +static int smbus_open(int dev_address) +{ + // re-entry compatible + if(i2c_handle < 0) + { + int fd; + if ((fd = open ("/dev/i2c-1", O_RDWR)) < 0) + { + printf("Unable to open I2C device: %s\n", strerror(errno)); + return 0; + } + + if (ioctl (fd, I2C_SLAVE, dev_address) < 0) + { + printf("Unable to select I2C device: %s\n", strerror (errno)); + close(fd); + return 0; + } + + if (i2c_smbus_write_quick(fd, I2C_SMBUS_WRITE) < 0) + { + printf("Unable to detect SMBUS device: %s\n", strerror(errno)); + close(fd); + return 0; + } + + i2c_handle = fd; + } + return 1; +} + +static void smbus_close() +{ + if(i2c_handle > 0) close(i2c_handle); + i2c_handle = -1; +} + +static int smbus_get(int address, short *data) +{ + union i2c_smbus_data smbus_data; + + if (i2c_smbus_access (i2c_handle, I2C_SMBUS_READ, address, I2C_SMBUS_WORD_DATA, &smbus_data)) return 0; + + *data = smbus_data.sword; + return 1; +} + +static int getReg(int reg, int min, int max) +{ + int count = 0; + short value = -1; + while ((value == -1) && (count++ < MAX_COUNT)) + { + if (smbus_get(reg, &value)) + { + if ((value > max) || (value < min)) value = -1; // out of limits + } + usleep(SLEEP_TIME); + } + + return value; +} + +int getBattery(int quick, struct battery_data_t *data) +{ + /* + data->capacity = 80; + data->load_current = -520; + data->time = 312; + data->current = 2510; + data->voltage = 16200; + data->cell[0] = 4101; + data->cell[1] = 4102; + data->cell[2] = 4103; + data->cell[3] = 4104; + return 1; + */ + // don't try to check if no battery device is present + if (i2c_handle == -2) return 0; + + if (!smbus_open(0x0b)) + { + printf("No battery found.\n"); + i2c_handle = -2; + return 0; + } + + data->capacity = getReg(0x0D, 0, 100); + data->load_current = getReg(0x0A, -5000, 5000); + if (quick) return 1; + + data->time = 0; + if (data->load_current > 0) data->time = getReg(0x13, 1, 999); + if (data->load_current < -1) data->time = getReg(0x12, 1, 960); + + data->current = getReg(0x0F, 0, 5000); + data->voltage = getReg(0x09, 5000, 20000); + /* + data->cell[0] = getReg(0x3F, 1000, 5000); + data->cell[1] = getReg(0x3E, 1000, 5000); + data->cell[2] = getReg(0x3D, 1000, 5000); + data->cell[3] = getReg(0x3C, 1000, 5000); + */ + + return 1; +} diff --git a/battery.h b/battery.h new file mode 100644 index 0000000..1519617 --- /dev/null +++ b/battery.h @@ -0,0 +1,16 @@ +#ifndef __BATTERY_H__ +#define __BATTERY_H__ + +struct battery_data_t +{ + short load_current; + short capacity; + short current; + short time; + short voltage; + short cell[4]; +}; + +int getBattery(int quick, struct battery_data_t *data); + +#endif diff --git a/charrom.h b/charrom.h index 53c7508..b454315 100644 --- a/charrom.h +++ b/charrom.h @@ -38,7 +38,7 @@ Middle Dot */ // *character font -unsigned char charfont[128][8] = +unsigned char charfont[][8] = { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 0 [0x0] { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 }, // 1 [0x1] @@ -70,8 +70,8 @@ unsigned char charfont[128][8] = { 0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00 }, // 27 [0x1b] middle dot { 0x68,0x78,0x6b,0x0f,0x6b,0x78,0x68,0x00 }, // 28 [0x1c] ethernet { 0x02,0x09,0x25,0x95,0x95,0x25,0x09,0x02 }, // 29 [0x1d] wifi - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 30 [0x1e] - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 31 [0x1f] + { 0x00,0x90,0xD8,0x7C,0x3E,0x1B,0x09,0x00 }, // 30 [0x1e] charge + { 0x7E,0x72,0x73,0x73,0x73,0x72,0x7E,0x00 }, // 31 [0x1f] battery { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 32 [0x20] { 0x00,0x00,0x00,0x5F,0x5F,0x00,0x00,0x00 }, // 33 [0x21] { 0x00,0x03,0x03,0x00,0x03,0x03,0x00,0x00 }, // 34 [0x22] @@ -167,7 +167,24 @@ unsigned char charfont[128][8] = { 0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,0x00 }, // 124 [0x7c] { 0x00,0x41,0x41,0x77,0x3E,0x08,0x08,0x00 }, // 125 [0x7d] { 0x02,0x01,0x01,0x03,0x02,0x02,0x01,0x00 }, // 126 [0x7e] - { 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x00 } // 127 [0x7f] + { 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x00 }, // 127 [0x7f] + + //dotted frame + { 0x00,0x00,0x00,0xA8,0x00,0x08,0x00,0x08 }, // 128 [0x80] TL + { 0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08 }, // 129 [0x81] T/B + { 0x00,0x08,0x00,0xA8,0x00,0x00,0x00,0x00 }, // 130 [0x82] TR + { 0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x00 }, // 131 [0x83] L/R + { 0x00,0x08,0x00,0x0A,0x00,0x00,0x00,0x00 }, // 132 [0x84] BR + { 0x00,0x00,0x00,0x0A,0x00,0x08,0x00,0x08 }, // 133 [0x85] BL + + //solid frame + { 0x00,0x00,0x00,0xF8,0x08,0x08,0x08,0x08 }, // 134 [0x86] TL + { 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08 }, // 135 [0x87] T/B + { 0x08,0x08,0x08,0xF8,0x00,0x00,0x00,0x00 }, // 136 [0x88] TR + { 0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00 }, // 137 [0x89] L/R + { 0x08,0x08,0x08,0x0F,0x00,0x00,0x00,0x00 }, // 138 [0x8A] BR + { 0x00,0x00,0x00,0x0F,0x08,0x08,0x08,0x08 }, // 139 [0x8B] BL + }; #endif diff --git a/menu.c b/menu.c index 560d07c..510e1b3 100644 --- a/menu.c +++ b/menu.c @@ -52,6 +52,7 @@ along with this program. If not, see . #include "cfg.h" #include "input.h" #include "x86.h" +#include "battery.h" /*menu states*/ enum MENU @@ -524,6 +525,91 @@ char* getNet() return ifa ? host : 0; } +static long sysinfo_timer; +void infowrite(int pos, char* txt) +{ + char str[40]; + memset(str, 0x20, 29); + int len = strlen(txt); + if (len > 27) len = 27; + if(len) strncpy(str + 1+ ((27-len)/2), txt, len); + str[0] = 0x83; + str[28] = 0x83; + str[29] = 0; + OsdWrite(pos, str, 0, 0); +} + +void printSysInfo() +{ + if (!sysinfo_timer || CheckTimer(sysinfo_timer)) + { + sysinfo_timer = GetTimer(2000); + struct battery_data_t bat; + int hasbat = getBattery(0, &bat); + int n = 9; + + char str[40]; + OsdWrite(n++, "\x80\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x82", 0, 0); + if (!hasbat) + { + infowrite(n++, ""); + } + + memset(str, 0, sizeof(str)); + char *net = getNet(); + if (net) + { + str[strlen(str)] = 0x1b + netType; + strcat(str, " "); + } + strcat(str, net ? net : "No network"); + infowrite(n++, str); + + if (hasbat) + { + infowrite(n++, ""); + sprintf(str, "\x1F "); + if (bat.capacity == -1) strcat(str, "n/a"); + else sprintf(str + strlen(str), "%d%%", bat.capacity); + if (bat.current != -1) sprintf(str + strlen(str), " %dmAh", bat.current); + if (bat.voltage != -1) sprintf(str + strlen(str), " %d.%dV", bat.voltage / 1000, (bat.voltage / 100) % 10); + + infowrite(n++, str); + + str[0] = 0; + if (bat.load_current > 0) + { + sprintf(str + strlen(str), " \x12 %dmA", bat.load_current); + if (bat.time != -1) + { + if (bat.time < 90) sprintf(str + strlen(str), ", ETA: %dm", bat.time); + else sprintf(str + strlen(str), ", ETA: %dh%02dm", bat.time / 60, bat.time % 60); + } + } + else if (bat.load_current < -1) + { + sprintf(str + strlen(str), " \x13 %dmA", -bat.load_current); + if (bat.time != -1) + { + if (bat.time < 90) sprintf(str + strlen(str), ", ETA: %dm", bat.time); + else sprintf(str + strlen(str), ", ETA: %dh%02dm", bat.time / 60, bat.time % 60); + } + } + else + { + strcat(str, "Not charging"); + } + infowrite(n++, str); + } + else + { + infowrite(n++, ""); + infowrite(n++, ""); + } + OsdWrite(n++, "\x85\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x84", 0, 0); + } +} + void HandleUI(void) { switch (user_io_core_type()) @@ -621,15 +707,6 @@ void HandleUI(void) case KEY_MINUS: // -/_ minus = true; break; -/* - case 0x01: // 1: 1280x720 mode - if (user_io_osd_is_visible) cfg.video_mode = 0; - break; - - case 0x02: // 2: 1280x1024 mode - if (user_io_osd_is_visible) cfg.video_mode = 1; - break; -*/ } if (menu || select || up || down || left || right) @@ -1146,21 +1223,18 @@ void HandleUI(void) parentstate = MENU_8BIT_SYSTEM1; if (OsdIsBig) OsdWrite(0, "", 0, 0); OsdWrite(OsdIsBig ? 1 : 0, " Firmware & Core \x16", menusub == 0, 0); - if(OsdIsBig) OsdWrite(2, "", 0, 0); - OsdWrite(OsdIsBig ? 3 : 1, " Define joystick buttons", menusub == 1, 0); - OsdWrite(OsdIsBig ? 4 : 2, "", 0, 0); - if (OsdIsBig) OsdWrite(5, "", 0, 0); - OsdWrite(OsdIsBig ? 6 : 3, m ? " Reset" : " Reset settings", menusub == 3, !has_menu()); + OsdWrite(OsdIsBig ? 2 : 1, " Define joystick buttons \x16", menusub == 1, 0); + OsdWrite(OsdIsBig ? 3 : 2, "", 0, 0); + OsdWrite(OsdIsBig ? 4 : 3, m ? " Reset" : " Reset settings", menusub == 3, !has_menu()); if (m) - OsdWrite(OsdIsBig ? 7 : 4, "", 0, 0); + OsdWrite(OsdIsBig ? 5 : 4, "", 0, 0); else - OsdWrite(OsdIsBig ? 7 : 4, " Save settings", menusub == 4, !has_menu()); // Minimig saves settings elsewhere - if (OsdIsBig) OsdWrite(8, "", 0, 0); - OsdWrite(OsdIsBig ? 9 : 5, " Cold reset", menusub == (5 - m), 0); - if (OsdIsBig) OsdWrite(10, "", 0, 0); - OsdWrite(OsdIsBig ? 11 : 6, " About", menusub == (6 - m), 0); - if(OsdIsBig) for (int i = 12; i < OsdGetSize() - 1; i++) OsdWrite(i, "", 0, 0); + OsdWrite(OsdIsBig ? 5 : 4, " Save settings", menusub == 4, !has_menu()); // Minimig saves settings elsewhere + if (OsdIsBig) OsdWrite(6, "", 0, 0); + OsdWrite(OsdIsBig ? 7 : 5, " Cold reset", menusub == (5 - m), 0); + OsdWrite(OsdIsBig ? 8 : 6, " About", menusub == (6 - m), 0); OsdWrite(OsdGetSize() - 1, STD_EXIT, menusub == (7 - m), 0); + sysinfo_timer = 0; break; case MENU_8BIT_SYSTEM2: @@ -1274,6 +1348,8 @@ void HandleUI(void) } } } + + if (OsdIsBig) printSysInfo(); break; case MENU_JOYDIGMAP: @@ -3011,16 +3087,12 @@ void HandleUI(void) } } OsdWrite(5, "", 0, 0); - OsdWrite(6, " NOTE:", 0, 0); - OsdWrite(7, " USB storage takes longer", 0, 0); - OsdWrite(8, " time to initialize", 0, 0); - OsdWrite(9, " upon cold boot.", 0, 0); - OsdWrite(10, " Use OSD or USER button to", 0, 0); - OsdWrite(11, " cancel USB waiting.", 0, 0); - OsdWrite(12, "", 0, 0); - OsdWrite(13, "", 0, 0); - OsdWrite(14, " Remap keyboard", menusub == 1, 0); - OsdWrite(15, " Define joystick buttons", menusub == 2, 0); + OsdWrite(6, " Remap keyboard \x16", menusub == 1, 0); + OsdWrite(7, " Define joystick buttons \x16", menusub == 2, 0); + OsdWrite(8, "", 0, 0); + OsdWrite(15, "", 0, 0); + sysinfo_timer = 0; + menustate = MENU_STORAGE; } else @@ -3096,6 +3168,7 @@ void HandleUI(void) break; } } + printSysInfo(); break; case MENU_KBDMAP: @@ -3223,23 +3296,15 @@ void HandleUI(void) rtc_timer = GetTimer(1000); char str[64] = { 0 }; sprintf(str, " MiSTer "); - char *net = getNet(); - if (menustate == MENU_STORAGE) + time_t t = time(NULL); + struct tm tm = *localtime(&t); + if (tm.tm_year >= 117) { - strcat(str, net ? net : " no network"); - } - else - { - time_t t = time(NULL); - struct tm tm = *localtime(&t); - if (tm.tm_year >= 117) - { - strftime(str + strlen(str), sizeof(str) - 1 - strlen(str), "%b %d %a %H:%M:%S", &tm); - } + strftime(str + strlen(str), sizeof(str) - 1 - strlen(str), "%b %d %a %H:%M:%S", &tm); } - if (net) str[9] = 0x1b + netType; + if (getNet()) str[9] = 0x1b + netType; OsdWrite(16, "", 1, 0); OsdWrite(17, str, 1, 0);