From a9681c5e39155f7ae1b6e1b2668950ef70b1223b Mon Sep 17 00:00:00 2001 From: Baldanos Date: Thu, 12 May 2016 18:08:38 +0200 Subject: [PATCH] Raw 3-wire support (#52) * Initial 3-wire support * 3-wire BBIO support * BBIO timer cleanup --- common/exec.c | 1 + hydrabus/commands.c | 107 ++++++++ hydrabus/commands.h | 1 + hydrabus/hydrabus.mk | 3 +- hydrabus/hydrabus_bbio.c | 4 +- hydrabus/hydrabus_bbio.h | 36 +-- hydrabus/hydrabus_bbio_rawwire.c | 199 +++++++++++++++ hydrabus/hydrabus_bbio_rawwire.h | 37 +++ hydrabus/hydrabus_bbio_twowire.c | 146 ----------- hydrabus/hydrabus_bbio_twowire.h | 20 -- hydrabus/hydrabus_mode.c | 3 + hydrabus/hydrabus_mode_threewire.c | 397 +++++++++++++++++++++++++++++ hydrabus/hydrabus_mode_threewire.h | 44 ++++ hydrabus/hydrabus_mode_twowire.c | 16 +- hydrabus/hydrabus_mode_twowire.h | 7 +- 15 files changed, 823 insertions(+), 198 deletions(-) create mode 100644 hydrabus/hydrabus_bbio_rawwire.c create mode 100644 hydrabus/hydrabus_bbio_rawwire.h delete mode 100644 hydrabus/hydrabus_bbio_twowire.c delete mode 100644 hydrabus/hydrabus_bbio_twowire.h create mode 100644 hydrabus/hydrabus_mode_threewire.c create mode 100644 hydrabus/hydrabus_mode_threewire.h diff --git a/common/exec.c b/common/exec.c index 523b0964..0b4b278c 100644 --- a/common/exec.c +++ b/common/exec.c @@ -243,6 +243,7 @@ static struct cmd_map { { T_JTAG, cmd_mode_init }, { T_RNG, cmd_rng }, { T_TWOWIRE, cmd_mode_init }, + { T_THREEWIRE, cmd_mode_init }, { 0, NULL } }; diff --git a/hydrabus/commands.c b/hydrabus/commands.c index 480c1095..c5d59488 100644 --- a/hydrabus/commands.c +++ b/hydrabus/commands.c @@ -134,6 +134,7 @@ t_token_dict tl_dict[] = { { T_FILTER, "filter" }, { T_LOW, "low" }, { T_HIGH, "high" }, + { T_THREEWIRE, "3-wire" }, { T_LEFT_SQ, "[" }, { T_RIGHT_SQ, "]" }, @@ -911,6 +912,107 @@ t_token tokens_twowire[] = { { } }; +#define THREEWIRE_PARAMETERS \ + { T_DEVICE, \ + .arg_type = T_ARG_UINT, \ + .help = "3-wire device (1)" }, \ + { T_PULL, \ + .arg_type = T_ARG_TOKEN, \ + .subtokens = tokens_gpio_pull, \ + .help = "GPIO pull (up/down/floating)" }, \ + { T_MSB_FIRST, \ + .help = "Send/receive MSB first" }, \ + { T_LSB_FIRST, \ + .help = "Send/receive LSB first" }, + +t_token tokens_mode_threewire[] = { + { + T_SHOW, + .subtokens = tokens_mode_show, + .help = "Show 3-wire parameters" + }, + THREEWIRE_PARAMETERS + /* 3-wire-specific commands */ + { + T_READ, + .flags = T_FLAG_SUFFIX_TOKEN_DELIM_INT, + .help = "Read byte (repeat with :)" + }, + { + T_WRITE, + .flags = T_FLAG_SUFFIX_TOKEN_DELIM_INT, + .help = "Write byte (repeat with :)" + }, + { + T_FREQUENCY, + .arg_type = T_ARG_FLOAT, + .help = "Bus frequency" + }, + { + T_ARG_UINT, + .flags = T_FLAG_SUFFIX_TOKEN_DELIM_INT, + .help = "Write byte (repeat with :)" + }, + { + T_ARG_STRING, + .help = "Write string" + }, + /* BP commands */ + { + T_CARET, + .help = "Send one clock tick" + }, + { + T_SLASH, + .help = "Toggle clock level high" + }, + { + T_BACKSLASH, + .help = "Toggle clock level low" + }, + { + T_MINUS, + .help = "Toggle SDO high" + }, + { + T_UNDERSCORE, + .help = "Toggle SDO low" + }, + { + T_EXCLAMATION, + .help = "Read bit with clock" + }, + { + T_DOT, + .help = "Read bit without clock" + }, + { + T_AMPERSAND, + .flags = T_FLAG_SUFFIX_TOKEN_DELIM_INT, + .help = "Delay 1 usec (repeat with :)" + }, + { + T_PERCENT, + .flags = T_FLAG_SUFFIX_TOKEN_DELIM_INT, + .help = "Delay 1 msec (repeat with :)" + }, + { + T_TILDE, + .flags = T_FLAG_SUFFIX_TOKEN_DELIM_INT, + .help = "Write a random byte (repeat with :)" + }, + { + T_EXIT, + .help = "Exit 3-wire mode" + }, + { } +}; + +t_token tokens_threewire[] = { + THREEWIRE_PARAMETERS + { } +}; + t_token tokens_gpio_mode[] = { { T_IN, @@ -1247,6 +1349,11 @@ t_token tl_tokens[] = { .subtokens = tokens_twowire, .help = "2-wire mode" }, + { + T_THREEWIRE, + .subtokens = tokens_threewire, + .help = "3-wire mode" + }, { T_UART, .subtokens = tokens_uart, diff --git a/hydrabus/commands.h b/hydrabus/commands.h index e1f61dfe..3ac2a1f0 100644 --- a/hydrabus/commands.h +++ b/hydrabus/commands.h @@ -127,6 +127,7 @@ enum { T_FILTER, T_LOW, T_HIGH, + T_THREEWIRE, /* BP-compatible commands */ T_LEFT_SQ, diff --git a/hydrabus/hydrabus.mk b/hydrabus/hydrabus.mk index 0975fba3..ea87c6c3 100644 --- a/hydrabus/hydrabus.mk +++ b/hydrabus/hydrabus.mk @@ -13,6 +13,7 @@ HYDRABUSSRC = hydrabus/hydrabus.c \ hydrabus/hydrabus_mode_jtag.c \ hydrabus/hydrabus_rng.c \ hydrabus/hydrabus_mode_twowire.c \ + hydrabus/hydrabus_mode_threewire.c \ hydrabus/hydrabus_mode_can.c \ hydrabus/hydrabus_bbio.c \ hydrabus/hydrabus_bbio_spi.c \ @@ -20,7 +21,7 @@ HYDRABUSSRC = hydrabus/hydrabus.c \ hydrabus/hydrabus_bbio_can.c \ hydrabus/hydrabus_bbio_uart.c \ hydrabus/hydrabus_bbio_i2c.c \ - hydrabus/hydrabus_bbio_twowire.c + hydrabus/hydrabus_bbio_rawwire.c # Required include directories HYDRABUSINC = ./hydrabus diff --git a/hydrabus/hydrabus_bbio.c b/hydrabus/hydrabus_bbio.c index 11df90c9..4b97b3ab 100644 --- a/hydrabus/hydrabus_bbio.c +++ b/hydrabus/hydrabus_bbio.c @@ -31,7 +31,7 @@ #include "hydrabus_bbio_can.h" #include "hydrabus_bbio_uart.h" #include "hydrabus_bbio_i2c.h" -#include "hydrabus_bbio_twowire.h" +#include "hydrabus_bbio_rawwire.h" int cmd_bbio(t_hydra_console *con) { @@ -59,7 +59,7 @@ int cmd_bbio(t_hydra_console *con) break; case BBIO_RAWWIRE: cprint(con, "RAW1", 4); - bbio_mode_twowire(con); + bbio_mode_rawwire(con); break; case BBIO_JTAG: cprint(con, "OCD1", 4); diff --git a/hydrabus/hydrabus_bbio.h b/hydrabus/hydrabus_bbio.h index 4c19ca0c..2880c385 100644 --- a/hydrabus/hydrabus_bbio.h +++ b/hydrabus/hydrabus_bbio.h @@ -105,23 +105,23 @@ /* * 2-Wire-specific commands */ -#define BBIO_2WIRE_I2C_START 0b00000010 -#define BBIO_2WIRE_I2C_STOP 0b00000011 -#define BBIO_2WIRE_CS_LOW 0b00000100 -#define BBIO_2WIRE_CS_HIGH 0b00000101 -#define BBIO_2WIRE_READ_BYTE 0b00000110 -#define BBIO_2WIRE_READ_BIT 0b00000111 -#define BBIO_2WIRE_PEEK_INPUT 0b00001000 -#define BBIO_2WIRE_CLK_TICK 0b00001001 -#define BBIO_2WIRE_CLK_LOW 0b00001010 -#define BBIO_2WIRE_CLK_HIGH 0b00001011 -#define BBIO_2WIRE_DATA_LOW 0b00001100 -#define BBIO_2WIRE_DATA_HIGH 0b00001101 -#define BBIO_2WIRE_BULK_TRANSFER 0b00010000 -#define BBIO_2WIRE_BULK_CLK 0b00100000 -#define BBIO_2WIRE_BULK_BIT 0b00110000 -#define BBIO_2WIRE_CONFIG_PERIPH 0b01000000 -#define BBIO_2WIRE_SET_SPEED 0b01100000 -#define BBIO_2WIRE_CONFIG 0b10000000 +#define BBIO_RAWWIRE_I2C_START 0b00000010 +#define BBIO_RAWWIRE_I2C_STOP 0b00000011 +#define BBIO_RAWWIRE_CS_LOW 0b00000100 +#define BBIO_RAWWIRE_CS_HIGH 0b00000101 +#define BBIO_RAWWIRE_READ_BYTE 0b00000110 +#define BBIO_RAWWIRE_READ_BIT 0b00000111 +#define BBIO_RAWWIRE_PEEK_INPUT 0b00001000 +#define BBIO_RAWWIRE_CLK_TICK 0b00001001 +#define BBIO_RAWWIRE_CLK_LOW 0b00001010 +#define BBIO_RAWWIRE_CLK_HIGH 0b00001011 +#define BBIO_RAWWIRE_DATA_LOW 0b00001100 +#define BBIO_RAWWIRE_DATA_HIGH 0b00001101 +#define BBIO_RAWWIRE_BULK_TRANSFER 0b00010000 +#define BBIO_RAWWIRE_BULK_CLK 0b00100000 +#define BBIO_RAWWIRE_BULK_BIT 0b00110000 +#define BBIO_RAWWIRE_CONFIG_PERIPH 0b01000000 +#define BBIO_RAWWIRE_SET_SPEED 0b01100000 +#define BBIO_RAWWIRE_CONFIG 0b10000000 int cmd_bbio(t_hydra_console *con); diff --git a/hydrabus/hydrabus_bbio_rawwire.c b/hydrabus/hydrabus_bbio_rawwire.c new file mode 100644 index 00000000..9a743b3e --- /dev/null +++ b/hydrabus/hydrabus_bbio_rawwire.c @@ -0,0 +1,199 @@ +/* + * HydraBus/HydraNFC + * + * Copyright (C) 2014-2016 Benjamin VERNOUX + * Copyright (C) 2016 Nicolas OBERLI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common.h" +#include "tokenline.h" +#include +#include +#include + +#include "hydrabus_bbio.h" +#include "hydrabus_bbio_rawwire.h" +#include "hydrabus_mode_twowire.h" +#include "hydrabus_mode_threewire.h" + + +const mode_rawwire_exec_t bbio_twowire = { + .init = &twowire_init_proto_default, + .pin_init = &twowire_pin_init, + .tim_init = &twowire_tim_init, + .tim_update = &twowire_tim_set_prescaler, + .read_u8 = &twowire_read_u8, + .read_bit_clock = &twowire_read_bit_clock, + .read_bit = &twowire_read_bit, + .write_u8 = &twowire_write_u8, + .write_bit = &twowire_send_bit, + .clock = &twowire_clock, + .clock_high = &twowire_clk_high, + .clock_low = &twowire_clk_low, + .data_high = &twowire_sda_high, + .data_low = &twowire_sda_low, + .cleanup = &twowire_cleanup, +}; +const mode_rawwire_exec_t bbio_threewire = { + .init = &threewire_init_proto_default, + .pin_init = &threewire_pin_init, + .tim_init = &threewire_tim_init, + .tim_update = &threewire_tim_set_prescaler, + .read_u8 = &threewire_read_u8, + .read_bit_clock = &threewire_read_bit_clock, + .read_bit = &threewire_read_bit, + .write_u8 = &threewire_write_u8, + .write_bit = &threewire_send_bit, + .clock = &threewire_clock, + .clock_high = &threewire_clk_high, + .clock_low = &threewire_clk_low, + .data_high = &threewire_sdo_high, + .data_low = &threewire_sdo_low, + .cleanup = &threewire_cleanup, +}; + +void bbio_mode_rawwire(t_hydra_console *con) +{ + uint8_t bbio_subcommand, i; + uint8_t rx_data[16], tx_data[16]; + uint8_t data; + mode_rawwire_exec_t curmode = bbio_twowire; + mode_config_proto_t* proto = &con->mode->proto; + + curmode.init(con); + curmode.pin_init(con); + curmode.tim_init(con); + curmode.clock_low(); + curmode.data_low(); + + while (!USER_BUTTON) { + if(chnRead(con->sdu, &bbio_subcommand, 1) == 1) { + switch(bbio_subcommand) { + case BBIO_RESET: + curmode.cleanup(con); + return; + case BBIO_RAWWIRE_READ_BYTE: + rx_data[0] = curmode.read_u8(con); + cprint(con, (char *)&rx_data[0], 1); + break; + case BBIO_RAWWIRE_READ_BIT: + rx_data[0] = curmode.read_bit_clock(); + cprint(con, (char *)&rx_data[0], 1); + break; + case BBIO_RAWWIRE_PEEK_INPUT: + rx_data[0] = curmode.read_bit(); + cprint(con, (char *)&rx_data[0], 1); + break; + case BBIO_RAWWIRE_CLK_TICK: + curmode.clock(); + cprint(con, "\x01", 1); + break; + case BBIO_RAWWIRE_CLK_LOW: + curmode.clock_low(); + cprint(con, "\x01", 1); + break; + case BBIO_RAWWIRE_CLK_HIGH: + curmode.clock_high(); + cprint(con, "\x01", 1); + break; + case BBIO_RAWWIRE_DATA_LOW: + curmode.data_low(); + cprint(con, "\x01", 1); + break; + case BBIO_RAWWIRE_DATA_HIGH: + curmode.data_high(); + cprint(con, "\x01", 1); + break; + default: + if ((bbio_subcommand & BBIO_RAWWIRE_BULK_TRANSFER) == BBIO_RAWWIRE_BULK_TRANSFER) { + // data contains the number of bytes to + // write + data = (bbio_subcommand & 0b1111) + 1; + + chnRead(con->sdu, tx_data, data); + for(i=0; isdu, &tx_data[0], 1); + if(proto->dev_bit_lsb_msb == DEV_SPI_FIRSTBIT_LSB) { + for (i=0; i>i) & 1); + } + } else { + for (i=0; i>(7-i)) & 1); + } + } + cprint(con, "\x01", 1); + + } else if ((bbio_subcommand & BBIO_RAWWIRE_BULK_CLK) == BBIO_RAWWIRE_BULK_CLK) { + // data contains the number of bytes to + // write + data = (bbio_subcommand & 0b1111) + 1; + + for(i=0; idev_speed = 5000; + break; + case 1: + proto->dev_speed = 50000; + break; + case 2: + proto->dev_speed = 100000; + break; + case 3: + proto->dev_speed = 1000000; + break; + } + curmode.tim_update(con); + } else if ((bbio_subcommand & BBIO_RAWWIRE_CONFIG) == BBIO_RAWWIRE_CONFIG) { + curmode.cleanup(con); + if(bbio_subcommand & 0b10){ + proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_MSB; + } else { + proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_LSB; + } + if(bbio_subcommand & 0b100){ + curmode = bbio_threewire; + } else { + curmode = bbio_twowire; + } + curmode.init(con); + curmode.pin_init(con); + curmode.tim_init(con); + curmode.clock_low(); + curmode.data_low(); + + cprint(con, "\x01", 1); + } else if ((bbio_subcommand & BBIO_RAWWIRE_CONFIG_PERIPH) == BBIO_RAWWIRE_CONFIG_PERIPH) { + cprint(con, "\x01", 1); + } + + } + } + } + curmode.cleanup(con); +} diff --git a/hydrabus/hydrabus_bbio_rawwire.h b/hydrabus/hydrabus_bbio_rawwire.h new file mode 100644 index 00000000..ccebc9f9 --- /dev/null +++ b/hydrabus/hydrabus_bbio_rawwire.h @@ -0,0 +1,37 @@ +/* + * HydraBus/HydraNFC + * + * Copyright (C) 2016 Nicolas OBERLI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +void bbio_mode_rawwire(t_hydra_console *con); + +typedef struct mode_rawwire_exec_t { + void (*init)(t_hydra_console *con); + bool (*pin_init)(t_hydra_console *con); + void (*tim_init)(t_hydra_console *con); + void (*tim_update)(t_hydra_console *con); + uint8_t (*read_u8)(t_hydra_console *con); + uint8_t (*read_bit_clock)(void); + uint8_t (*read_bit)(void); + void (*write_u8)(t_hydra_console *con, uint8_t tx_data); + void (*write_bit)(uint8_t bit); + void (*clock)(void); + void (*clock_high)(void); + void (*clock_low)(void); + void (*data_high)(void); + void (*data_low)(void); + void (*cleanup)(t_hydra_console *con); +} mode_rawwire_exec_t; diff --git a/hydrabus/hydrabus_bbio_twowire.c b/hydrabus/hydrabus_bbio_twowire.c deleted file mode 100644 index 8dac4a0f..00000000 --- a/hydrabus/hydrabus_bbio_twowire.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * HydraBus/HydraNFC - * - * Copyright (C) 2014-2016 Benjamin VERNOUX - * Copyright (C) 2016 Nicolas OBERLI - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "common.h" -#include "tokenline.h" -#include -#include -#include - -#include "hydrabus_bbio.h" -#include "hydrabus_mode_twowire.h" - -void bbio_mode_twowire(t_hydra_console *con) -{ - uint8_t bbio_subcommand, i; - uint8_t rx_data[16], tx_data[16]; - uint8_t data; - mode_config_proto_t* proto = &con->mode->proto; - - init_proto_default(con); - twowire_pin_init(con); - tim_init(con); - twowire_clk_low(); - twowire_sda_low(); - - while (!USER_BUTTON) { - if(chnRead(con->sdu, &bbio_subcommand, 1) == 1) { - switch(bbio_subcommand) { - case BBIO_RESET: - return; - case BBIO_2WIRE_READ_BYTE: - rx_data[0] = twowire_read_u8(con); - cprint(con, (char *)&rx_data[0], 1); - break; - case BBIO_2WIRE_READ_BIT: - rx_data[0] = twowire_read_bit_clock(); - cprint(con, (char *)&rx_data[0], 1); - break; - case BBIO_2WIRE_PEEK_INPUT: - rx_data[0] = twowire_read_bit(); - cprint(con, (char *)&rx_data[0], 1); - break; - case BBIO_2WIRE_CLK_TICK: - twowire_clock(); - cprint(con, "\x01", 1); - break; - case BBIO_2WIRE_CLK_LOW: - twowire_clk_low(); - cprint(con, "\x01", 1); - break; - case BBIO_2WIRE_CLK_HIGH: - twowire_clk_high(); - cprint(con, "\x01", 1); - break; - case BBIO_2WIRE_DATA_LOW: - twowire_sda_low(); - cprint(con, "\x01", 1); - break; - case BBIO_2WIRE_DATA_HIGH: - twowire_sda_high(); - cprint(con, "\x01", 1); - break; - default: - if ((bbio_subcommand & BBIO_2WIRE_BULK_TRANSFER) == BBIO_2WIRE_BULK_TRANSFER) { - // data contains the number of bytes to - // write - data = (bbio_subcommand & 0b1111) + 1; - - chnRead(con->sdu, tx_data, data); - for(i=0; isdu, &tx_data[0], 1); - if(proto->dev_bit_lsb_msb == DEV_SPI_FIRSTBIT_LSB) { - for (i=0; i>i) & 1); - } - } else { - for (i=0; i>(7-i)) & 1); - } - } - cprint(con, "\x01", 1); - - } else if ((bbio_subcommand & BBIO_2WIRE_BULK_CLK) == BBIO_2WIRE_BULK_CLK) { - // data contains the number of bytes to - // write - data = (bbio_subcommand & 0b1111) + 1; - - for(i=0; idev_speed = 5000; - break; - case 1: - proto->dev_speed = 50000; - break; - case 2: - proto->dev_speed = 100000; - break; - case 3: - proto->dev_speed = 1000000; - break; - } - tim_set_prescaler(con); - } else if ((bbio_subcommand & BBIO_2WIRE_CONFIG) == BBIO_2WIRE_CONFIG) { - if(bbio_subcommand & 0b10){ - proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_MSB; - } else { - proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_LSB; - } - cprint(con, "\x01", 1); - } else if ((bbio_subcommand & BBIO_2WIRE_CONFIG_PERIPH) == BBIO_2WIRE_CONFIG_PERIPH) { - cprint(con, "\x01", 1); - } - - } - } - } -} diff --git a/hydrabus/hydrabus_bbio_twowire.h b/hydrabus/hydrabus_bbio_twowire.h deleted file mode 100644 index 7c8ae2d9..00000000 --- a/hydrabus/hydrabus_bbio_twowire.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * HydraBus/HydraNFC - * - * Copyright (C) 2016 Nicolas OBERLI - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -void bbio_twowire_init_proto_default(t_hydra_console *con); -void bbio_mode_twowire(t_hydra_console *con); diff --git a/hydrabus/hydrabus_mode.c b/hydrabus/hydrabus_mode.c index 80580596..600f94f1 100644 --- a/hydrabus/hydrabus_mode.c +++ b/hydrabus/hydrabus_mode.c @@ -41,6 +41,7 @@ extern const mode_exec_t mode_uart_exec; extern const mode_exec_t mode_nfc_exec; extern const mode_exec_t mode_jtag_exec; extern const mode_exec_t mode_twowire_exec; +extern const mode_exec_t mode_threewire_exec; extern const mode_exec_t mode_can_exec; extern t_token tokens_mode_spi[]; extern t_token tokens_mode_i2c[]; @@ -48,6 +49,7 @@ extern t_token tokens_mode_uart[]; extern t_token tokens_mode_nfc[]; extern t_token tokens_mode_jtag[]; extern t_token tokens_mode_twowire[]; +extern t_token tokens_mode_threewire[]; extern t_token tokens_mode_can[]; static struct { @@ -61,6 +63,7 @@ static struct { { T_NFC, tokens_mode_nfc, &mode_nfc_exec }, { T_JTAG, tokens_mode_jtag, &mode_jtag_exec }, { T_TWOWIRE, tokens_mode_twowire, &mode_twowire_exec }, + { T_THREEWIRE, tokens_mode_threewire, &mode_threewire_exec }, { T_CAN, tokens_mode_can, &mode_can_exec }, }; diff --git a/hydrabus/hydrabus_mode_threewire.c b/hydrabus/hydrabus_mode_threewire.c new file mode 100644 index 00000000..9dacb840 --- /dev/null +++ b/hydrabus/hydrabus_mode_threewire.c @@ -0,0 +1,397 @@ +/* +* HydraBus/HydraNFC +* +* Copyright (C) 2014-2015 Benjamin VERNOUX +* Copyright (C) 2015 Nicolas OBERLI +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "common.h" +#include "tokenline.h" +#include "hydrabus.h" +#include "bsp.h" +#include "bsp_gpio.h" +#include "hydrabus_mode_threewire.h" +#include "stm32f4xx_hal.h" +#include + +static int exec(t_hydra_console *con, t_tokenline_parsed *p, int token_pos); +static int show(t_hydra_console *con, t_tokenline_parsed *p); + +static threewire_config config; +static TIM_HandleTypeDef htim; + +static const char* str_prompt_threewire[] = { + "threewire1" PROMPT, +}; + +void threewire_init_proto_default(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + + /* Defaults */ + proto->dev_num = 0; + proto->dev_gpio_mode = MODE_CONFIG_DEV_GPIO_OUT_PUSHPULL; + proto->dev_gpio_pull = MODE_CONFIG_DEV_GPIO_NOPULL; + proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_MSB; + proto->dev_speed = THREEWIRE_MAX_FREQ; + + config.clk_pin = 3; + config.sdi_pin = 4; + config.sdo_pin = 5; +} + +static void show_params(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + + cprintf(con, "Device: threewire%d\r\nGPIO resistor: %s\r\n", + proto->dev_num + 1, + proto->dev_gpio_pull == MODE_CONFIG_DEV_GPIO_PULLUP ? "pull-up" : + proto->dev_gpio_pull == MODE_CONFIG_DEV_GPIO_PULLDOWN ? "pull-down" : + "floating"); + + cprintf(con, "Frequency: %dHz\r\nBit order: %s first\r\n", + (proto->dev_speed), proto->dev_bit_lsb_msb == DEV_SPI_FIRSTBIT_MSB ? "MSB" : "LSB"); +} + +bool threewire_pin_init(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + + bsp_gpio_init(BSP_GPIO_PORTB, config.clk_pin, + proto->dev_gpio_mode, proto->dev_gpio_pull); + bsp_gpio_init(BSP_GPIO_PORTB, config.sdi_pin, + MODE_CONFIG_DEV_GPIO_IN, proto->dev_gpio_pull); + bsp_gpio_init(BSP_GPIO_PORTB, config.sdo_pin, + proto->dev_gpio_mode, proto->dev_gpio_pull); + return true; +} + +void threewire_tim_init(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + htim.Instance = TIM4; + + htim.Init.Period = 42 - 1; + htim.Init.Prescaler = (THREEWIRE_MAX_FREQ/proto->dev_speed) - 1; + htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim.Init.CounterMode = TIM_COUNTERMODE_UP; + + HAL_TIM_Base_MspInit(&htim); + __TIM4_CLK_ENABLE(); + HAL_TIM_Base_Init(&htim); + TIM4->SR &= ~TIM_SR_UIF; //clear overflow flag + HAL_TIM_Base_Start(&htim); +} + +void threewire_tim_set_prescaler(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + + HAL_TIM_Base_Stop(&htim); + HAL_TIM_Base_DeInit(&htim); + htim.Init.Prescaler = (THREEWIRE_MAX_FREQ/proto->dev_speed) - 1; + HAL_TIM_Base_Init(&htim); + TIM4->SR &= ~TIM_SR_UIF; //clear overflow flag + HAL_TIM_Base_Start(&htim); +} + +inline void threewire_sdo_high(void) +{ + bsp_gpio_set(BSP_GPIO_PORTB, config.sdo_pin); +} + +inline void threewire_sdo_low(void) +{ + bsp_gpio_clr(BSP_GPIO_PORTB, config.sdo_pin); +} + +inline void threewire_clk_high(void) +{ + while (!(TIM4->SR & TIM_SR_UIF)) { + } + bsp_gpio_set(BSP_GPIO_PORTB, config.clk_pin); + TIM4->SR &= ~TIM_SR_UIF; //clear overflow flag +} + +inline void threewire_clk_low(void) +{ + while (!(TIM4->SR & TIM_SR_UIF)) { + } + bsp_gpio_clr(BSP_GPIO_PORTB, config.clk_pin); + TIM4->SR &= ~TIM_SR_UIF; //clear overflow flag +} + +inline void threewire_clock(void) +{ + threewire_clk_high(); + threewire_clk_low(); +} + +void threewire_send_bit(uint8_t bit) +{ + if (bit) { + threewire_sdo_high(); + } else { + threewire_sdo_low(); + } + threewire_clock(); +} + +uint8_t threewire_read_bit(void) +{ + return bsp_gpio_pin_read(BSP_GPIO_PORTB, config.sdi_pin); +} + +uint8_t threewire_read_bit_clock(void) +{ + uint8_t bit; + threewire_clock(); + bit = bsp_gpio_pin_read(BSP_GPIO_PORTB, config.sdi_pin); + return bit; +} + +static void clkh(t_hydra_console *con) +{ + threewire_clk_high(); + cprintf(con, "CLK HIGH\r\n"); +} + +static void clkl(t_hydra_console *con) +{ + threewire_clk_low(); + cprintf(con, "CLK LOW\r\n"); +} + +static void clk(t_hydra_console *con) +{ + threewire_clock(); + cprintf(con, "CLOCK PULSE\r\n"); +} + +static void dath(t_hydra_console *con) +{ + threewire_sdo_high(); + cprintf(con, "SDO HIGH\r\n"); +} + +static void datl(t_hydra_console *con) +{ + threewire_sdo_low(); + cprintf(con, "SDO LOW\r\n"); +} + +static void dats(t_hydra_console *con) +{ + uint8_t rx_data = threewire_read_bit_clock(); + cprintf(con, hydrabus_mode_str_read_one_u8, rx_data); +} + +static void bitr(t_hydra_console *con) +{ + uint8_t rx_data = threewire_read_bit(); + cprintf(con, hydrabus_mode_str_read_one_u8, rx_data); +} + +void threewire_write_u8(t_hydra_console *con, uint8_t tx_data) +{ + mode_config_proto_t* proto = &con->mode->proto; + uint8_t i; + + if(proto->dev_bit_lsb_msb == DEV_SPI_FIRSTBIT_LSB) { + for (i=0; i<8; i++) { + threewire_send_bit((tx_data>>i) & 1); + } + } else { + for (i=0; i<8; i++) { + threewire_send_bit((tx_data>>(7-i)) & 1); + } + } +} + +uint8_t threewire_read_u8(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + uint8_t value; + uint8_t i; + + value = 0; + if(proto->dev_bit_lsb_msb == DEV_SPI_FIRSTBIT_LSB) { + for(i=0; i<8; i++) { + value |= (threewire_read_bit_clock() << i); + } + } else { + for(i=0; i<8; i++) { + value |= (threewire_read_bit_clock() << (7-i)); + } + } + return value; +} + +static int init(t_hydra_console *con, t_tokenline_parsed *p) +{ + int tokens_used; + + /* Defaults */ + threewire_init_proto_default(con); + + /* Process cmdline arguments, skipping "threewire". */ + tokens_used = 1 + exec(con, p, 1); + + threewire_pin_init(con); + threewire_tim_init(con); + + threewire_clk_low(); + threewire_sdo_low(); + + show_params(con); + + return tokens_used; +} + +static int exec(t_hydra_console *con, t_tokenline_parsed *p, int token_pos) +{ + mode_config_proto_t* proto = &con->mode->proto; + float arg_float; + int t; + + for (t = token_pos; p->tokens[t]; t++) { + switch (p->tokens[t]) { + case T_SHOW: + t += show(con, p); + break; + case T_PULL: + switch (p->tokens[++t]) { + case T_UP: + proto->dev_gpio_pull = MODE_CONFIG_DEV_GPIO_PULLUP; + break; + case T_DOWN: + proto->dev_gpio_pull = MODE_CONFIG_DEV_GPIO_PULLDOWN; + break; + case T_FLOATING: + proto->dev_gpio_pull = MODE_CONFIG_DEV_GPIO_NOPULL; + break; + } + threewire_pin_init(con); + break; + case T_MSB_FIRST: + proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_MSB; + break; + case T_LSB_FIRST: + proto->dev_bit_lsb_msb = DEV_SPI_FIRSTBIT_LSB; + break; + case T_FREQUENCY: + t += 2; + memcpy(&arg_float, p->buf + p->tokens[t], sizeof(float)); + if(arg_float > THREEWIRE_MAX_FREQ) { + cprintf(con, "Frequency too high\r\n"); + } else { + proto->dev_speed = (int)arg_float; + threewire_tim_set_prescaler(con); + } + break; + default: + return t - token_pos; + } + } + + return t - token_pos; +} + +static uint32_t write(t_hydra_console *con, uint8_t *tx_data, uint8_t nb_data) +{ + int i; + for (i = 0; i < nb_data; i++) { + threewire_write_u8(con, tx_data[i]); + } + if(nb_data == 1) { + /* Write 1 data */ + cprintf(con, hydrabus_mode_str_write_one_u8, tx_data[0]); + } else if(nb_data > 1) { + /* Write n data */ + cprintf(con, hydrabus_mode_str_mul_write); + for(i = 0; i < nb_data; i++) { + cprintf(con, hydrabus_mode_str_mul_value_u8, + tx_data[i]); + } + cprintf(con, hydrabus_mode_str_mul_br); + } + return BSP_OK; +} + +static uint32_t read(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data) +{ + int i; + + for(i = 0; i < nb_data; i++) { + rx_data[i] = threewire_read_u8(con); + } + if(nb_data == 1) { + /* Read 1 data */ + cprintf(con, hydrabus_mode_str_read_one_u8, rx_data[0]); + } else if(nb_data > 1) { + /* Read n data */ + cprintf(con, hydrabus_mode_str_mul_read); + for(i = 0; i < nb_data; i++) { + cprintf(con, hydrabus_mode_str_mul_value_u8, + rx_data[i]); + } + cprintf(con, hydrabus_mode_str_mul_br); + } + return BSP_OK; +} + +void threewire_cleanup(t_hydra_console *con) +{ + (void)con; + HAL_TIM_Base_Stop(&htim); +} + +static int show(t_hydra_console *con, t_tokenline_parsed *p) +{ + int tokens_used; + + tokens_used = 0; + if (p->tokens[1] == T_PINS) { + tokens_used++; + cprintf(con, "CLK: PB%d\r\nSDI: PB%d\r\nSDO: PB%d\r\n", + config.clk_pin, config.sdi_pin, config.sdo_pin); + } else { + show_params(con); + } + return tokens_used; +} + +static const char *get_prompt(t_hydra_console *con) +{ + mode_config_proto_t* proto = &con->mode->proto; + return str_prompt_threewire[proto->dev_num]; +} + +const mode_exec_t mode_threewire_exec = { + .init = &init, + .exec = &exec, + .write = &write, + .read = &read, + .cleanup = &threewire_cleanup, + .get_prompt = &get_prompt, + .clkl = &clkl, + .clkh = &clkh, + .clk = &clk, + .dath = &dath, + .datl = &datl, + .dats = &dats, + .bitr = &bitr, +}; + diff --git a/hydrabus/hydrabus_mode_threewire.h b/hydrabus/hydrabus_mode_threewire.h new file mode 100644 index 00000000..aee1cec7 --- /dev/null +++ b/hydrabus/hydrabus_mode_threewire.h @@ -0,0 +1,44 @@ +/* +* HydraBus/HydraNFC +* +* Copyright (C) 2015 Benjamin VERNOUX +* Copyright (C) 2015 Nicolas OBERLI +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "hydrabus_mode.h" + +#define THREEWIRE_MAX_FREQ 1000000 + +typedef struct { + uint8_t clk_pin; + uint8_t sdi_pin; + uint8_t sdo_pin; +} threewire_config; + +void threewire_init_proto_default(t_hydra_console *con); +bool threewire_pin_init(t_hydra_console *con); +void threewire_tim_init(t_hydra_console *con); +void threewire_tim_set_prescaler(t_hydra_console *con); +uint8_t threewire_read_u8(t_hydra_console *con); +void threewire_write_u8(t_hydra_console *con, uint8_t tx_data); +inline void threewire_clock(void); +inline void threewire_clk_low(void); +inline void threewire_clk_high(void); +inline void threewire_sdo_low(void); +inline void threewire_sdo_high(void); +void threewire_send_bit(uint8_t bit); +uint8_t threewire_read_bit(void); +uint8_t threewire_read_bit_clock(void); +void threewire_cleanup(t_hydra_console *con); diff --git a/hydrabus/hydrabus_mode_twowire.c b/hydrabus/hydrabus_mode_twowire.c index cc8989da..dc385b14 100644 --- a/hydrabus/hydrabus_mode_twowire.c +++ b/hydrabus/hydrabus_mode_twowire.c @@ -35,7 +35,7 @@ static const char* str_prompt_twowire[] = { "twowire1" PROMPT, }; -void init_proto_default(t_hydra_console *con) +void twowire_init_proto_default(t_hydra_console *con) { mode_config_proto_t* proto = &con->mode->proto; @@ -75,7 +75,7 @@ bool twowire_pin_init(t_hydra_console *con) return true; } -void tim_init(t_hydra_console *con) +void twowire_tim_init(t_hydra_console *con) { mode_config_proto_t* proto = &con->mode->proto; htim.Instance = TIM4; @@ -92,7 +92,7 @@ void tim_init(t_hydra_console *con) HAL_TIM_Base_Start(&htim); } -void tim_set_prescaler(t_hydra_console *con) +void twowire_tim_set_prescaler(t_hydra_console *con) { mode_config_proto_t* proto = &con->mode->proto; @@ -259,13 +259,13 @@ static int init(t_hydra_console *con, t_tokenline_parsed *p) int tokens_used; /* Defaults */ - init_proto_default(con); + twowire_init_proto_default(con); /* Process cmdline arguments, skipping "twowire". */ tokens_used = 1 + exec(con, p, 1); twowire_pin_init(con); - tim_init(con); + twowire_tim_init(con); twowire_clk_low(); twowire_sda_low(); @@ -313,7 +313,7 @@ static int exec(t_hydra_console *con, t_tokenline_parsed *p, int token_pos) cprintf(con, "Frequency too high\r\n"); } else { proto->dev_speed = (int)arg_float; - tim_set_prescaler(con); + twowire_tim_set_prescaler(con); } break; default: @@ -367,7 +367,7 @@ static uint32_t read(t_hydra_console *con, uint8_t *rx_data, uint8_t nb_data) return BSP_OK; } -static void cleanup(t_hydra_console *con) +void twowire_cleanup(t_hydra_console *con) { (void)con; HAL_TIM_Base_Stop(&htim); @@ -399,7 +399,7 @@ const mode_exec_t mode_twowire_exec = { .exec = &exec, .write = &write, .read = &read, - .cleanup = &cleanup, + .cleanup = &twowire_cleanup, .get_prompt = &get_prompt, .clkl = &clkl, .clkh = &clkh, diff --git a/hydrabus/hydrabus_mode_twowire.h b/hydrabus/hydrabus_mode_twowire.h index 52eb4394..4d69efea 100644 --- a/hydrabus/hydrabus_mode_twowire.h +++ b/hydrabus/hydrabus_mode_twowire.h @@ -26,10 +26,10 @@ typedef struct { uint8_t sda_pin; } twowire_config; -void init_proto_default(t_hydra_console *con); +void twowire_init_proto_default(t_hydra_console *con); bool twowire_pin_init(t_hydra_console *con); -void tim_init(t_hydra_console *con); -void tim_set_prescaler(t_hydra_console *con); +void twowire_tim_init(t_hydra_console *con); +void twowire_tim_set_prescaler(t_hydra_console *con); uint8_t twowire_read_u8(t_hydra_console *con); void twowire_write_u8(t_hydra_console *con, uint8_t tx_data); inline void twowire_clock(void); @@ -40,3 +40,4 @@ inline void twowire_sda_high(void); void twowire_send_bit(uint8_t bit); uint8_t twowire_read_bit(void); uint8_t twowire_read_bit_clock(void); +void twowire_cleanup(t_hydra_console *con);