diff --git a/s96at/CMakeLists.txt b/s96at/CMakeLists.txt index a3ee84d..b8de11c 100644 --- a/s96at/CMakeLists.txt +++ b/s96at/CMakeLists.txt @@ -15,6 +15,7 @@ set(SRC ${CMAKE_SOURCE_DIR}/src/s96at.c ${CMAKE_SOURCE_DIR}/src/cmd.c ${CMAKE_SOURCE_DIR}/src/crc.c ${CMAKE_SOURCE_DIR}/src/debug.c + ${CMAKE_SOURCE_DIR}/src/device.c ${CMAKE_SOURCE_DIR}/src/io.c ${CMAKE_SOURCE_DIR}/src/i2c_linux.c ${CMAKE_SOURCE_DIR}/src/packet.c diff --git a/s96at/include/cmd.h b/s96at/include/cmd.h index 73d78a1..2f0119d 100644 --- a/s96at/include/cmd.h +++ b/s96at/include/cmd.h @@ -56,12 +56,6 @@ enum { #define SHA_MODE_INIT 0x00 #define SHA_MODE_COMPUTE 0x01 -/* Word address values */ -#define PKT_FUNC_RESET 0x0 -#define PKT_FUNC_SLEEP 0x1 -#define PKT_FUNC_IDLE 0x2 -#define PKT_FUNC_COMMAND 0x3 - /* OP-codes for each command, see section 8.5.4 in spec */ #define OPCODE_DERIVEKEY 0x1c #define OPCODE_DEVREV 0x30 diff --git a/s96at/include/device.h b/s96at/include/device.h index 244ca7c..d48971a 100644 --- a/s96at/include/device.h +++ b/s96at/include/device.h @@ -5,7 +5,21 @@ #ifndef __DEVICE_H #define __DEVICE_H +#include + /* Default I2C address for the ATSHA204a */ #define ATSHA204A_ADDR 0x64 +/* Word address values */ +#define PKT_FUNC_RESET 0x0 +#define PKT_FUNC_SLEEP 0x1 +#define PKT_FUNC_IDLE 0x2 +#define PKT_FUNC_COMMAND 0x3 + +uint8_t device_idle(struct io_interface *ioif); + +uint8_t device_reset(struct io_interface *ioif); + +uint8_t device_sleep(struct io_interface *ioif); + #endif diff --git a/s96at/include/s96at.h b/s96at/include/s96at.h index eaed77b..ab22395 100644 --- a/s96at/include/s96at.h +++ b/s96at/include/s96at.h @@ -389,6 +389,34 @@ uint8_t s96at_lock_zone(struct s96at_desc *desc, enum s96at_zone zone, uint16_t */ uint8_t s96at_read(struct s96at_desc *desc, enum s96at_zone zone, uint8_t id, uint8_t *buf); +/* Put the device into the sleep state + * + * Puts the device in low-power sleep. The device does not respond until the + * next wakeup is sent. The volatile state of the device is reset. + * + * Returns S96AT_STATUS_OK on success, otherwise S96AT_STATUS_EXEC_ERROR. + */ +uint8_t s96at_sleep(struct s96at_desc *desc); + +/* Put the device into the idle state + * + * Puts the device into the idle state. The device does not respond until the + * next wakeup is sent. The contents of RNG seed register and TempKey are + * retained. + * + * Returns S96AT_STATUS_OK on success, otherwise S96AT_STATUS_EXEC_ERROR. + */ +uint8_t s96at_idle(struct s96at_desc *desc); + +/* Reset the address counter + * + * Resets the address counter. This allows re-reading the device's output + * buffer. + * + * Returns always S96AT_SUCCESS. + */ +uint8_t s96at_reset(struct s96at_desc *desc); + /* Wake up the device * * Wakes up the device by sending the wake-up sequence. Upon wake up, a watchdog diff --git a/s96at/src/cmd.c b/s96at/src/cmd.c index 2593144..74ac9a4 100644 --- a/s96at/src/cmd.c +++ b/s96at/src/cmd.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/s96at/src/device.c b/s96at/src/device.c new file mode 100644 index 0000000..9670d6f --- /dev/null +++ b/s96at/src/device.c @@ -0,0 +1,59 @@ +/* + * Copyright 2017, Linaro Ltd and contributors + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include +#include +#include +#include + +uint8_t device_idle(struct io_interface *ioif) +{ + uint8_t ret; + uint8_t data; + uint8_t word_addr = PKT_FUNC_IDLE; + + at204_write(ioif, &word_addr, sizeof(word_addr)); + + /* If idle was successful, we expect a NAK on read */ + ret = at204_read(ioif, &data, sizeof(data)); + + if (ret != STATUS_OK) + ret = STATUS_OK; + else + ret = STATUS_EXEC_ERROR; + + return ret; +} + +uint8_t device_sleep(struct io_interface *ioif) +{ + uint8_t ret; + uint8_t data; + uint8_t word_addr = PKT_FUNC_SLEEP; + + at204_write(ioif, &word_addr, sizeof(word_addr)); + + /* If sleep was successful, we expect a NAK on read */ + ret = at204_read(ioif, &data, sizeof(data)); + + if (ret != STATUS_OK) + ret = STATUS_OK; + else + ret = STATUS_EXEC_ERROR; + + return ret; +} + +uint8_t device_reset(struct io_interface *ioif) +{ + uint8_t word_addr = PKT_FUNC_RESET; + + at204_write(ioif, &word_addr, sizeof(word_addr)); + + return STATUS_OK; +} + diff --git a/s96at/src/s96at.c b/s96at/src/s96at.c index 004c163..9124adc 100644 --- a/s96at/src/s96at.c +++ b/s96at/src/s96at.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,21 @@ uint8_t s96at_cleanup(struct s96at_desc *desc) return ret; } +uint8_t s96at_idle(struct s96at_desc *desc) +{ + return device_idle(desc->ioif); +} + +uint8_t s96at_reset(struct s96at_desc *desc) +{ + return device_reset(desc->ioif); +} + +uint8_t s96at_sleep(struct s96at_desc *desc) +{ + return device_sleep(desc->ioif); +} + uint8_t s96at_wake(struct s96at_desc *desc) { uint8_t ret; diff --git a/s96at/tests/tests.c b/s96at/tests/tests.c index 006775c..7cca866 100644 --- a/s96at/tests/tests.c +++ b/s96at/tests/tests.c @@ -786,6 +786,23 @@ static int test_read_otp(void) return memcmp(buf_a, buf_e, ARRAY_LEN(buf_e)); } +static int test_reset(void) +{ + uint8_t ret; + uint8_t random1[S96AT_RANDOM_LEN]; + uint8_t random2[S96AT_RANDOM_LEN]; + + ret = s96at_get_random(&desc, S96AT_RANDOM_MODE_UPDATE_SEED, random1); + CHECK_RES("Random 1", ret, random1, ARRAY_LEN(random1)); + + /* Now send a reset and read the FIFO again */ + s96at_reset(&desc); + ret = at204_read(desc.ioif, random2, ARRAY_LEN(random2)); + CHECK_RES("Random 2", ret, random2, ARRAY_LEN(random2)); + + return memcmp(random1, random2, ARRAY_LEN(random2)); +} + int main(int argc, char *argv[]) { uint8_t ret; @@ -811,6 +828,7 @@ int main(int argc, char *argv[]) {"Read: Config", test_read_config}, {"Read: Data", test_read_data}, {"Read: OTP", test_read_otp}, + {"Reset", test_reset}, {"SHA", test_sha}, {0, NULL} }; @@ -832,6 +850,14 @@ int main(int argc, char *argv[]) ret = tests[i].func(); printf("%-30s %s\n", tests[i].name, ret ? "\x1B[31m[FAIL]\033[0m" : "\x1B[32m[PASS]\033[0m"); + + /* Force an idle-wake cycle every 4 tests to prevent the watchdog + * from putting the device to sleep during the execution of a test. + */ + if ((i + 1) % 4 == 0) { + s96at_idle(&desc); + while (s96at_wake(&desc) != S96AT_STATUS_READY) {}; + } } printf("Done\n"); out: