summaryrefslogtreecommitdiff
path: root/extra/lightbar
diff options
context:
space:
mode:
authorAnton Staaf <robotboy@chromium.org>2014-09-10 12:33:58 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-09-11 20:00:21 +0000
commitdab91fe9ec6ecddea2e3f6f46d207263b58d7982 (patch)
treeaae6f9162e2498fadf2595cf92f258f9c18ddf2e /extra/lightbar
parent0e59d4f38a97defe45351f2b1e132f76f17160e6 (diff)
downloadchrome-ec-dab91fe9ec6ecddea2e3f6f46d207263b58d7982.tar.gz
extra: Move lightbar simulator into subdirectory
This clears the top level extra directory for additional extras. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=cd extra/lightbar; make; lightbar Change-Id: If05a768e4d33cbf21b2ce47a056c960a95728558 Reviewed-on: https://chromium-review.googlesource.com/217537 Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org>
Diffstat (limited to 'extra/lightbar')
-rw-r--r--extra/lightbar/.gitignore1
-rw-r--r--extra/lightbar/Makefile28
-rw-r--r--extra/lightbar/README39
-rw-r--r--extra/lightbar/input.c80
-rw-r--r--extra/lightbar/main.c292
-rw-r--r--extra/lightbar/simulation.h114
-rw-r--r--extra/lightbar/windows.c294
7 files changed, 848 insertions, 0 deletions
diff --git a/extra/lightbar/.gitignore b/extra/lightbar/.gitignore
new file mode 100644
index 0000000000..964154302a
--- /dev/null
+++ b/extra/lightbar/.gitignore
@@ -0,0 +1 @@
+lightbar
diff --git a/extra/lightbar/Makefile b/extra/lightbar/Makefile
new file mode 100644
index 0000000000..920483b781
--- /dev/null
+++ b/extra/lightbar/Makefile
@@ -0,0 +1,28 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+PROG= lightbar
+HEADERS= simulation.h
+SRCS= main.c windows.c input.c ../../common/lightbar.c
+
+# comment this out if you don't have libreadline installed
+HAS_GNU_READLINE=1
+
+INCLUDE= -I. -I../../include
+CFLAGS= -g -Wall -Werror -pthread ${INCLUDE} -DLIGHTBAR_SIMULATION
+LDFLAGS = -lX11 -lxcb -lrt
+
+ifneq ($(HAS_GNU_READLINE),)
+CFLAGS += -DHAS_GNU_READLINE
+LDFLAGS += -lreadline
+endif
+
+all: ${PROG}
+
+${PROG} : ${SRCS} ${HEADERS} Makefile
+ gcc ${CFLAGS} ${SRCS} ${LDFLAGS} -o ${PROG}
+
+.PHONY: clean
+clean:
+ rm -f ${PROG}
diff --git a/extra/lightbar/README b/extra/lightbar/README
new file mode 100644
index 0000000000..1862f922e4
--- /dev/null
+++ b/extra/lightbar/README
@@ -0,0 +1,39 @@
+Lightbar simulator
+------------------------------------------------------------------------------
+
+Build with "make lightbar". The executable is "./lightbar".
+
+You may need to install libxcb1-dev or similar.
+
+This provides a simulation environment for the lightbar task, compiling
+common/lightbar.c from the EC source, but faking the rest of the EC.
+
+The EC console is on stdin/stdout, delivering all input to the lightbar's
+console command handler (so it prefixes any input with "lightbar"). The
+lightbar itself is displayed in an X window. You can click in that window to
+emulate changes to the battery level, AC connection, and brightness, all of
+which are normally outside the lightbar task's direct control.
+
+The initial sequence is "S5". Try issuing the command "seq s3s0" to see
+something more familiar.
+
+
+Note: the Pixel lightbar circuitry has three modes of operation:
+
+Unpowered
+
+ When the host CPU is off (S5/G3), all power to the lightbar and its
+ controller circuitry is lost.
+
+On
+
+ When the host CPU is on (S0) or suspended (S3), the lightbar is powered
+ again. After every power loss, it will need to be reinitialized by calling
+ lb_init() before it can be used.
+
+Standby
+
+ The lightbar controller ICs can turn off all the LED outputs to conserve
+ power. This is the initial state when power is applied. You can turn the
+ LEDs off manually by calling lb_off(). When suspended, the controller will
+ respond to commands, but the LEDs aren't lit. Turn them on with lb_on().
diff --git a/extra/lightbar/input.c b/extra/lightbar/input.c
new file mode 100644
index 0000000000..fe4f7cd19f
--- /dev/null
+++ b/extra/lightbar/input.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "simulation.h"
+
+#ifdef HAS_GNU_READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+
+char *get_input(const char *prompt)
+{
+ static char *line;
+
+ if (line) {
+ free(line);
+ line = 0;
+ }
+
+ line = readline(prompt);
+
+ if (line && *line)
+ add_history(line);
+
+ return line;
+}
+
+#else /* no readline */
+
+char *get_input(const char *prompt)
+{
+ static char mybuf[80];
+ char *got;
+ printf("%s", prompt);
+ got = fgets(mybuf, sizeof(mybuf), stdin);
+ return got;
+}
+
+#endif /* HAS_GNU_READLINE */
+
+void *entry_input(void *ptr)
+{
+ char *got, buf[80];
+ char *str, *word, *saveptr;
+ int argc;
+ char *argv[40];
+ int ret;
+
+ do {
+ got = get_input("lightbar% ");
+ if (got) {
+ strcpy(buf, got);
+ argc = 0;
+ argv[argc++] = "lightbar";
+ word = str = buf;
+ while (word && argc < ARRAY_SIZE(argv)) {
+ word = strtok_r(str, " \t\r\n", &saveptr);
+ if (word)
+ argv[argc++] = word;
+ str = 0;
+ }
+ argv[argc] = 0;
+ ret = fake_consolecmd_lightbar(argc, argv);
+ if (ret)
+ printf("ERROR %d\n", ret);
+ }
+
+ } while (got);
+
+ exit(0);
+
+ return 0;
+}
diff --git a/extra/lightbar/main.c b/extra/lightbar/main.c
new file mode 100644
index 0000000000..38234e743c
--- /dev/null
+++ b/extra/lightbar/main.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "simulation.h"
+
+static void *(*thread_fns[])(void *) = {
+ entry_windows,
+ entry_lightbar,
+ entry_input,
+};
+
+int main(int argc, char *argv[])
+{
+ int i;
+ pthread_t thread[ARRAY_SIZE(thread_fns)];
+
+ printf("\nLook at the README file.\n");
+ printf("Click in the window.\n");
+ printf("Type \"help\" for commands.\n\n");
+ fflush(stdout);
+
+ init_windows();
+
+ for (i = 0; i < ARRAY_SIZE(thread_fns); i++)
+ assert(0 == pthread_create(&thread[i], NULL, thread_fns[i], 0));
+
+ for (i = 0; i < ARRAY_SIZE(thread_fns); i++)
+ pthread_join(thread[i], NULL);
+
+ return 0;
+}
+
+void *entry_lightbar(void *ptr)
+{
+ lightbar_task();
+ return 0;
+}
+
+/****************************************************************************/
+/* Fake functions. We only have to implement enough for lightbar.c */
+
+/* timespec uses nanoseconds */
+#define TS_USEC 1000L
+#define TS_MSEC 1000000L
+#define TS_SEC 1000000000L
+
+static void timespec_incr(struct timespec *v, time_t secs, long nsecs)
+{
+ v->tv_sec += secs;
+ /* The nanosecond sum won't overflow, but might have a carry. */
+ v->tv_nsec += nsecs;
+ v->tv_sec += v->tv_nsec / TS_SEC;
+ v->tv_nsec %= TS_SEC;
+}
+
+
+static pthread_mutex_t task_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t task_cond = PTHREAD_COND_INITIALIZER;
+static uint32_t task_event;
+
+uint32_t task_wait_event(int timeout_us)
+{
+ struct timespec t;
+ uint32_t event;
+
+ pthread_mutex_lock(&task_mutex);
+
+ if (timeout_us > 0) {
+ clock_gettime(CLOCK_REALTIME, &t);
+ timespec_incr(&t, timeout_us / SECOND, timeout_us * TS_USEC);
+
+ if (ETIMEDOUT == pthread_cond_timedwait(&task_cond,
+ &task_mutex, &t))
+ task_event |= TASK_EVENT_TIMER;
+ } else {
+ pthread_cond_wait(&task_cond, &task_mutex);
+ }
+
+ pthread_mutex_unlock(&task_mutex);
+ event = task_event;
+ task_event = 0;
+ return event;
+}
+
+uint32_t task_set_event(task_id_t tskid, /* always LIGHTBAR */
+ uint32_t event,
+ int wait_for_reply) /* always 0 */
+{
+ pthread_mutex_lock(&task_mutex);
+ task_event = event;
+ pthread_cond_signal(&task_cond);
+ pthread_mutex_unlock(&task_mutex);
+ return 0;
+}
+
+
+
+/* Stubbed functions */
+
+void cprintf(int zero, const char *fmt, ...)
+{
+ va_list ap;
+ char *s;
+ char *newfmt = strdup(fmt);
+
+ for (s = newfmt; *s; s++)
+ if (*s == '%' && s[1] == 'T')
+ *s = 'T';
+
+ va_start(ap, fmt);
+ vprintf(newfmt, ap);
+ va_end(ap);
+
+ free(newfmt);
+}
+
+void cprints(int zero, const char *fmt, ...)
+{
+ va_list ap;
+
+ printf("[TT ");
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("]\n");
+}
+
+timestamp_t get_time(void)
+{
+ static struct timespec t_start;
+ struct timespec t;
+ timestamp_t ret;
+
+ if (!t_start.tv_sec)
+ clock_gettime(CLOCK_REALTIME, &t_start);
+ clock_gettime(CLOCK_REALTIME, &t);
+ ret.val = (t.tv_sec - t_start.tv_sec) * SECOND +
+ (t.tv_nsec - t_start.tv_nsec) / TS_USEC;
+ return ret;
+}
+
+/* We could implement these if we wanted to test their usage. */
+int system_add_jump_tag(uint16_t tag, int version, int size, const void *data)
+{
+ return 0;
+}
+
+uint8_t *system_get_jump_tag(uint16_t tag, int *version, int *size)
+{
+ return 0;
+}
+
+/* Copied from util/ectool.c */
+int lb_read_params_from_file(const char *filename,
+ struct lightbar_params_v1 *p)
+{
+ FILE *fp;
+ char buf[80];
+ int val[4];
+ int r = 1;
+ int line = 0;
+ int want, got;
+ int i;
+
+ fp = fopen(filename, "rb");
+ if (!fp) {
+ fprintf(stderr, "Can't open %s: %s\n",
+ filename, strerror(errno));
+ return 1;
+ }
+
+ /* We must read the correct number of params from each line */
+#define READ(N) do { \
+ line++; \
+ want = (N); \
+ got = -1; \
+ if (!fgets(buf, sizeof(buf), fp)) \
+ goto done; \
+ got = sscanf(buf, "%i %i %i %i", \
+ &val[0], &val[1], &val[2], &val[3]); \
+ if (want != got) \
+ goto done; \
+ } while (0)
+
+
+ /* Do it */
+ READ(1); p->google_ramp_up = val[0];
+ READ(1); p->google_ramp_down = val[0];
+ READ(1); p->s3s0_ramp_up = val[0];
+ READ(1); p->s0_tick_delay[0] = val[0];
+ READ(1); p->s0_tick_delay[1] = val[0];
+ READ(1); p->s0a_tick_delay[0] = val[0];
+ READ(1); p->s0a_tick_delay[1] = val[0];
+ READ(1); p->s0s3_ramp_down = val[0];
+ READ(1); p->s3_sleep_for = val[0];
+ READ(1); p->s3_ramp_up = val[0];
+ READ(1); p->s3_ramp_down = val[0];
+ READ(1); p->tap_tick_delay = val[0];
+ READ(1); p->tap_display_time = val[0];
+
+ READ(1); p->tap_pct_red = val[0];
+ READ(1); p->tap_pct_green = val[0];
+ READ(1); p->tap_seg_min_on = val[0];
+ READ(1); p->tap_seg_max_on = val[0];
+ READ(1); p->tap_seg_osc = val[0];
+ READ(3);
+ p->tap_idx[0] = val[0];
+ p->tap_idx[1] = val[1];
+ p->tap_idx[2] = val[2];
+
+ READ(2);
+ p->osc_min[0] = val[0];
+ p->osc_min[1] = val[1];
+ READ(2);
+ p->osc_max[0] = val[0];
+ p->osc_max[1] = val[1];
+ READ(2);
+ p->w_ofs[0] = val[0];
+ p->w_ofs[1] = val[1];
+
+ READ(2);
+ p->bright_bl_off_fixed[0] = val[0];
+ p->bright_bl_off_fixed[1] = val[1];
+
+ READ(2);
+ p->bright_bl_on_min[0] = val[0];
+ p->bright_bl_on_min[1] = val[1];
+
+ READ(2);
+ p->bright_bl_on_max[0] = val[0];
+ p->bright_bl_on_max[1] = val[1];
+
+ READ(3);
+ p->battery_threshold[0] = val[0];
+ p->battery_threshold[1] = val[1];
+ p->battery_threshold[2] = val[2];
+
+ READ(4);
+ p->s0_idx[0][0] = val[0];
+ p->s0_idx[0][1] = val[1];
+ p->s0_idx[0][2] = val[2];
+ p->s0_idx[0][3] = val[3];
+
+ READ(4);
+ p->s0_idx[1][0] = val[0];
+ p->s0_idx[1][1] = val[1];
+ p->s0_idx[1][2] = val[2];
+ p->s0_idx[1][3] = val[3];
+
+ READ(4);
+ p->s3_idx[0][0] = val[0];
+ p->s3_idx[0][1] = val[1];
+ p->s3_idx[0][2] = val[2];
+ p->s3_idx[0][3] = val[3];
+
+ READ(4);
+ p->s3_idx[1][0] = val[0];
+ p->s3_idx[1][1] = val[1];
+ p->s3_idx[1][2] = val[2];
+ p->s3_idx[1][3] = val[3];
+
+ for (i = 0; i < ARRAY_SIZE(p->color); i++) {
+ READ(3);
+ p->color[i].r = val[0];
+ p->color[i].g = val[1];
+ p->color[i].b = val[2];
+ }
+
+#undef READ
+
+ /* Yay */
+ r = 0;
+done:
+ if (r)
+ fprintf(stderr, "problem with line %d: wanted %d, got %d\n",
+ line, want, got);
+ fclose(fp);
+ return r;
+}
diff --git a/extra/lightbar/simulation.h b/extra/lightbar/simulation.h
new file mode 100644
index 0000000000..569107023b
--- /dev/null
+++ b/extra/lightbar/simulation.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef _SIMULATION_H
+#define _SIMULATION_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lb_common.h"
+#include "lightbar.h"
+
+/* Functions specific to our simulation environment */
+void *entry_windows(void *);
+void *entry_input(void *);
+void *entry_lightbar(void *);
+void init_windows(void);
+int lb_read_params_from_file(const char *filename,
+ struct lightbar_params_v1 *p);
+/* Interfaces to the EC code that we're encapsulating */
+void lightbar_task(void);
+int fake_consolecmd_lightbar(int argc, char *argv[]);
+
+/* EC-specific configuration */
+#undef DEMO_MODE_DEFAULT
+#define DEMO_MODE_DEFAULT 1
+#ifndef CONFIG_CONSOLE_CMDHELP
+#define CONFIG_CONSOLE_CMDHELP
+#endif
+#ifndef CONFIG_LIGHTBAR_POWER_RAILS
+#define CONFIG_LIGHTBAR_POWER_RAILS
+#endif
+
+
+/* Stuff that's too interleaved with the rest of the EC to just include */
+
+/* Test an important condition at compile time, not run time */
+#define _BA1_(cond, line) \
+ extern int __build_assertion_ ## line[1 - 2*!(cond)] \
+ __attribute__ ((unused))
+#define _BA0_(c, x) _BA1_(c, x)
+#define BUILD_ASSERT(cond) _BA0_(cond, __LINE__)
+
+/* Number of elements in an array */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/* Non-standard standard library functions */
+void cprintf(int zero, const char *fmt, ...);
+void cprints(int zero, const char *fmt, ...);
+#define ccprintf(fmt...) cprintf(0, fmt)
+#define strtoi strtol
+
+/* Task events */
+#define TASK_EVENT_CUSTOM(x) (x & 0x0fffffff)
+#define TASK_EVENT_I2C_IDLE 0x10000000
+#define TASK_EVENT_WAKE 0x20000000
+#define TASK_EVENT_MUTEX 0x40000000
+#define TASK_EVENT_TIMER 0x80000000
+
+/* Time units in usecs */
+#define MSEC 1000
+#define SECOND 1000000
+
+#define TASK_ID_LIGHTBAR 0
+#define CC_LIGHTBAR 0
+
+/* Other definitions and structs */
+#define EC_SUCCESS 0
+#define EC_ERROR_INVAL 5
+#define EC_ERROR_PARAM1 11
+#define EC_ERROR_PARAM2 12
+
+typedef int task_id_t;
+
+typedef union {
+ uint64_t val;
+ struct {
+ uint32_t lo;
+ uint32_t hi;
+ } le /* little endian words */;
+} timestamp_t;
+
+struct host_cmd_handler_args {
+ const void *params;
+ void *response;
+ int response_size;
+};
+
+/* EC functions that we have to provide */
+uint32_t task_wait_event(int timeout_us);
+uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait_for_reply);
+timestamp_t get_time(void);
+int system_add_jump_tag(uint16_t tag, int version, int size, const void *data);
+uint8_t *system_get_jump_tag(uint16_t tag, int *version, int *size);
+
+/* Export unused static functions to avoid compiler warnings. */
+#define DECLARE_HOOK(X, fn, Y) \
+ void fake_hook_##fn(void) { fn(); }
+
+#define DECLARE_HOST_COMMAND(X, fn, Y) \
+ int fake_hostcmd_##fn(struct host_cmd_handler_args *args) \
+ { return fn(args); }
+
+#define DECLARE_CONSOLE_COMMAND(X, fn, Y...) \
+ int fake_consolecmd_##X(int argc, char *argv[]) \
+ { return fn(argc, argv); }
+
+#endif /* _SIMULATION_H */
diff --git a/extra/lightbar/windows.c b/extra/lightbar/windows.c
new file mode 100644
index 0000000000..20b3a5780c
--- /dev/null
+++ b/extra/lightbar/windows.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <assert.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <xcb/xcb.h>
+
+#include "simulation.h"
+
+/*****************************************************************************/
+/* Window drawing stuff */
+
+/* Dimensions - may change */
+static int win_w = 1024;
+static int win_h = 32;
+
+static xcb_connection_t *c;
+static xcb_screen_t *screen;
+static xcb_drawable_t win;
+static xcb_gcontext_t foreground;
+static xcb_colormap_t colormap_id;
+
+static int fake_power;
+
+void init_windows(void)
+{
+ uint32_t mask = 0;
+ uint32_t values[2];
+
+ /* Open the connection to the X server */
+ c = xcb_connect(NULL, NULL);
+
+ /* Get the first screen */
+ screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+ /* Get a colormap */
+ colormap_id = xcb_generate_id(c);
+ xcb_create_colormap(c, XCB_COLORMAP_ALLOC_NONE,
+ colormap_id, screen->root, screen->root_visual);
+
+ /* Create foreground GC */
+ foreground = xcb_generate_id(c);
+ mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
+ values[0] = screen->white_pixel;
+ values[1] = 0;
+ xcb_create_gc(c, foreground, screen->root, mask, values);
+
+ /* Create the window */
+ win = xcb_generate_id(c);
+ mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
+ values[0] = screen->black_pixel;
+ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;
+ xcb_create_window(c, /* Connection */
+ XCB_COPY_FROM_PARENT, /* depth */
+ win, /* window Id */
+ screen->root, /* parent window */
+ 0, 0, /* x, y */
+ win_w, win_h, /* width, height */
+ 10, /* border_width */
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
+ screen->root_visual, /* visual */
+ mask, values); /* masks */
+
+ /* Map the window on the screen */
+ xcb_map_window(c, win);
+
+ /* We flush the request */
+ xcb_flush(c);
+}
+
+void cleanup(void)
+{
+ xcb_destroy_window(c, win);
+ xcb_free_gc(c, foreground);
+ xcb_free_colormap(c, colormap_id);
+ xcb_disconnect(c);
+}
+
+/*****************************************************************************/
+/* Draw the lightbar elements */
+
+/* xcb likes 16-bit colors */
+uint16_t leds[NUM_LEDS][3] = {
+ {0xffff, 0x0000, 0x0000},
+ {0x0000, 0xffff, 0x0000},
+ {0x0000, 0x0000, 0xffff},
+ {0xffff, 0xffff, 0x0000},
+};
+pthread_mutex_t leds_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void change_gc_color(uint16_t red, uint16_t green, uint16_t blue)
+{
+ uint32_t mask = 0;
+ uint32_t values[2];
+ xcb_alloc_color_reply_t *reply;
+
+ reply = xcb_alloc_color_reply(c,
+ xcb_alloc_color(c, colormap_id,
+ red, green, blue),
+ NULL);
+ assert(reply);
+
+ mask = XCB_GC_FOREGROUND;
+ values[0] = reply->pixel;
+ xcb_change_gc(c, foreground, mask, values);
+ free(reply);
+}
+
+void update_window(void)
+{
+ xcb_segment_t segments[] = {
+ {0, 0, win_w, win_h},
+ {0, win_h, win_w, 0},
+ };
+ xcb_rectangle_t rect;
+ int w = win_w / NUM_LEDS;
+ int i;
+ uint16_t copyleds[NUM_LEDS][3];
+
+ if (fake_power) {
+ pthread_mutex_lock(&leds_mutex);
+ memcpy(copyleds, leds, sizeof(leds));
+ pthread_mutex_unlock(&leds_mutex);
+
+ for (i = 0; i < NUM_LEDS; i++) {
+ rect.x = i * w;
+ rect.y = 0;
+ rect.width = w;
+ rect.height = win_h;
+
+ change_gc_color(copyleds[i][0],
+ copyleds[i][1],
+ copyleds[i][2]);
+
+ xcb_poly_fill_rectangle(c, win, foreground, 1, &rect);
+ }
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = win_w;
+ rect.height = win_h;
+
+ change_gc_color(0, 0, 0);
+ xcb_poly_fill_rectangle(c, win, foreground, 1, &rect);
+
+ change_gc_color(0x8080, 0, 0);
+
+ for (i = 0; i < NUM_LEDS; i++) {
+ segments[0].x1 = i * w;
+ segments[0].y1 = 0;
+ segments[0].x2 = segments[0].x1 + w;
+ segments[0].y2 = win_h;
+ segments[1].x1 = segments[0].x1;
+ segments[1].y1 = win_h;
+ segments[1].x2 = segments[0].x2;
+ segments[1].y2 = 0;
+ xcb_poly_segment(c, win, foreground, 2, segments);
+ }
+ }
+
+ xcb_flush(c);
+}
+
+void setrgb(int led, int red, int green, int blue)
+{
+ led %= NUM_LEDS;
+
+ pthread_mutex_lock(&leds_mutex);
+ leds[led][0] = red << 8 | red;
+ leds[led][1] = green << 8 | green;
+ leds[led][2] = blue << 8 | blue;
+ pthread_mutex_unlock(&leds_mutex);
+
+ update_window();
+}
+
+/*****************************************************************************/
+/* lb_common stubs */
+
+
+
+/* Brightness serves no purpose here. It's automatic on the Chromebook. */
+static int brightness = 0xc0;
+void lb_set_brightness(unsigned int newval)
+{
+ brightness = newval;
+}
+uint8_t lb_get_brightness(void)
+{
+ return brightness;
+}
+
+void lb_set_rgb(unsigned int led, int red, int green, int blue)
+{
+ int i;
+ if (led >= NUM_LEDS)
+ for (i = 0; i < NUM_LEDS; i++)
+ setrgb(i, red, green, blue);
+ else
+ setrgb(led, red, green, blue);
+}
+
+int lb_get_rgb(unsigned int led, uint8_t *red, uint8_t *green, uint8_t *blue)
+{
+ led %= NUM_LEDS;
+ pthread_mutex_lock(&leds_mutex);
+ *red = leds[led][0];
+ *green = leds[led][1];
+ *blue = leds[led][2];
+ pthread_mutex_unlock(&leds_mutex);
+ return 0;
+}
+
+void lb_init(void)
+{
+ if (fake_power)
+ lb_set_rgb(NUM_LEDS, 0, 0, 0);
+};
+void lb_off(void)
+{
+ fake_power = 0;
+ update_window();
+};
+void lb_on(void)
+{
+ fake_power = 1;
+ update_window();
+};
+void lb_start_builtin_cycle(void) { };
+void lb_hc_cmd_dump(struct ec_response_lightbar *out)
+{
+ printf("lightbar is %s\n", fake_power ? "on" : "off");
+ memset(out, fake_power, sizeof(*out));
+};
+void lb_hc_cmd_reg(const struct ec_params_lightbar *in) { };
+
+int lb_power(int enabled)
+{
+ return fake_power;
+}
+
+
+/*****************************************************************************/
+/* Event handling stuff */
+
+void *entry_windows(void *ptr)
+{
+ xcb_generic_event_t *e;
+ xcb_expose_event_t *ev;
+ xcb_button_press_event_t *bv;
+ int chg = 1;
+
+ while ((e = xcb_wait_for_event(c))) {
+
+ switch (e->response_type & ~0x80) {
+ case XCB_EXPOSE:
+ ev = (xcb_expose_event_t *)e;
+ if (win_w != ev->width || win_h != ev->height) {
+ win_w = ev->width;
+ win_h = ev->height;
+ }
+ update_window();
+ break;
+ case XCB_BUTTON_PRESS:
+ bv = (xcb_button_press_event_t *)e;
+ switch (bv->detail) {
+ case 1:
+ demo_battery_level(-1);
+ break;
+ case 3:
+ demo_battery_level(+1);
+ break;
+ case 2:
+ chg = !chg;
+ demo_is_charging(chg);
+ break;
+ }
+ break;
+ }
+
+ free(e);
+ }
+
+ cleanup();
+ exit(0);
+ return 0;
+}