add new board and app for gpio testing on octsimtest board

Change-Id: I01243044002f51b34e8dc12c1b1f565bbf1740a2
diff --git a/firmware/libboard/octsimtest/source/board_octsimtest.c b/firmware/libboard/octsimtest/source/board_octsimtest.c
new file mode 100644
index 0000000..2772015
--- /dev/null
+++ b/firmware/libboard/octsimtest/source/board_octsimtest.c
@@ -0,0 +1,72 @@
+/* SIMtrace with SAM3S specific application code
+ *
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
+ */
+#include "board.h"
+#include "simtrace.h"
+#include "utils.h"
+#include "sim_switch.h"
+#include <osmocom/core/timer.h>
+#include "usb_buf.h"
+#include "i2c.h"
+#include "mcp23017.h"
+
+void board_exec_dbg_cmd(int ch)
+{
+	switch (ch) {
+	case '?':
+		printf("\t?\thelp\n\r");
+		printf("\tR\treset SAM3\n\r");
+		break;
+	case 'R':
+		printf("Asking NVIC to reset us\n\r");
+		USBD_Disconnect();
+		NVIC_SystemReset();
+		break;
+	default:
+		printf("Unknown command '%c'\n\r", ch);
+		break;
+	}
+}
+
+void board_main_top(void)
+{
+#ifndef APPLICATION_dfu
+	usb_buf_init();
+
+	i2c_pin_init();
+	mcp23017_init(MCP23017_ADDRESS);
+	/* Initialize checking for card insert/remove events */
+	//card_present_init();
+#endif
+}
+
+int board_override_enter_dfu(void)
+{
+	const Pin bl_sw_pin = PIN_BOOTLOADER_SW;
+
+	PIO_Configure(&bl_sw_pin, 1);
+
+	/* Enter DFU bootloader in case the respective button is pressed */
+	if (PIO_Get(&bl_sw_pin) == 0) {
+		/* do not print to early since the console is not initialized yet */
+		//printf("BOOTLOADER switch pressed -> Force DFU\n\r");
+		return 1;
+	} else
+		return 0;
+}
diff --git a/firmware/libboard/octsimtest/source/i2c.c b/firmware/libboard/octsimtest/source/i2c.c
new file mode 100644
index 0000000..a708704
--- /dev/null
+++ b/firmware/libboard/octsimtest/source/i2c.c
@@ -0,0 +1,225 @@
+/* I2C EEPROM memory read and write utilities
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
+ */
+#include "board.h"
+#include <stdbool.h>
+
+/* Low-Level I2C Routines */
+
+static const Pin pin_sda = {PIO_PA30, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN };
+static const Pin pin_sda_in = {PIO_PA30, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT };
+static const Pin pin_scl = {PIO_PA31, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN };
+
+static void i2c_delay()
+{
+	volatile int v;
+	int i;
+
+	/* 100 cycles results in SCL peak length of 44us, so it's about
+	 * 440ns per cycle here */
+	for (i = 0; i < 14; i++) {
+		v = 0;
+	}
+}
+
+void i2c_pin_init(void)
+{
+	PIO_Configure(&pin_scl, PIO_LISTSIZE(pin_scl));
+	PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
+}
+
+static void set_scl(void)
+{
+	PIO_Set(&pin_scl);
+	i2c_delay();
+}
+
+static void set_sda(void)
+{
+	PIO_Set(&pin_sda);
+	i2c_delay();
+}
+
+static void clear_scl(void)
+{
+	PIO_Clear(&pin_scl);
+	i2c_delay();
+}
+
+static void clear_sda(void)
+{
+	PIO_Clear(&pin_sda);
+	i2c_delay();
+}
+
+static bool read_sda(void)
+{
+	bool ret;
+
+	PIO_Configure(&pin_sda_in, PIO_LISTSIZE(pin_sda_in));
+	if (PIO_Get(&pin_sda_in))
+		ret = true;
+	else
+		ret = false;
+	PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda));
+
+	return ret;
+}
+
+/* Core I2C Routines */
+
+static bool i2c_started = false;
+
+static void i2c_start_cond(void)
+{
+	if (i2c_started) {
+		set_sda();
+		set_scl();
+	}
+
+	clear_sda();
+	i2c_delay();
+	clear_scl();
+	i2c_started = true;
+}
+
+static void i2c_stop_cond(void)
+{
+	clear_sda();
+	set_scl();
+	set_sda();
+	i2c_delay();
+	i2c_started = false;
+}
+
+static void i2c_write_bit(bool bit)
+{
+	if (bit)
+		set_sda();
+	else
+		clear_sda();
+	i2c_delay(); // ?
+	set_scl();
+	clear_scl();
+}
+
+static bool i2c_read_bit(void)
+{
+	bool bit;
+
+	set_sda();
+	set_scl();
+	bit = read_sda();
+	clear_scl();
+
+	return bit;
+}
+
+bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte)
+{
+	uint8_t bit;
+	bool nack;
+
+	if (send_start)
+		i2c_start_cond();
+
+	for (bit = 0; bit < 8; bit++) {
+		i2c_write_bit((byte & 0x80) != 0);
+		byte <<= 1;
+	}
+
+	nack = i2c_read_bit();
+
+	if (send_stop)
+		i2c_stop_cond();
+
+	return nack;
+}
+
+uint8_t i2c_read_byte(bool nack, bool send_stop)
+{
+	uint8_t byte = 0;
+	uint8_t bit;
+
+	for (bit = 0; bit < 8; bit++) {
+		byte = (byte << 1) | i2c_read_bit();
+	}
+
+	i2c_write_bit(nack);
+
+	if (send_stop)
+		i2c_stop_cond();
+
+	return byte;
+}
+
+
+/* EEPROM related code */
+
+int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
+{
+	bool nack;
+
+	WDT_Restart(WDT);
+
+	/* Write slave address */
+	nack = i2c_write_byte(true, false, slave << 1);
+	if (nack)
+		goto out_stop;
+	nack = i2c_write_byte(false, false, addr);
+	if (nack)
+		goto out_stop;
+	nack = i2c_write_byte(false, true, byte);
+	if (nack)
+		goto out_stop;
+	/* Wait tWR time to ensure EEPROM is writing correctly (tWR = 5 ms for AT24C02) */
+	mdelay(5);
+
+out_stop:
+	i2c_stop_cond();
+	if (nack)
+		return -1;
+	else
+		return 0;
+}
+
+int eeprom_read_byte(uint8_t slave, uint8_t addr)
+{
+	bool nack;
+
+	WDT_Restart(WDT);
+
+	/* dummy write cycle */
+	nack = i2c_write_byte(true, false, slave << 1);
+	if (nack)
+		goto out_stop;
+	nack = i2c_write_byte(false, false, addr);
+	if (nack)
+		goto out_stop;
+	/* Re-start with read */
+	nack = i2c_write_byte(true, false, (slave << 1) | 1);
+	if (nack)
+		goto out_stop;
+
+	return i2c_read_byte(true, true);
+
+out_stop:
+	i2c_stop_cond();
+	if (nack)
+		return -1;
+	else
+		return 0;
+}
diff --git a/firmware/libboard/octsimtest/source/mcp23017.c b/firmware/libboard/octsimtest/source/mcp23017.c
new file mode 100644
index 0000000..63390b4
--- /dev/null
+++ b/firmware/libboard/octsimtest/source/mcp23017.c
@@ -0,0 +1,106 @@
+#include "board.h"
+#include <stdbool.h>
+#include "i2c.h"
+#include "mcp23017.h"
+
+
+//defines from https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.h under BSD license
+
+// registers
+#define MCP23017_IODIRA 0x00
+#define MCP23017_IPOLA 0x02
+#define MCP23017_GPINTENA 0x04
+#define MCP23017_DEFVALA 0x06
+#define MCP23017_INTCONA 0x08
+#define MCP23017_IOCONA 0x0A
+#define MCP23017_GPPUA 0x0C
+#define MCP23017_INTFA 0x0E
+#define MCP23017_INTCAPA 0x10
+#define MCP23017_GPIOA 0x12
+#define MCP23017_OLATA 0x14
+
+
+#define MCP23017_IODIRB 0x01
+#define MCP23017_IPOLB 0x03
+#define MCP23017_GPINTENB 0x05
+#define MCP23017_DEFVALB 0x07
+#define MCP23017_INTCONB 0x09
+#define MCP23017_IOCONB 0x0B
+#define MCP23017_GPPUB 0x0D
+#define MCP23017_INTFB 0x0F
+#define MCP23017_INTCAPB 0x11
+#define MCP23017_GPIOB 0x13
+#define MCP23017_OLATB 0x15
+
+#define MCP23017_INT_ERR 255
+
+
+//bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte)
+//uint8_t i2c_read_byte(bool nack, bool send_stop)
+//static void i2c_stop_cond(void)
+
+int mcp23017_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
+{
+	bool nack;
+
+	WDT_Restart(WDT);
+
+//	 Write slave address 
+	nack = i2c_write_byte(true, false, slave << 1);
+	if (nack)
+		goto out_stop;
+	nack = i2c_write_byte(false, false, addr);
+	if (nack)
+		goto out_stop;
+	nack = i2c_write_byte(false, true, byte);
+	if (nack)
+		goto out_stop;
+
+out_stop:
+	i2c_stop_cond();
+	if (nack)
+		return -1;
+	else
+		return 0;
+}
+
+int mcp23017_read_byte(uint8_t slave, uint8_t addr)
+{
+	bool nack;
+
+	WDT_Restart(WDT);
+
+	// dummy write cycle
+	nack = i2c_write_byte(true, false, slave << 1);
+	if (nack)
+		goto out_stop;
+	nack = i2c_write_byte(false, false, addr);
+	if (nack)
+		goto out_stop;
+	// Re-start with read
+	nack = i2c_write_byte(true, false, (slave << 1) | 1);
+	if (nack)
+		goto out_stop;
+
+	return i2c_read_byte(true, true);
+
+out_stop:
+	i2c_stop_cond();
+	if (nack)
+		return -1;
+	else
+		return 0;
+}
+
+int mcp23017_init(uint8_t slave)
+{
+	printf("mcp23017_init\n");
+	// all gpio input
+	if (mcp23017_write_byte(slave, MCP23017_IODIRA, 0xff))
+		return false;
+	if (mcp23017_write_byte(slave, MCP23017_IODIRB, 0xff))
+		return false;
+	printf("mcp23017 found\n");
+	return true;
+}
+