144 lines
4.5 KiB
C
144 lines
4.5 KiB
C
/*
|
|
* sppro-console - Linux serial-console dashboard for the Selectronic SP PRO.
|
|
*
|
|
* Opens the SP PRO serial port (57600 8N1), logs in, then polls the key
|
|
* registers on an interval and prints a refreshing table. Demonstrates wiring
|
|
* the portable core (src/sppro.c) to a real transport via termios.
|
|
*
|
|
* make host
|
|
* ./build/sppro-console /dev/ttyUSB0 [password] [interval_seconds]
|
|
*
|
|
* The password is the SP PRO serial-port password (Settings -> Comms). Pass ""
|
|
* (or omit) if no password is configured. It may also be set via SPPRO_PASSWORD.
|
|
*/
|
|
#define _DEFAULT_SOURCE /* cfmakeraw, CRTSCTS, sleep() under -std=c99 */
|
|
|
|
#include "sppro.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
/* ----- termios transport -------------------------------------------------- */
|
|
|
|
static int serial_read(void *ctx, uint8_t *buf, size_t len)
|
|
{
|
|
int fd = *(int *)ctx;
|
|
ssize_t n = read(fd, buf, len);
|
|
if (n < 0) {
|
|
if (errno == EINTR || errno == EAGAIN) return 0;
|
|
return -1;
|
|
}
|
|
return (int)n; /* 0 on VTIME timeout */
|
|
}
|
|
|
|
static int serial_write(void *ctx, const uint8_t *buf, size_t len)
|
|
{
|
|
int fd = *(int *)ctx;
|
|
ssize_t n = write(fd, buf, len);
|
|
if (n < 0) {
|
|
if (errno == EINTR || errno == EAGAIN) return 0;
|
|
return -1;
|
|
}
|
|
return (int)n;
|
|
}
|
|
|
|
static int serial_open(const char *path)
|
|
{
|
|
struct termios tio;
|
|
int fd = open(path, O_RDWR | O_NOCTTY);
|
|
if (fd < 0) { perror("open"); return -1; }
|
|
|
|
if (tcgetattr(fd, &tio) != 0) { perror("tcgetattr"); close(fd); return -1; }
|
|
cfmakeraw(&tio);
|
|
cfsetispeed(&tio, B57600);
|
|
cfsetospeed(&tio, B57600);
|
|
tio.c_cflag |= (CLOCAL | CREAD);
|
|
tio.c_cflag &= ~CSTOPB; /* 1 stop bit */
|
|
tio.c_cflag &= ~PARENB; /* no parity */
|
|
tio.c_cflag &= ~CRTSCTS; /* no hardware flow control */
|
|
tio.c_cc[VMIN] = 0; /* non-blocking with timeout */
|
|
tio.c_cc[VTIME] = 2; /* 0.2s read timeout */
|
|
if (tcsetattr(fd, TCSANOW, &tio) != 0) { perror("tcsetattr"); close(fd); return -1; }
|
|
tcflush(fd, TCIOFLUSH);
|
|
return fd;
|
|
}
|
|
|
|
/* ----- dashboard ---------------------------------------------------------- */
|
|
|
|
/* Registers shown on the dashboard (names must exist in SPPRO_REGISTERS). */
|
|
static const char *const DASHBOARD[] = {
|
|
"BatteryVolts", "BattSocPercent", "BatteryTemperature", "DCBatteryPower",
|
|
"LoadAcPower", "CombinedKacoAcPowerHiRes", "ACGeneratorPower",
|
|
"Shunt1Power", "Shunt2Power",
|
|
"DCkWhInToday", "DCkWhOutToday", "ACLoadkWhTotalAcc", "TotalKacokWhTotalAcc",
|
|
};
|
|
|
|
static void print_dashboard(const sppro_transport_t *t, const sppro_scales_t *scales)
|
|
{
|
|
size_t i;
|
|
printf("\033[2J\033[H"); /* clear screen, home cursor */
|
|
printf("== Selectronic SP PRO ==\n\n");
|
|
for (i = 0; i < sizeof(DASHBOARD) / sizeof(DASHBOARD[0]); i++) {
|
|
const sppro_reg_t *reg = sppro_reg_by_name(DASHBOARD[i]);
|
|
double value;
|
|
int rc;
|
|
if (!reg) continue;
|
|
rc = sppro_session_read(t, reg, scales, &value);
|
|
if (rc != SPPRO_OK) {
|
|
printf(" %-26s (read error %d)\n", reg->description, rc);
|
|
continue;
|
|
}
|
|
if (reg->conv == SPPRO_C_SHUNT_NAME)
|
|
printf(" %-26s %12s\n", reg->description, sppro_shunt_name((int)value));
|
|
else
|
|
printf(" %-26s %12.2f %-3s\n", reg->description, value, reg->units);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const char *path = (argc > 1) ? argv[1] : "/dev/ttyUSB0";
|
|
const char *password = (argc > 2) ? argv[2] : getenv("SPPRO_PASSWORD");
|
|
int interval = (argc > 3) ? atoi(argv[3]) : 5;
|
|
int fd, rc;
|
|
sppro_transport_t t;
|
|
sppro_scales_t scales;
|
|
|
|
if (!password) password = "";
|
|
if (interval < 1) interval = 1;
|
|
|
|
fd = serial_open(path);
|
|
if (fd < 0) return 1;
|
|
|
|
t.read = serial_read;
|
|
t.write = serial_write;
|
|
t.ctx = &fd;
|
|
|
|
rc = sppro_session_login(&t, password);
|
|
if (rc != SPPRO_OK) {
|
|
fprintf(stderr, "login failed (%d) - check cabling and serial password\n", rc);
|
|
close(fd);
|
|
return 1;
|
|
}
|
|
rc = sppro_session_read_scales(&t, &scales);
|
|
if (rc != SPPRO_OK) {
|
|
fprintf(stderr, "could not read scale factors (%d)\n", rc);
|
|
close(fd);
|
|
return 1;
|
|
}
|
|
|
|
for (;;) {
|
|
print_dashboard(&t, &scales);
|
|
sleep((unsigned)interval);
|
|
}
|
|
|
|
close(fd); /* not reached */
|
|
return 0;
|
|
}
|