diff options
author | Stefan Adolfsson <sadolfsson@chromium.org> | 2018-05-25 14:47:32 +0200 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-08-22 08:16:01 -0700 |
commit | e8252556d52f897f2ea443e1cdd1bb0ebf7174ab (patch) | |
tree | dabe6d6811a71f5839ef6590a389be47da1b44ce | |
parent | 913a697b7b385f3b03ac16e9c96313139eab3578 (diff) | |
download | chrome-ec-e8252556d52f897f2ea443e1cdd1bb0ebf7174ab.tar.gz |
CEC: Make buffer handling code unit testable
Moving code to common/ to be able to write some unit test. The
API in cec.h will be refactored in a later commit since it does
not look so nice for a common API. However, it is better to do the
refactoring after the unit tests are in place
Signed-off-by: Stefan Adolfsson <sadolfsson@chromium.org>
BUG=b:80288314
BRANCH=none
TEST=emerge-fizz chromeos-ec
Change-Id: I2d675689cc40248d74bf812bd6c86125d681767d
Reviewed-on: https://chromium-review.googlesource.com/1073414
Commit-Ready: Stefan Adolfsson <sadolfsson@chromium.org>
Tested-by: Stefan Adolfsson <sadolfsson@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | chip/npcx/cec.c | 159 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/cec.c | 134 | ||||
-rw-r--r-- | include/cec.h | 55 |
4 files changed, 191 insertions, 158 deletions
diff --git a/chip/npcx/cec.c b/chip/npcx/cec.c index 73a1c7c1cf..7d4fc3be78 100644 --- a/chip/npcx/cec.c +++ b/chip/npcx/cec.c @@ -4,6 +4,7 @@ */ #include "atomic.h" +#include "cec.h" #include "clock_chip.h" #include "console.h" #include "ec_commands.h" @@ -47,15 +48,6 @@ */ #define CEC_MAX_RESENDS 5 -/* Size of circular buffer used to store incoming CEC messages */ -#define CEC_CIRCBUF_SIZE 20 -#if CEC_CIRCBUF_SIZE < MAX_CEC_MSG_LEN + 1 -#error "Buffer must fit at least a CEC message and a length byte" -#endif -#if CEC_CIRCBUF_SIZE > 255 -#error "Buffer size must not exceed 255 since offsets are uint8_t" -#endif - /* * Free time timing (us). Our free-time is calculated from the end of * the last bit (not from the start). We compensate by having one @@ -190,32 +182,6 @@ enum cap_edge { CAP_EDGE_RISING }; -/* CEC message during transfer */ -struct cec_msg_transfer { - /* The CEC message */ - uint8_t buf[MAX_CEC_MSG_LEN]; - /* Bit offset */ - uint8_t bit; - /* Byte offset */ - uint8_t byte; -}; - -/* - * Circular buffer of completed incoming CEC messages - * ready to be read out by AP - */ -struct cec_rx_cb { - /* Cicular buffer data */ - uint8_t buf[CEC_CIRCBUF_SIZE]; - /* - * Write offset. Updated from interrupt context when we - * have received a complete message. - */ - uint8_t write_offset; - /* Read offset. Updated when AP sends CEC read command */ - uint8_t read_offset; -}; - /* Receive buffer and states */ struct cec_rx { /* @@ -288,12 +254,6 @@ static uint32_t cec_events; /* APB1 frequency. Store divided by 10k to avoid some runtime divisions */ static uint32_t apb1_freq_div_10k; -/* - * Mutex for the read-offset of the circular buffer. Needed since the - * buffer is read and flushed from different contexts - */ -static struct mutex circbuf_readoffset_mutex; - static void send_mkbp_event(uint32_t event) { atomic_or(&cec_events, event); @@ -374,123 +334,6 @@ static void tmr2_stop(void) SET_FIELD(NPCX_TCKC(mdl), NPCX_TCKC_C2CSEL_FIELD, 0); } -static int msgt_get_bit(const struct cec_msg_transfer *msgt) -{ - if (msgt->byte >= MAX_CEC_MSG_LEN) - return 0; - - return msgt->buf[msgt->byte] & (0x80 >> msgt->bit); -} - -static void msgt_set_bit(struct cec_msg_transfer *msgt, int val) -{ - uint8_t bit_flag; - - if (msgt->byte >= MAX_CEC_MSG_LEN) - return; - bit_flag = 0x80 >> msgt->bit; - msgt->buf[msgt->byte] &= ~bit_flag; - if (val) - msgt->buf[msgt->byte] |= bit_flag; -} - -static void msgt_inc_bit(struct cec_msg_transfer *msgt) -{ - if (++(msgt->bit) == 8) { - if (msgt->byte >= MAX_CEC_MSG_LEN) - return; - msgt->bit = 0; - msgt->byte++; - } -} - -static int msgt_is_eom(const struct cec_msg_transfer *msgt, int len) -{ - if (msgt->bit) - return 0; - return (msgt->byte == len); -} - -static void rx_circbuf_flush(struct cec_rx_cb *cb) -{ - mutex_lock(&circbuf_readoffset_mutex); - cb->read_offset = 0; - mutex_unlock(&circbuf_readoffset_mutex); - cb->write_offset = 0; -} - -static int rx_circbuf_push(struct cec_rx_cb *cb, uint8_t *msg, uint8_t msg_len) -{ - int i; - uint32_t offset; - - if (msg_len > MAX_CEC_MSG_LEN || msg_len == 0) - return EC_ERROR_INVAL; - - offset = cb->write_offset; - /* Fill in message length last, if successful. Set to zero for now */ - cb->buf[offset] = 0; - offset = (offset + 1) % CEC_CIRCBUF_SIZE; - - for (i = 0 ; i < msg_len; i++) { - if (offset == cb->read_offset) { - /* Buffer full */ - return EC_ERROR_OVERFLOW; - } - - cb->buf[offset] = msg[i]; - offset = (offset + 1) % CEC_CIRCBUF_SIZE; - } - - /* - * Don't commit if we caught up with read-offset - * since that would indicate an empty buffer - */ - if (offset == cb->read_offset) { - /* Buffer full */ - return EC_ERROR_OVERFLOW; - } - - /* Commit the push */ - cb->buf[cb->write_offset] = msg_len; - cb->write_offset = offset; - - return EC_SUCCESS; -} - -static int rx_circbuf_pop(struct cec_rx_cb *cb, uint8_t *msg, uint8_t *msg_len) -{ - int i; - - mutex_lock(&circbuf_readoffset_mutex); - if (cb->read_offset == cb->write_offset) { - /* Circular buffer empty */ - mutex_unlock(&circbuf_readoffset_mutex); - *msg_len = 0; - return -1; - } - - /* The first byte in the buffer is the message length */ - *msg_len = cb->buf[cb->read_offset]; - if (*msg_len == 0 || *msg_len > MAX_CEC_MSG_LEN) { - mutex_unlock(&circbuf_readoffset_mutex); - *msg_len = 0; - CPRINTF("Invalid CEC msg size: %u\n", *msg_len); - return -1; - } - - cb->read_offset = (cb->read_offset + 1) % CEC_CIRCBUF_SIZE; - for (i = 0; i < *msg_len; i++) { - msg[i] = cb->buf[cb->read_offset]; - cb->read_offset = (cb->read_offset + 1) % CEC_CIRCBUF_SIZE; - - } - - mutex_unlock(&circbuf_readoffset_mutex); - - return 0; -} - void enter_state(enum cec_state new_state) { int gpio = -1, timeout = -1; diff --git a/common/build.mk b/common/build.mk index 1b3cf67e98..fe644bf384 100644 --- a/common/build.mk +++ b/common/build.mk @@ -28,6 +28,7 @@ common-$(CONFIG_BLUETOOTH_LE)+=bluetooth_le.o common-$(CONFIG_BLUETOOTH_LE_STACK)+=btle_hci_controller.o btle_ll.o common-$(CONFIG_CAPSENSE)+=capsense.o common-$(CONFIG_CASE_CLOSED_DEBUG_V1)+=ccd_config.o +common-$(CONFIG_CEC)+=cec.o common-$(CONFIG_CROS_BOARD_INFO)+=cbi.o common-$(CONFIG_CHARGE_MANAGER)+=charge_manager.o common-$(CONFIG_CHARGE_RAMP_HW)+=charge_ramp.o diff --git a/common/cec.c b/common/cec.c new file mode 100644 index 0000000000..27df7a22d8 --- /dev/null +++ b/common/cec.c @@ -0,0 +1,134 @@ +/* Copyright 2018 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 "cec.h" +#include "console.h" +#include "task.h" + +#define CPRINTF(format, args...) cprintf(CC_CEC, format, ## args) +#define CPRINTS(format, args...) cprints(CC_CEC, format, ## args) + +/* + * Mutex for the read-offset of the circular buffer. Needed since the + * buffer is read and flushed from different contexts + */ +static struct mutex circbuf_readoffset_mutex; + +int msgt_get_bit(const struct cec_msg_transfer *msgt) +{ + if (msgt->byte >= MAX_CEC_MSG_LEN) + return 0; + + return msgt->buf[msgt->byte] & (0x80 >> msgt->bit); +} + +void msgt_set_bit(struct cec_msg_transfer *msgt, int val) +{ + uint8_t bit_flag; + + if (msgt->byte >= MAX_CEC_MSG_LEN) + return; + bit_flag = 0x80 >> msgt->bit; + msgt->buf[msgt->byte] &= ~bit_flag; + if (val) + msgt->buf[msgt->byte] |= bit_flag; +} + +void msgt_inc_bit(struct cec_msg_transfer *msgt) +{ + if (++(msgt->bit) == 8) { + if (msgt->byte >= MAX_CEC_MSG_LEN) + return; + msgt->bit = 0; + msgt->byte++; + } +} + +int msgt_is_eom(const struct cec_msg_transfer *msgt, int len) +{ + if (msgt->bit) + return 0; + return (msgt->byte == len); +} + +void rx_circbuf_flush(struct cec_rx_cb *cb) +{ + mutex_lock(&circbuf_readoffset_mutex); + cb->read_offset = 0; + mutex_unlock(&circbuf_readoffset_mutex); + cb->write_offset = 0; +} + +int rx_circbuf_push(struct cec_rx_cb *cb, uint8_t *msg, uint8_t msg_len) +{ + int i; + uint32_t offset; + + if (msg_len > MAX_CEC_MSG_LEN || msg_len == 0) + return EC_ERROR_INVAL; + + offset = cb->write_offset; + /* Fill in message length last, if successful. Set to zero for now */ + cb->buf[offset] = 0; + offset = (offset + 1) % CEC_CIRCBUF_SIZE; + + for (i = 0 ; i < msg_len; i++) { + if (offset == cb->read_offset) { + /* Buffer full */ + return EC_ERROR_OVERFLOW; + } + + cb->buf[offset] = msg[i]; + offset = (offset + 1) % CEC_CIRCBUF_SIZE; + } + + /* + * Don't commit if we caught up with read-offset + * since that would indicate an empty buffer + */ + if (offset == cb->read_offset) { + /* Buffer full */ + return EC_ERROR_OVERFLOW; + } + + /* Commit the push */ + cb->buf[cb->write_offset] = msg_len; + cb->write_offset = offset; + + return EC_SUCCESS; +} + +int rx_circbuf_pop(struct cec_rx_cb *cb, uint8_t *msg, uint8_t *msg_len) +{ + int i; + + mutex_lock(&circbuf_readoffset_mutex); + if (cb->read_offset == cb->write_offset) { + /* Circular buffer empty */ + mutex_unlock(&circbuf_readoffset_mutex); + *msg_len = 0; + return -1; + } + + /* The first byte in the buffer is the message length */ + *msg_len = cb->buf[cb->read_offset]; + if (*msg_len == 0 || *msg_len > MAX_CEC_MSG_LEN) { + mutex_unlock(&circbuf_readoffset_mutex); + *msg_len = 0; + CPRINTF("Invalid CEC msg size: %u\n", *msg_len); + return -1; + } + + cb->read_offset = (cb->read_offset + 1) % CEC_CIRCBUF_SIZE; + for (i = 0; i < *msg_len; i++) { + msg[i] = cb->buf[cb->read_offset]; + cb->read_offset = (cb->read_offset + 1) % CEC_CIRCBUF_SIZE; + + } + + mutex_unlock(&circbuf_readoffset_mutex); + + return 0; +} diff --git a/include/cec.h b/include/cec.h new file mode 100644 index 0000000000..d16378917f --- /dev/null +++ b/include/cec.h @@ -0,0 +1,55 @@ +/* Copyright 2018 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 "ec_commands.h" + +/* Size of circular buffer used to store incoming CEC messages */ +#define CEC_CIRCBUF_SIZE 20 +#if CEC_CIRCBUF_SIZE < MAX_CEC_MSG_LEN + 1 +#error "Buffer must fit at least a CEC message and a length byte" +#endif +#if CEC_CIRCBUF_SIZE > 255 +#error "Buffer size must not exceed 255 since offsets are uint8_t" +#endif + +/* CEC message during transfer */ +struct cec_msg_transfer { + /* The CEC message */ + uint8_t buf[MAX_CEC_MSG_LEN]; + /* Bit offset */ + uint8_t bit; + /* Byte offset */ + uint8_t byte; +}; + +/* + * Circular buffer of completed incoming CEC messages + * ready to be read out by AP + */ +struct cec_rx_cb { + /* + * Write offset. Updated from interrupt context when we + * have received a complete message. + */ + uint8_t write_offset; + /* Read offset. Updated when AP sends CEC read command */ + uint8_t read_offset; + /* Cicular buffer data */ + uint8_t buf[CEC_CIRCBUF_SIZE]; +}; + +int msgt_get_bit(const struct cec_msg_transfer *msgt); + +void msgt_set_bit(struct cec_msg_transfer *msgt, int val); + +void msgt_inc_bit(struct cec_msg_transfer *msgt); + +int msgt_is_eom(const struct cec_msg_transfer *msgt, int len); + +void rx_circbuf_flush(struct cec_rx_cb *cb); + +int rx_circbuf_push(struct cec_rx_cb *cb, uint8_t *msg, uint8_t msg_len); + +int rx_circbuf_pop(struct cec_rx_cb *cb, uint8_t *msg, uint8_t *msg_len); |