summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2014-04-16 16:10:05 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-05-15 05:20:14 +0000
commitc46f569a39210c5ecc7f2f767b6a77c9554f3d73 (patch)
tree8d5544c243b4f305706e448013f31bba61588679
parent53eb009d52fe82409784dfa6f079d45e7a2339b5 (diff)
downloadchrome-ec-c46f569a39210c5ecc7f2f767b6a77c9554f3d73.tar.gz
Add standalone lightbar simulation tool
This adds an "extra/" directory to hold various experiments and optional programs. With this change, we add a tool that can simulate the lightbar behavior on the build machine. That can be used to experment with variations in the lightbar pattern code without needing to reflash a Pixel with a new EC to see the effect. There is no functional change to the EC code, just a couple of #ifdefs to allow common/lightbar.c to be compiled separately from the EC. BUG=none BRANCH=ToT TEST=make buildall -j cd extra make ./lightbar You may need to install the libxcb1-dev package on your build machine. Change-Id: I847ce7ea97cae792b1de1b91f488819e873b6555 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/199883
-rw-r--r--README3
-rw-r--r--common/lightbar.c14
-rw-r--r--extra/.gitignore1
-rw-r--r--extra/Makefile20
-rw-r--r--extra/README46
-rw-r--r--extra/input.c46
-rw-r--r--extra/main.c256
-rw-r--r--extra/simulation.h108
-rw-r--r--extra/windows.c289
-rw-r--r--include/lightbar.h1
10 files changed, 781 insertions, 3 deletions
diff --git a/README b/README
new file mode 100644
index 0000000000..2462fef2d5
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+For an overview of the Embedded Controller firmware, refer to
+
+http://www.chromium.org/chromium-os/2014-firmware-summit
diff --git a/common/lightbar.c b/common/lightbar.c
index 6508d897fb..82cc723555 100644
--- a/common/lightbar.c
+++ b/common/lightbar.c
@@ -6,6 +6,9 @@
* LED controls.
*/
+#ifdef LIGHTBAR_SIMULATION
+#include "simulation.h"
+#else
#include "battery.h"
#include "charge_state.h"
#include "common.h"
@@ -20,6 +23,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#endif
/*
* The Link lightbar had no version command, so defaulted to zero. We have
@@ -139,7 +143,7 @@ static void lightbar_restore_state(void)
static int last_backlight_level;
#endif
-static int demo_mode;
+static int demo_mode = DEMO_MODE_DEFAULT;
/* Update the known state. */
static void get_battery_level(void)
@@ -1016,7 +1020,7 @@ static void show_params(const struct lightbar_params *p)
ccprintf("%d\t\t# .s0a_tick_delay (battery)\n", p->s0a_tick_delay[0]);
ccprintf("%d\t\t# .s0a_tick_delay (AC)\n", p->s0a_tick_delay[1]);
ccprintf("%d\t\t# .s0s3_ramp_down\n", p->s0s3_ramp_down);
- ccprintf("%d\t# .s3_sleep_for\n", p->s3_sleep_for);
+ ccprintf("%d\t\t# .s3_sleep_for\n", p->s3_sleep_for);
ccprintf("%d\t\t# .s3_ramp_up\n", p->s3_ramp_up);
ccprintf("%d\t\t# .s3_ramp_down\n", p->s3_ramp_down);
ccprintf("%d\t\t# .new_s0\n", p->new_s0);
@@ -1032,7 +1036,7 @@ static void show_params(const struct lightbar_params *p)
p->bright_bl_on_min[0], p->bright_bl_on_min[1]);
ccprintf("0x%02x 0x%02x\t# .bright_bl_on_max (battery, AC)\n",
p->bright_bl_on_max[0], p->bright_bl_on_max[1]);
- ccprintf("%d %d %d\t\t# .battery_threshold\n",
+ ccprintf("%d %d %d\t# .battery_threshold\n",
p->battery_threshold[0],
p->battery_threshold[1],
p->battery_threshold[2]);
@@ -1089,6 +1093,10 @@ static int command_lightbar(int argc, char **argv)
}
if (!strcasecmp(argv[1], "params")) {
+#ifdef LIGHTBAR_SIMULATION
+ if (argc > 2)
+ lb_read_params_from_file(argv[2], &st.p);
+#endif
show_params(&st.p);
return EC_SUCCESS;
}
diff --git a/extra/.gitignore b/extra/.gitignore
new file mode 100644
index 0000000000..964154302a
--- /dev/null
+++ b/extra/.gitignore
@@ -0,0 +1 @@
+lightbar
diff --git a/extra/Makefile b/extra/Makefile
new file mode 100644
index 0000000000..0b6c7f7cf7
--- /dev/null
+++ b/extra/Makefile
@@ -0,0 +1,20 @@
+# 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
+
+INCLUDE= -I. -I../include
+CFLAGS= -g -Wall -Werror -pthread ${INCLUDE} -DLIGHTBAR_SIMULATION
+LDFLAGS = -lX11 -lxcb -lrt
+
+all: ${PROG}
+
+${PROG} : ${SRCS} ${HEADERS} Makefile
+ gcc ${CFLAGS} ${SRCS} ${LDFLAGS} -o ${PROG}
+
+.PHONY: clean
+clean:
+ rm -f ${PROG}
diff --git a/extra/README b/extra/README
new file mode 100644
index 0000000000..16659415fb
--- /dev/null
+++ b/extra/README
@@ -0,0 +1,46 @@
+
+This directory is for experiments only. It is not built automatically,
+required, supported, guaranteed to work, or necessarily well-documented.
+
+The contents may change without warning at any time.
+
+------------------------------------------------------------------------------
+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/input.c b/extra/input.c
new file mode 100644
index 0000000000..dcb2a98891
--- /dev/null
+++ b/extra/input.c
@@ -0,0 +1,46 @@
+/*
+ * 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"
+
+void *entry_input(void *ptr)
+{
+ char *got, buf[80];
+ char *str, *word, *saveptr;
+ int argc;
+ char *argv[40];
+ int ret;
+
+ do {
+ printf("lightbar%% ");
+ got = fgets(buf, sizeof(buf), stdin);
+ if (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/main.c b/extra/main.c
new file mode 100644
index 0000000000..9c9e26d08d
--- /dev/null
+++ b/extra/main.c
@@ -0,0 +1,256 @@
+/*
+ * 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 <pthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.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");
+
+ 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, 0, 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);
+}
+
+timestamp_t get_time(void)
+{
+ timestamp_t ret = { .val = 0UL };
+ 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 *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->new_s0 = val[0];
+
+ 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];
+ }
+
+ /* 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/simulation.h b/extra/simulation.h
new file mode 100644
index 0000000000..7ec55ce0cd
--- /dev/null
+++ b/extra/simulation.h
@@ -0,0 +1,108 @@
+/*
+ * 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 *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
+
+/* 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, ...);
+#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/windows.c b/extra/windows.c
new file mode 100644
index 0000000000..fd09af53f5
--- /dev/null
+++ b/extra/windows.c
@@ -0,0 +1,289 @@
+/*
+ * 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 lb_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 (lb_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 (lb_power)
+ lb_set_rgb(NUM_LEDS, 0, 0, 0);
+};
+void lb_off(void)
+{
+ lb_power = 0;
+ update_window();
+};
+void lb_on(void)
+{
+ lb_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", lb_power ? "on" : "off");
+ memset(out, lb_power, sizeof(*out));
+};
+void lb_hc_cmd_reg(const struct ec_params_lightbar *in) { };
+
+
+/*****************************************************************************/
+/* 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;
+}
diff --git a/include/lightbar.h b/include/lightbar.h
index 4f284a43b6..0d143a2e8a 100644
--- a/include/lightbar.h
+++ b/include/lightbar.h
@@ -26,6 +26,7 @@ void lightbar_sequence(enum lightbar_sequence s);
/* External stuff */
/* These are used for demo purposes */
+#define DEMO_MODE_DEFAULT 0
extern void demo_battery_level(int inc);
extern void demo_is_charging(int ischarge);
extern void demo_brightness(int inc);