1 Commits

Author SHA1 Message Date
Konrad Dybcio
672eeb89c3 Add protocol.md 2024-04-25 17:20:17 +02:00
16 changed files with 177 additions and 251 deletions

View File

@@ -43,15 +43,10 @@ jobs:
# Fails on configure on GCC and clang (process restrictions?) # Fails on configure on GCC and clang (process restrictions?)
# - fedora:rawhide # - fedora:rawhide
- fedora:latest - fedora:latest
- fedora:42
- fedora:41
- fedora:40
- fedora:39 - fedora:39
- fedora:38 - fedora:38
- fedora:37 - fedora:37
- ubuntu:latest - ubuntu:lunar # EOL 01.2024
- ubuntu:oracular
- ubuntu:noble
- ubuntu:jammy - ubuntu:jammy
- ubuntu:focal - ubuntu:focal
# On Ubuntu Bionic the Meson doesn't support feature options # On Ubuntu Bionic the Meson doesn't support feature options
@@ -183,7 +178,7 @@ jobs:
echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH" echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
- name: Git checkout - name: Git checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Install additional packages - name: Install additional packages
run: | run: |

View File

@@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v2

View File

@@ -27,7 +27,7 @@ jobs:
steps: steps:
- name: Git checkout - name: Git checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Install additional packages - name: Install additional packages
run: | run: |

8
README
View File

@@ -19,13 +19,11 @@ from sandbox/cdba/cdba-server. Available devices are read from $HOME/.cdba
= Client side = Client side
The client is invoked as: The client is invoked as:
cdba -b <board> [-h <host>] [-c <power-cylce-count>] [-s <status-fifo>] [boot.img] cdba -b <board> -h <host> [-c <power-cylce-count>] [-s <status-fifo>] boot.img
<host> will be connected to using ssh and <board> will be selected for <host> will be connected to using ssh and <board> will be selected for
operation. As the board's fastboot interface shows up the given boot.img operation. As the board's fastboot interface shows up the given boot.img will
will be transfered and booted on the device. If <host> is omitted, the be transfered and booted on the device.
cdba-server is started locally without using ssh. If [boot.img] is omitted,
"fastboot continue" is run to boot the installed operating system.
The board will execute until the key sequence ^A q is invoked or the board The board will execute until the key sequence ^A q is invoked or the board
outputs a sequence of 20 ~ (tilde) chards in a row. outputs a sequence of 20 ~ (tilde) chards in a row.

View File

@@ -59,10 +59,10 @@ static void msg_select_board(const void *param)
if (!selected_device) { if (!selected_device) {
fprintf(stderr, "failed to open %s\n", (const char *)param); fprintf(stderr, "failed to open %s\n", (const char *)param);
watch_quit(); watch_quit();
} else {
device_fastboot_open(selected_device, &fastboot_ops);
} }
device_fastboot_open(selected_device, &fastboot_ops);
cdba_send(MSG_SELECT_BOARD); cdba_send(MSG_SELECT_BOARD);
} }
@@ -99,28 +99,6 @@ static void msg_fastboot_continue(void)
cdba_send(MSG_FASTBOOT_CONTINUE); cdba_send(MSG_FASTBOOT_CONTINUE);
} }
static void msg_key_release(void *data)
{
int key = (int)(uintptr_t)data;
device_key(selected_device, key, false);
}
static void msg_key_press(const void *data, size_t len)
{
const struct key_press *press = data;
if (len != sizeof(*press))
return;
if (press->state == KEY_PRESS_PULSE) {
device_key(selected_device, press->key, true);
watch_timer_add(100, msg_key_release, (void*)(uintptr_t)press->key);
} else {
device_key(selected_device, press->key, !!press->state);
}
}
void cdba_send_buf(int type, size_t len, const void *buf) void cdba_send_buf(int type, size_t len, const void *buf)
{ {
struct msg msg = { struct msg msg = {
@@ -207,9 +185,6 @@ static int handle_stdin(int fd, void *buf)
case MSG_FASTBOOT_CONTINUE: case MSG_FASTBOOT_CONTINUE:
msg_fastboot_continue(); msg_fastboot_continue();
break; break;
case MSG_KEY_PRESS:
msg_key_press(msg->data, msg->len);
break;
default: default:
fprintf(stderr, "unk %d len %d\n", msg->type, msg->len); fprintf(stderr, "unk %d len %d\n", msg->type, msg->len);
exit(1); exit(1);
@@ -226,11 +201,6 @@ static void sigpipe_handler(int signo)
watch_quit(); watch_quit();
} }
static void atexit_handler(void)
{
syslog(LOG_INFO, "exiting");
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int flags; int flags;
@@ -246,8 +216,7 @@ int main(int argc, char **argv)
if (!username) if (!username)
username = "nobody"; username = "nobody";
openlog("cdba-server", LOG_PID, LOG_DAEMON); openlog("cdba-server", 0, LOG_DAEMON);
atexit(atexit_handler);
ret = device_parser(".cdba"); ret = device_parser(".cdba");
if (ret) { if (ret) {

73
cdba.c
View File

@@ -103,13 +103,8 @@ static int fork_ssh(const char *host, const char *cmd, int *pipes)
close(piped_stderr[0]); close(piped_stderr[0]);
close(piped_stderr[1]); close(piped_stderr[1]);
if (host) { execl("/usr/bin/ssh", "ssh", host, cmd, NULL);
execlp("ssh", "ssh", host, cmd, NULL); err(1, "launching ssh failed");
err(1, "launching ssh failed");
} else {
execlp(cmd, cmd, NULL);
err(1, "launching cdba-server failed");
}
default: default:
close(piped_stdin[0]); close(piped_stdin[0]);
close(piped_stdout[1]); close(piped_stdout[1]);
@@ -148,25 +143,8 @@ static int cdba_send_buf(int fd, int type, size_t len, const void *buf)
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
} }
static int cdba_send_key(int fd, int key, uint8_t state)
{
struct key_press press = {
.key = key,
.state = state,
};
return cdba_send_buf(fd, MSG_KEY_PRESS, sizeof(press), &press);
}
static int cdba_toggle_key(int fd, int key, bool key_state[DEVICE_KEY_COUNT])
{
key_state[key] = !key_state[key];
return cdba_send_key(fd, key, key_state[key]);
}
static int tty_callback(int *ssh_fds) static int tty_callback(int *ssh_fds)
{ {
static bool key_state[DEVICE_KEY_COUNT];
static const char ctrl_a = 0x1; static const char ctrl_a = 0x1;
static bool special; static bool special;
char buf[32]; char buf[32];
@@ -206,18 +184,6 @@ static int tty_callback(int *ssh_fds)
case 'B': case 'B':
cdba_send(ssh_fds[0], MSG_SEND_BREAK); cdba_send(ssh_fds[0], MSG_SEND_BREAK);
break; break;
case 'o':
cdba_send_key(ssh_fds[0], DEVICE_KEY_POWER, KEY_PRESS_PULSE);
break;
case 'O':
cdba_toggle_key(ssh_fds[0], DEVICE_KEY_POWER, key_state);
break;
case 'f':
cdba_send_key(ssh_fds[0], DEVICE_KEY_FASTBOOT, KEY_PRESS_PULSE);
break;
case 'F':
cdba_toggle_key(ssh_fds[0], DEVICE_KEY_FASTBOOT, key_state);
break;
} }
special = false; special = false;
@@ -567,11 +533,13 @@ static int handle_message(struct circ_buf *buf)
} else { } else {
quit = true; quit = true;
} }
} else {
fastboot_done = true;
// printf("======================================== MSG_FASTBOOT_PRESENT(off)\n");
} }
break; break;
case MSG_FASTBOOT_DOWNLOAD: case MSG_FASTBOOT_DOWNLOAD:
// printf("======================================== MSG_FASTBOOT_DOWNLOAD\n"); // printf("======================================== MSG_FASTBOOT_DOWNLOAD\n");
fastboot_done = true;
break; break;
case MSG_FASTBOOT_BOOT: case MSG_FASTBOOT_BOOT:
// printf("======================================== MSG_FASTBOOT_BOOT\n"); // printf("======================================== MSG_FASTBOOT_BOOT\n");
@@ -588,7 +556,6 @@ static int handle_message(struct circ_buf *buf)
break; break;
case MSG_FASTBOOT_CONTINUE: case MSG_FASTBOOT_CONTINUE:
// printf("======================================== MSG_FASTBOOT_CONTINUE\n"); // printf("======================================== MSG_FASTBOOT_CONTINUE\n");
fastboot_done = true;
break; break;
default: default:
fprintf(stderr, "unk %d len %d\n", msg->type, msg->len); fprintf(stderr, "unk %d len %d\n", msg->type, msg->len);
@@ -617,12 +584,12 @@ static void usage(void)
{ {
extern const char *__progname; extern const char *__progname;
fprintf(stderr, "usage: %s -b <board> [-h <host>] [-t <timeout>] " fprintf(stderr, "usage: %s -b <board> -h <host> [-t <timeout>] "
"[-T <inactivity-timeout>] [boot.img]\n", "[-T <inactivity-timeout>] <boot.img>\n",
__progname); __progname);
fprintf(stderr, "usage: %s -i -b <board> [-h <host>]\n", fprintf(stderr, "usage: %s -i -b <board> -h <host>\n",
__progname); __progname);
fprintf(stderr, "usage: %s -l [-h <host>]\n", fprintf(stderr, "usage: %s -l -h <host>\n",
__progname); __progname);
exit(1); exit(1);
} }
@@ -638,7 +605,6 @@ int main(int argc, char **argv)
bool power_cycle_on_timeout = true; bool power_cycle_on_timeout = true;
struct timeval timeout_inactivity_tv; struct timeval timeout_inactivity_tv;
struct timeval timeout_total_tv; struct timeval timeout_total_tv;
struct timeval *timeout = NULL;
struct termios *orig_tios; struct termios *orig_tios;
const char *server_binary = "cdba-server"; const char *server_binary = "cdba-server";
const char *status_pipe = NULL; const char *status_pipe = NULL;
@@ -702,6 +668,9 @@ int main(int argc, char **argv)
} }
} }
if (!host)
usage();
switch (verb) { switch (verb) {
case CDBA_BOOT: case CDBA_BOOT:
if (optind > argc || !board) if (optind > argc || !board)
@@ -739,8 +708,6 @@ int main(int argc, char **argv)
timeout_total_tv = get_timeout(timeout_total); timeout_total_tv = get_timeout(timeout_total);
timeout_inactivity_tv = get_timeout(timeout_inactivity); timeout_inactivity_tv = get_timeout(timeout_inactivity);
if (timeout_total || timeout_inactivity)
timeout = &tv;
while (!quit) { while (!quit) {
if (received_power_off || reached_timeout) { if (received_power_off || reached_timeout) {
@@ -778,16 +745,14 @@ int main(int argc, char **argv)
if (!list_empty(&work_items)) if (!list_empty(&work_items))
FD_SET(ssh_fds[0], &wfds); FD_SET(ssh_fds[0], &wfds);
if (timeout) { gettimeofday(&now, NULL);
gettimeofday(&now, NULL); if (timeout_inactivity && timercmp(&timeout_inactivity_tv, &timeout_total_tv, <)) {
if (timeout_inactivity && (!timeout_total || timersub(&timeout_inactivity_tv, &now, &tv);
timercmp(&timeout_inactivity_tv, &timeout_total_tv, <))) { } else {
timersub(&timeout_inactivity_tv, &now, timeout); timersub(&timeout_total_tv, &now, &tv);
} else {
timersub(&timeout_total_tv, &now, timeout);
}
} }
ret = select(nfds + 1, &rfds, &wfds, NULL, timeout);
ret = select(nfds + 1, &rfds, &wfds, NULL, &tv);
#if 0 #if 0
printf("select: %d (%c%c%c)\n", ret, FD_ISSET(STDIN_FILENO, &rfds) ? 'X' : '-', printf("select: %d (%c%c%c)\n", ret, FD_ISSET(STDIN_FILENO, &rfds) ? 'X' : '-',
FD_ISSET(ssh_fds[1], &rfds) ? 'X' : '-', FD_ISSET(ssh_fds[1], &rfds) ? 'X' : '-',

18
cdba.h
View File

@@ -31,24 +31,6 @@ enum {
MSG_LIST_DEVICES, MSG_LIST_DEVICES,
MSG_BOARD_INFO, MSG_BOARD_INFO,
MSG_FASTBOOT_CONTINUE, MSG_FASTBOOT_CONTINUE,
MSG_KEY_PRESS,
};
struct key_press {
uint8_t key;
uint8_t state;
} __packed;
enum {
DEVICE_KEY_FASTBOOT,
DEVICE_KEY_POWER,
DEVICE_KEY_COUNT
};
enum {
KEY_PRESS_RELEASE,
KEY_PRESS_PRESS,
KEY_PRESS_PULSE,
}; };
#endif #endif

View File

@@ -73,32 +73,3 @@ devices:
power: power:
interface: D interface: D
line: 6 line: 6
- board: myboard-5
name: "My Board 5"
description: |
My super awesome board Number 5
console: /dev/ttyABC1
fastboot: cacafada
ftdi_gpio:
vendor: "0x0403"
product: "0x6011"
index: 0
power:
interface: B
line: 1
active_low: true
fastboot_key:
interface: B
line: 0
active_low: true
power_key:
interface: B
line: 2
usb0_disconnect:
interface: C
line: 7
active_low: true
usb1_disconnect:
interface: A
line: 4
active_low: true

View File

@@ -64,21 +64,15 @@ static void device_lock(struct device *device)
if (fd < 0) if (fd < 0)
err(1, "failed to open lockfile %s", lock); err(1, "failed to open lockfile %s", lock);
while (1) { n = flock(fd, LOCK_EX | LOCK_NB);
char c; if (!n)
return;
n = flock(fd, LOCK_EX | LOCK_NB); warnx("board is in use, waiting...");
if (!n)
return;
warnx("board is in use, waiting..."); n = flock(fd, LOCK_EX);
if (n < 0)
sleep(3); err(1, "failed to lock lockfile %s", lock);
/* check that connection isn't gone */
if (read(STDIN_FILENO, &c, 1) == 0)
errx(1, "connection is gone");
}
} }
static bool device_check_access(struct device *device, static bool device_check_access(struct device *device,
@@ -163,7 +157,7 @@ static void device_impl_power(struct device *device, bool on)
device_control(device, power, on); device_control(device, power, on);
} }
void device_key(struct device *device, int key, bool asserted) static void device_key(struct device *device, int key, bool asserted)
{ {
if (device_has_control(device, key)) if (device_has_control(device, key))
device_control(device, key, key, asserted); device_control(device, key, key, asserted);
@@ -285,7 +279,7 @@ void device_usb(struct device *device, bool on)
{ {
if (device->ppps_path) if (device->ppps_path)
ppps_power(device, on); ppps_power(device, on);
if (device_has_control(device, usb)) else if (device_has_control(device, usb))
device_control(device, usb, on); device_control(device, usb, on);
} }

View File

@@ -2,7 +2,6 @@
#define __DEVICE_H__ #define __DEVICE_H__
#include <termios.h> #include <termios.h>
#include "cdba.h"
#include "list.h" #include "list.h"
struct cdb_assist; struct cdb_assist;
@@ -77,7 +76,6 @@ struct device *device_open(const char *board,
const char *username); const char *username);
void device_close(struct device *dev); void device_close(struct device *dev);
int device_power(struct device *device, bool on); int device_power(struct device *device, bool on);
void device_key(struct device *device, int key, bool asserted);
void device_status_enable(struct device *device); void device_status_enable(struct device *device);
void device_usb(struct device *device, bool on); void device_usb(struct device *device, bool on);
@@ -95,6 +93,11 @@ void device_info(const char *username, const void *data, size_t dlen);
void device_fastboot_continue(struct device *device); void device_fastboot_continue(struct device *device);
bool device_is_running(struct device *device); bool device_is_running(struct device *device);
enum {
DEVICE_KEY_FASTBOOT,
DEVICE_KEY_POWER,
};
extern const struct control_ops alpaca_ops; extern const struct control_ops alpaca_ops;
extern const struct control_ops cdb_assist_ops; extern const struct control_ops cdb_assist_ops;
extern const struct control_ops conmux_ops; extern const struct control_ops conmux_ops;

View File

@@ -22,11 +22,6 @@ static void nextsym(struct device_parser *dp)
{ {
if (!yaml_parser_parse(&dp->parser, &dp->event)) { if (!yaml_parser_parse(&dp->parser, &dp->event)) {
fprintf(stderr, "device parser: error %u\n", dp->parser.error); fprintf(stderr, "device parser: error %u\n", dp->parser.error);
fprintf(stderr,
"device parser: index %zu, line %zu, column %zu\n",
dp->parser.context_mark.index,
dp->parser.context_mark.line,
dp->parser.context_mark.column);
exit(1); exit(1);
} }
} }
@@ -48,33 +43,6 @@ int device_parser_accept(struct device_parser *dp, int type,
} }
} }
void decode_yaml_type_error(struct device_parser *dp, int type)
{
char event_type[11][26] = {
"YAML_NO_EVENT",
"YAML_STREAM_START_EVENT",
"YAML_STREAM_END_EVENT",
"YAML_DOCUMENT_START_EVENT",
"YAML_DOCUMENT_END_EVENT",
"YAML_ALIAS_EVENT",
"YAML_SCALAR_EVENT",
"YAML_SEQUENCE_START_EVENT",
"YAML_SEQUENCE_END_EVENT",
"YAML_MAPPING_START_EVENT",
"YAML_MAPPING_END_EVENT"
};
fprintf(stderr,
"device parser: expected %s got %s\n",
event_type[type],
event_type[dp->event.type]);
fprintf(stderr,
"device parser: index %zu, line %zu, column %zu\n",
dp->parser.mark.index,
dp->parser.mark.line,
dp->parser.mark.column);
}
bool device_parser_expect(struct device_parser *dp, int type, bool device_parser_expect(struct device_parser *dp, int type,
char *scalar, size_t scalar_len) char *scalar, size_t scalar_len)
{ {
@@ -82,7 +50,7 @@ bool device_parser_expect(struct device_parser *dp, int type,
return true; return true;
} }
decode_yaml_type_error(dp, type); fprintf(stderr, "device parser: expected %d got %u\n", type, dp->event.type);
exit(1); exit(1);
} }

View File

@@ -31,8 +31,7 @@ enum {
GPIO_POWER = 0, // Power input enable GPIO_POWER = 0, // Power input enable
GPIO_FASTBOOT_KEY, // Usually volume key GPIO_FASTBOOT_KEY, // Usually volume key
GPIO_POWER_KEY, // Key to power the device GPIO_POWER_KEY, // Key to power the device
GPIO_USB0_DISCONNECT, // Simulate main USB connection GPIO_USB_DISCONNECT, // Simulate main USB connection
GPIO_USB1_DISCONNECT, // Simulate secondary USB connection
GPIO_OUTPUT_ENABLE, // Enable FTDI signals to flow to the board GPIO_OUTPUT_ENABLE, // Enable FTDI signals to flow to the board
GPIO_COUNT GPIO_COUNT
}; };
@@ -132,7 +131,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio_options *options, char *valu
else if (strncmp("POWER_KEY", name, off - name - 1) == 0) else if (strncmp("POWER_KEY", name, off - name - 1) == 0)
gpio_type = GPIO_POWER_KEY; gpio_type = GPIO_POWER_KEY;
else if (strncmp("USB_DISCONNECT", name, off - name - 1) == 0) else if (strncmp("USB_DISCONNECT", name, off - name - 1) == 0)
gpio_type = GPIO_USB0_DISCONNECT; gpio_type = GPIO_USB_DISCONNECT;
else if (strncmp("OUTPUT_ENABLE", name, off - name - 1) == 0) else if (strncmp("OUTPUT_ENABLE", name, off - name - 1) == 0)
gpio_type = GPIO_OUTPUT_ENABLE; gpio_type = GPIO_OUTPUT_ENABLE;
else else
@@ -183,11 +182,7 @@ void *ftdi_gpio_parse_options(struct device_parser *dp)
} else if (!strcmp(key, "power_key")) { } else if (!strcmp(key, "power_key")) {
gpio_id = GPIO_POWER_KEY; gpio_id = GPIO_POWER_KEY;
} else if (!strcmp(key, "usb_disconnect")) { } else if (!strcmp(key, "usb_disconnect")) {
gpio_id = GPIO_USB0_DISCONNECT; gpio_id = GPIO_USB_DISCONNECT;
} else if (!strcmp(key, "usb0_disconnect")) {
gpio_id = GPIO_USB0_DISCONNECT;
} else if (!strcmp(key, "usb1_disconnect")) {
gpio_id = GPIO_USB1_DISCONNECT;
} else if (!strcmp(key, "output_enable")) { } else if (!strcmp(key, "output_enable")) {
gpio_id = GPIO_OUTPUT_ENABLE; gpio_id = GPIO_OUTPUT_ENABLE;
} else { } else {
@@ -316,9 +311,6 @@ static void *ftdi_gpio_open(struct device *dev)
if (ftdi_gpio->options->gpios[GPIO_POWER_KEY].present) if (ftdi_gpio->options->gpios[GPIO_POWER_KEY].present)
dev->has_power_key = true; dev->has_power_key = true;
if (ftdi_gpio->options->gpios[GPIO_OUTPUT_ENABLE].present)
ftdi_gpio_toggle_io(ftdi_gpio, GPIO_OUTPUT_ENABLE, 1);
ftdi_gpio_device_power(ftdi_gpio, 0); ftdi_gpio_device_power(ftdi_gpio, 0);
if (dev->usb_always_on) if (dev->usb_always_on)
@@ -326,6 +318,9 @@ static void *ftdi_gpio_open(struct device *dev)
else else
ftdi_gpio_device_usb(ftdi_gpio, 0); ftdi_gpio_device_usb(ftdi_gpio, 0);
if (ftdi_gpio->options->gpios[GPIO_OUTPUT_ENABLE].present)
ftdi_gpio_toggle_io(ftdi_gpio, GPIO_OUTPUT_ENABLE, 1);
usleep(500000); usleep(500000);
return ftdi_gpio; return ftdi_gpio;
@@ -362,8 +357,7 @@ static int ftdi_gpio_device_power(struct ftdi_gpio *ftdi_gpio, bool on)
static void ftdi_gpio_device_usb(struct ftdi_gpio *ftdi_gpio, bool on) static void ftdi_gpio_device_usb(struct ftdi_gpio *ftdi_gpio, bool on)
{ {
ftdi_gpio_toggle_io(ftdi_gpio, GPIO_USB0_DISCONNECT, on); ftdi_gpio_toggle_io(ftdi_gpio, GPIO_USB_DISCONNECT, on);
ftdi_gpio_toggle_io(ftdi_gpio, GPIO_USB1_DISCONNECT, on);
} }
static int ftdi_gpio_power(struct device *dev, bool on) static int ftdi_gpio_power(struct device *dev, bool on)

View File

@@ -23,7 +23,6 @@ struct laurent_options {
const char *server; const char *server;
const char *password; const char *password;
unsigned int relay; unsigned int relay;
int usb_relay;
}; };
struct laurent { struct laurent {
@@ -43,7 +42,6 @@ void *laurent_parse_options(struct device_parser *dp)
options = calloc(1, sizeof(*options)); options = calloc(1, sizeof(*options));
options->password = DEFAULT_PASSWORD; options->password = DEFAULT_PASSWORD;
options->usb_relay = -1;
device_parser_accept(dp, YAML_MAPPING_START_EVENT, NULL, 0); device_parser_accept(dp, YAML_MAPPING_START_EVENT, NULL, 0);
while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) { while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) {
@@ -56,8 +54,6 @@ void *laurent_parse_options(struct device_parser *dp)
options->password = strdup(value); options->password = strdup(value);
else if (!strcmp(key, "relay")) else if (!strcmp(key, "relay"))
options->relay = strtoul(value, NULL, 0); options->relay = strtoul(value, NULL, 0);
else if (!strcmp(key, "usb_relay"))
options->usb_relay = strtoul(value, NULL, 0);
else else
errx(1, "%s: unknown option \"%s\"", __func__, key); errx(1, "%s: unknown option \"%s\"", __func__, key);
} }
@@ -128,7 +124,7 @@ static void *laurent_open(struct device *dev)
return laurent; return laurent;
} }
static int laurent_control(struct device *dev, unsigned int relay, bool on) static int laurent_power(struct device *dev, bool on)
{ {
struct laurent *laurent = dev->cdb; struct laurent *laurent = dev->cdb;
char buf[BUFSIZ]; char buf[BUFSIZ];
@@ -149,7 +145,7 @@ static int laurent_control(struct device *dev, unsigned int relay, bool on)
len = snprintf(buf, sizeof(buf), "GET /cmd.cgi?psw=%s&cmd=REL,%u,%d HTTP/1.0\r\n\r\n", len = snprintf(buf, sizeof(buf), "GET /cmd.cgi?psw=%s&cmd=REL,%u,%d HTTP/1.0\r\n\r\n",
laurent->options->password, laurent->options->password,
relay, laurent->options->relay,
on); on);
if (len < 0) { if (len < 0) {
warn("asprintf failed\n"); warn("asprintf failed\n");
@@ -194,30 +190,8 @@ err:
return -1; return -1;
} }
static int laurent_power(struct device *dev, bool on)
{
struct laurent *laurent = dev->cdb;
return laurent_control(dev,
laurent->options->relay,
on);
}
static void laurent_usb(struct device *dev, bool on)
{
struct laurent *laurent = dev->cdb;
if (laurent->options->usb_relay < 0)
return;
laurent_control(dev,
laurent->options->usb_relay,
on);
}
const struct control_ops laurent_ops = { const struct control_ops laurent_ops = {
.parse_options = laurent_parse_options, .parse_options = laurent_parse_options,
.open = laurent_open, .open = laurent_open,
.power = laurent_power, .power = laurent_power,
.usb = laurent_usb,
}; };

117
protocol.md Normal file
View File

@@ -0,0 +1,117 @@
# CDBA protocol description
## General stuff:
### cdba operates over ssh
### Client:
* `~/.ssh/config` is effectively the 'real' config on the client side
* The connection is established by executing:
```sh
# serverbinaryname defaults to 'cdba-server'
/usr/bin/ssh user@server serverbinaryname
```
* ssh `stdout` receives `messages` and the client is expected to handle them instantly after receiving, until `EOF`
* ssh `stderr` receives `status updates` (blue text) and the client is expected to handle them instantly after receiving, until `EOF`
### Server:
* The server enumerates all of the connected devices, based on a configuration file
* Client messages are received over `stdin`
* Messages are sent to the clients over `stdout`, until the connection is closed (or drops)
* The server opens a tty to the serial port on the device and forwards the output via `MSG_CONSOLE`
## Supported messages
`C - client | S - server`
### 1 - MSG_SELECT_BOARD [C -> S]
> ```data = string board name | len = sizeof(data) ```
>
> Select the board to operate on.
>
> Return [**S**]: Echo the command back with `len = 0`.
### 2 - MSG_CONSOLE [C <-> S]
> ```data = string_buffer | len = sizeof(data) ```
> Send TTY I/O.
>
> Return [**C**/**S**]: Echo the command back with `len = sizeof(buf), data = buf`.
### 3 - MSG_HARDRESET
`<unused>`
### 4 - MSG_POWER_ON [C -> S]
> ```len = 0```
>
> Power on the board.
>
> Return [**S**]: Echo the command back with `len = 0`.
### 5 - MSG_POWER_OFF [C -> S]
> ```len = 0```
>
> Power off the board.
>
> Return [**S**]: Echo the command back with `len = 0`.
### 6 - MSG_FASTBOOT_PRESENT [S -> C]
> ```data = 0 / 1 | len = 1 ```
>
> Signal that the device is available over fastboot and ready to receive further commands.
> Return [**C**]: MSG_FASTBOOT_DOWNLOAD or MSG_FASTBOOT_CONTINUE with `len = 0`.
### 7 - MSG_FASTBOOT_DOWNLOAD [C -> S]
> ```data = binary_chunk | len = sizeof(data)```
>
> Send binary data for fastboot.
>
> Return [**S**]: Echo the command back with `len = 0`.
### 8 - MSG_FASTBOOT_BOOT
`<unused>`
### 9 - MSG_STATUS_UPDATE [C -> S]
> TODO: json
>
>Return:
### 10 - MSG_VBUS_ON [C -> S]
> Enable USB VBUS going to the board.
>
> Return [**S**]: None
### 11 - MSG_VBUS_OFF [C -> S]
> Disable USB VBUS going to the board.
>
> Return [**S**]: None
### 12 - MSG_FASTBOOT_REBOOT
`<unused>`
### 13 - MSG_SEND_BREAK [C -> S]
> ```len = 0```
>
> Send a tcsendbreak to the board.
>
> Return [**S**]: None
### 14 - MSG_LIST_DEVICES [C - > S]
> ```len = 0```
>
> List the available boards.
>
> Return [**S**]: Echo the command back NUM_DEVICES times with `len = sizeof(buf), data = buf`. Once done, echo the command back with `len = 0`.
### 15 - MSG_BOARD_INFO [C -> S]
> ```data = string board name | len = sizeof(data) ```
>
> Get the board description.
>
> Return [**S**]: Echo the command back with `len = sizeof(buf), data = buf`.
### 16 - MSG_FASTBOOT_CONTINUE [C -> S]
> ```len = 0```
>
> Send `fastboot continue` to the board.
>
> Return [**S**]: Echo the command back with `len = 0`.

View File

@@ -26,7 +26,7 @@ properties:
fastboot: fastboot:
description: fastboot id description: fastboot id
type: string type: string
pattern: "^[0-9a-f]{8,16}$" pattern: "^[0-9a-f]{8}$"
fastboot_set_active: fastboot_set_active:
description: run fastboot set active before each boot, slot can be selected description: run fastboot set active before each boot, slot can be selected
@@ -123,10 +123,9 @@ properties:
minimin: 0 minimin: 0
devicenode: devicenode:
$ref: "#/$defs/device_path" $ref: "#/$defs/device_path"
patternProperties: patternProperties:
"^power|fastboot_key|power_key|usb[01]?_disconnect|output_enable$": "^power|fastboot_key|power_key|usb_disconnect|output_enable$":
$ref: "#/$defs/ftdi_gpio" $ref: "#/$defs/ftdi_gpio"
additionalProperties: false
dependentRequired: dependentRequired:
index: index:
@@ -139,7 +138,7 @@ properties:
local_gpio: local_gpio:
description: Local GPIO description: Local GPIO
type: object type: object
additionalProperties: false unevaluatedItems: false
patternProperties: patternProperties:
"^power|fastboot_key|power_key|usb_disconnect$": "^power|fastboot_key|power_key|usb_disconnect$":
$ref: "#/$defs/local_gpio" $ref: "#/$defs/local_gpio"
@@ -147,14 +146,12 @@ properties:
laurent: laurent:
description: KernelChip Laurent relays description: KernelChip Laurent relays
type: object type: object
additionalProperties: false unevaluatedItems: false
properties: properties:
server: server:
type: string type: string
relay: relay:
type: integer type: integer
usb_relay:
type: integer
password: password:
description: password to access the relays, defaults to 'Laurent' description: password to access the relays, defaults to 'Laurent'
type: string type: string

View File

@@ -43,8 +43,7 @@ void status_send_values(const char *id, struct status_value *values)
status_get_ts(&ts); status_get_ts(&ts);
len = snprintf(buf, sizeof(buf), "{\"ts\":%lld.%03ld, \"%s\":{ ", len = snprintf(buf, sizeof(buf), "{\"ts\":%ld.%03ld, \"%s\":{ ", ts.tv_sec, ts.tv_nsec / 1000000, id);
(long long int)ts.tv_sec, ts.tv_nsec / 1000000, id);
for (value = values; value->unit; value++) { for (value = values; value->unit; value++) {
if (value != values) { if (value != values) {