aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonard Kugis <leonard@kug.is>2024-05-15 19:01:15 +0200
committerLeonard Kugis <leonard@kug.is>2024-05-15 19:01:15 +0200
commit82de9a951b1a43c4abc71425be03877a43063584 (patch)
tree749a5dd1fe6734bdc4bc0314f3fb06abb4d0594c
parenta7dd3dc5171653c051992c5ee339f626d4300225 (diff)
Added first version
-rw-r--r--FT245.c601
-rw-r--r--FT245.h235
-rw-r--r--circular_buffer.h82
3 files changed, 918 insertions, 0 deletions
diff --git a/FT245.c b/FT245.c
new file mode 100644
index 0000000..0b078d3
--- /dev/null
+++ b/FT245.c
@@ -0,0 +1,601 @@
+#include "FT245.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "circular_buffer.h"
+#include <stdatomic.h>
+
+static void data_out(ft245_t *ft245);
+static void data_in(ft245_t *ft245);
+static void bit_set(ft245_t *ft245, uint8_t bit);
+static void bit_reset(ft245_t *ft245, uint8_t bit);
+static bool tx_word(ft245_t *ft245);
+static bool rx_word(ft245_t *ft245);
+
+static atomic_flag lock = ATOMIC_FLAG_INIT;
+
+void ft245_init(ft245_t *ft245)
+{
+ data_in(ft245);
+
+ cb_init(ft245->buffer_rx, FT245_BUFFER_SIZE_RX);
+ cb_init(ft245->buffer_tx, FT245_BUFFER_SIZE_TX);
+
+ ft245->clk_state = false;
+ ft245->clk_count = 0;
+}
+
+static void data_out(ft245_t *ft245)
+{
+ ft245->DATA0_to_output();
+ ft245->DATA1_to_output();
+ ft245->DATA2_to_output();
+ ft245->DATA3_to_output();
+ ft245->DATA4_to_output();
+ ft245->DATA5_to_output();
+ ft245->DATA6_to_output();
+ ft245->DATA7_to_output();
+ ft245->DATA8_to_output();
+ ft245->DATA9_to_output();
+ ft245->DATA10_to_output();
+ ft245->DATA11_to_output();
+ ft245->DATA12_to_output();
+ ft245->DATA13_to_output();
+ ft245->DATA14_to_output();
+ ft245->DATA15_to_output();
+ ft245->DATA16_to_output();
+ ft245->DATA17_to_output();
+ ft245->DATA18_to_output();
+ ft245->DATA19_to_output();
+ ft245->DATA20_to_output();
+ ft245->DATA21_to_output();
+ ft245->DATA22_to_output();
+ ft245->DATA23_to_output();
+ ft245->DATA24_to_output();
+ ft245->DATA25_to_output();
+ ft245->DATA26_to_output();
+ ft245->DATA27_to_output();
+ ft245->DATA28_to_output();
+ ft245->DATA29_to_output();
+ ft245->DATA30_to_output();
+ ft245->DATA31_to_output();
+ ft245->BE0_to_output();
+ ft245->BE1_to_output();
+ ft245->BE2_to_output();
+ ft245->BE3_to_output();
+}
+
+static void data_in(ft245_t *ft245)
+{
+ ft245->DATA0_to_input();
+ ft245->DATA1_to_input();
+ ft245->DATA2_to_input();
+ ft245->DATA3_to_input();
+ ft245->DATA4_to_input();
+ ft245->DATA5_to_input();
+ ft245->DATA6_to_input();
+ ft245->DATA7_to_input();
+ ft245->DATA8_to_input();
+ ft245->DATA9_to_input();
+ ft245->DATA10_to_input();
+ ft245->DATA11_to_input();
+ ft245->DATA12_to_input();
+ ft245->DATA13_to_input();
+ ft245->DATA14_to_input();
+ ft245->DATA15_to_input();
+ ft245->DATA16_to_input();
+ ft245->DATA17_to_input();
+ ft245->DATA18_to_input();
+ ft245->DATA19_to_input();
+ ft245->DATA20_to_input();
+ ft245->DATA21_to_input();
+ ft245->DATA22_to_input();
+ ft245->DATA23_to_input();
+ ft245->DATA24_to_input();
+ ft245->DATA25_to_input();
+ ft245->DATA26_to_input();
+ ft245->DATA27_to_input();
+ ft245->DATA28_to_input();
+ ft245->DATA29_to_input();
+ ft245->DATA30_to_input();
+ ft245->DATA31_to_input();
+ ft245->BE0_to_input();
+ ft245->BE1_to_input();
+ ft245->BE2_to_input();
+ ft245->BE3_to_input();
+}
+
+static void bit_set(ft245_t *ft245, uint8_t bit)
+{
+ switch(bit) {
+ case 0:
+ ft245->DATA0_set();
+ break;
+ case 1:
+ ft245->DATA1_set();
+ break;
+ case 2:
+ ft245->DATA2_set();
+ break;
+ case 3:
+ ft245->DATA3_set();
+ break;
+ case 4:
+ ft245->DATA4_set();
+ break;
+ case 5:
+ ft245->DATA5_set();
+ break;
+ case 6:
+ ft245->DATA6_set();
+ break;
+ case 7:
+ ft245->DATA7_set();
+ break;
+ case 8:
+ ft245->DATA8_set();
+ break;
+ case 9:
+ ft245->DATA9_set();
+ break;
+ case 10:
+ ft245->DATA10_set();
+ break;
+ case 11:
+ ft245->DATA11_set();
+ break;
+ case 12:
+ ft245->DATA12_set();
+ break;
+ case 13:
+ ft245->DATA13_set();
+ break;
+ case 14:
+ ft245->DATA14_set();
+ break;
+ case 15:
+ ft245->DATA15_set();
+ break;
+ case 16:
+ ft245->DATA16_set();
+ break;
+ case 17:
+ ft245->DATA17_set();
+ break;
+ case 18:
+ ft245->DATA18_set();
+ break;
+ case 19:
+ ft245->DATA19_set();
+ break;
+ case 20:
+ ft245->DATA20_set();
+ break;
+ case 21:
+ ft245->DATA21_set();
+ break;
+ case 22:
+ ft245->DATA22_set();
+ break;
+ case 23:
+ ft245->DATA23_set();
+ break;
+ case 24:
+ ft245->DATA24_set();
+ break;
+ case 25:
+ ft245->DATA25_set();
+ break;
+ case 26:
+ ft245->DATA26_set();
+ break;
+ case 27:
+ ft245->DATA27_set();
+ break;
+ case 28:
+ ft245->DATA28_set();
+ break;
+ case 29:
+ ft245->DATA29_set();
+ break;
+ case 30:
+ ft245->DATA30_set();
+ break;
+ case 31:
+ ft245->DATA31_set();
+ break;
+ }
+}
+
+static void bit_reset(ft245_t *ft245, uint8_t bit)
+{
+ switch(bit) {
+ case 0:
+ ft245->DATA0_reset();
+ break;
+ case 1:
+ ft245->DATA1_reset();
+ break;
+ case 2:
+ ft245->DATA2_reset();
+ break;
+ case 3:
+ ft245->DATA3_reset();
+ break;
+ case 4:
+ ft245->DATA4_reset();
+ break;
+ case 5:
+ ft245->DATA5_reset();
+ break;
+ case 6:
+ ft245->DATA6_reset();
+ break;
+ case 7:
+ ft245->DATA7_reset();
+ break;
+ case 8:
+ ft245->DATA8_reset();
+ break;
+ case 9:
+ ft245->DATA9_reset();
+ break;
+ case 10:
+ ft245->DATA10_reset();
+ break;
+ case 11:
+ ft245->DATA11_reset();
+ break;
+ case 12:
+ ft245->DATA12_reset();
+ break;
+ case 13:
+ ft245->DATA13_reset();
+ break;
+ case 14:
+ ft245->DATA14_reset();
+ break;
+ case 15:
+ ft245->DATA15_reset();
+ break;
+ case 16:
+ ft245->DATA16_reset();
+ break;
+ case 17:
+ ft245->DATA17_reset();
+ break;
+ case 18:
+ ft245->DATA18_reset();
+ break;
+ case 19:
+ ft245->DATA19_reset();
+ break;
+ case 20:
+ ft245->DATA20_reset();
+ break;
+ case 21:
+ ft245->DATA21_reset();
+ break;
+ case 22:
+ ft245->DATA22_reset();
+ break;
+ case 23:
+ ft245->DATA23_reset();
+ break;
+ case 24:
+ ft245->DATA24_reset();
+ break;
+ case 25:
+ ft245->DATA25_reset();
+ break;
+ case 26:
+ ft245->DATA26_reset();
+ break;
+ case 27:
+ ft245->DATA27_reset();
+ break;
+ case 28:
+ ft245->DATA28_reset();
+ break;
+ case 29:
+ ft245->DATA29_reset();
+ break;
+ case 30:
+ ft245->DATA30_reset();
+ break;
+ case 31:
+ ft245->DATA31_reset();
+ break;
+ }
+}
+
+static bool byte_enabled_get(ft245_t *ft245, uint8_t byte)
+{
+ switch(byte) {
+ case 0:
+ ft245->BE0_to_input();
+ return (ft245->BE0_read() != 0);
+ case 1:
+ ft245->BE1_to_input();
+ return (ft245->BE1_read() != 0);
+ case 2:
+ ft245->BE2_to_input();
+ return (ft245->BE2_read() != 0);
+ case 3:
+ ft245->BE3_to_input();
+ return (ft245->BE3_read() != 0);
+ }
+
+ return false;
+}
+
+static void byte_enabled_set(ft245_t *ft245, uint8_t byte, bool enabled)
+{
+ switch(byte) {
+ case 0:
+ ft245->BE0_to_output();
+ if(enabled)
+ ft245->BE0_set();
+ else
+ ft245->BE0_reset();
+ break;
+ case 1:
+ ft245->BE1_to_output();
+ if(enabled)
+ ft245->BE1_set();
+ else
+ ft245->BE1_reset();
+ break;
+ case 2:
+ ft245->BE2_to_output();
+ if(enabled)
+ ft245->BE2_set();
+ else
+ ft245->BE2_reset();
+ break;
+ case 3:
+ ft245->BE3_to_output();
+ if(enabled)
+ ft245->BE3_set();
+ else
+ ft245->BE3_reset();
+ break;
+ }
+}
+
+static bool tx_word(ft245_t *ft245)
+{
+ if(!cb_occupation(ft245->buffer_tx))
+ return false;
+
+ if(ft245->full_word_mode && (cb_occupation(ft245->buffer_tx) < 4))
+ return false;
+
+ data_out(ft245);
+
+ uint8_t data = 0;
+ uint32_t word = 0;
+
+ for(uint8_t i = 0; i < 4; i++) {
+ if(cb_occupation(ft245->buffer_tx)) {
+ cb_pop(ft245->buffer_tx, data);
+ byte_enabled_set(ft245, 3 - i, true);
+ } else {
+ data = 0;
+ byte_enabled_set(ft245, 3 - i, false);
+ }
+ word |= ((uint32_t) data) << (i * 8);
+ }
+
+ for(uint8_t i = 0; i < 32; i++) {
+ if((word >> i) & 0b1)
+ bit_set(ft245, i);
+ else
+ bit_reset(ft245, i);
+ }
+
+ return true;
+}
+
+static bool rx_word(ft245_t *ft245)
+{
+ data_in(ft245);
+
+ if((cb_size(ft245->buffer_rx) - cb_occupation(ft245->buffer_rx)) < 4)
+ return false;
+
+ if(ft245->full_word_mode && !(ft245->BE3_read() && ft245->BE2_read() && ft245->BE1_read() && ft245->BE0_read()))
+ return false;
+
+ uint8_t data[4];
+
+ if(ft245->BE3_read()) {
+ data[3] = ((((ft245->DATA31_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 7) |
+ (((ft245->DATA30_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 6) |
+ (((ft245->DATA29_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 5) |
+ (((ft245->DATA28_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 4) |
+ (((ft245->DATA27_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 3) |
+ (((ft245->DATA26_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 2) |
+ (((ft245->DATA25_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 1) |
+ (((ft245->DATA24_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 0));
+ cb_push(ft245->buffer_rx, data[3]);
+ } else {
+ data[3] = 0;
+ cb_push(ft245->buffer_rx, data[3]);
+ }
+
+ if(ft245->BE2_read()) {
+ data[2] = ((((ft245->DATA23_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 7) |
+ (((ft245->DATA22_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 6) |
+ (((ft245->DATA21_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 5) |
+ (((ft245->DATA20_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 4) |
+ (((ft245->DATA19_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 3) |
+ (((ft245->DATA18_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 2) |
+ (((ft245->DATA17_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 1) |
+ (((ft245->DATA16_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 0));
+ cb_push(ft245->buffer_rx, data[2]);
+ } else {
+ data[2] = 0;
+ cb_push(ft245->buffer_rx, data[2]);
+ }
+
+ if(ft245->BE1_read()) {
+ data[1] = ((((ft245->DATA15_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 7) |
+ (((ft245->DATA14_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 6) |
+ (((ft245->DATA13_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 5) |
+ (((ft245->DATA12_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 4) |
+ (((ft245->DATA11_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 3) |
+ (((ft245->DATA10_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 2) |
+ (((ft245->DATA9_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 1) |
+ (((ft245->DATA8_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 0));
+ cb_push(ft245->buffer_rx, data[1]);
+ } else {
+ data[1] = 0;
+ cb_push(ft245->buffer_rx, data[1]);
+ }
+
+ if(ft245->BE0_read()) {
+ data[0] = ((((ft245->DATA7_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 7) |
+ (((ft245->DATA6_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 6) |
+ (((ft245->DATA5_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 5) |
+ (((ft245->DATA4_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 4) |
+ (((ft245->DATA3_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 3) |
+ (((ft245->DATA2_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 2) |
+ (((ft245->DATA1_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 1) |
+ (((ft245->DATA0_read() == 0) ? ((uint32_t) 0) : ((uint32_t) 1)) << 0));
+ cb_push(ft245->buffer_rx, data[0]);
+ } else {
+ data[0] = 0;
+ cb_push(ft245->buffer_rx, data[0]);
+ }
+
+ // Check for sync word 0x66665555
+ if((data[3] == 0x55) && (data[2] == 0x55) && (data[1] == 0x66) && (data[0] == 0x66))
+ cb_reset(ft245->buffer_rx);
+
+ return true;
+}
+
+void ft245_periodic(ft245_t *ft245)
+{
+ static size_t oe_n = 0;
+ static size_t rd_n = 0;
+ static size_t wr_n = 0;
+ static size_t rst_n = 0;
+ bool rxf_n = false;
+ bool txe_n = false;
+ if(ft245->clk_state) {
+ ft245->CLK_reset();
+ ft245->clk_state = false;
+ } else {
+ ft245->CLK_set();
+ ft245->clk_state = true;
+
+ oe_n = ft245->OE_N_read() ? 0 : (oe_n + 1);
+ rd_n = ft245->RD_N_read() ? 0 : (rd_n + 1);
+ wr_n = ft245->WR_N_read() ? 0 : (wr_n + 1);
+ rst_n = ft245->RST_N_read() ? 0 : (rst_n + 1);
+
+ if(rst_n)
+ return;
+
+ rxf_n = (cb_occupation(ft245->buffer_tx) > (ft245->full_word_mode ? 3 : 0));
+ txe_n = !cb_full(ft245->buffer_rx);
+
+ if(rxf_n)
+ ft245->RXF_N_reset();
+ else
+ ft245->RXF_N_set();
+
+ if(txe_n)
+ ft245->TXE_N_reset();
+ else
+ ft245->TXE_N_set();
+
+ // OE_N low => Output Enable
+ // RD_N low => Read access for master
+ // Both required to drive data
+ if(rxf_n && oe_n && rd_n) {
+ tx_word(ft245);
+ } else if(txe_n && wr_n) {
+ rx_word(ft245);
+ } else {
+ data_in(ft245);
+ }
+ }
+}
+
+bool ft245_write_buffered(ft245_t *ft245, uint8_t *data, size_t size)
+{
+ if(cb_full(ft245->buffer_tx))
+ return false;
+
+ if(cb_size(ft245->buffer_tx) - cb_occupation(ft245->buffer_tx) < size)
+ return false;
+
+ for(size_t i = 0; i < size; i++)
+ cb_push(ft245->buffer_tx, data[i]);
+
+ return true;
+}
+
+bool ft245_read_buffered(ft245_t *ft245, uint8_t *data, size_t size)
+{
+ if(cb_occupation(ft245->buffer_rx) < size)
+ return false;
+
+ for(size_t i = 0; i < size; i++)
+ cb_pop(ft245->buffer_rx, data[i]);
+
+ return true;
+}
+
+bool ft245_write_word_buffered(ft245_t *ft245, uint32_t word)
+{
+ while(atomic_flag_test_and_set_explicit(&lock, memory_order_acquire));
+ if(cb_size(ft245->buffer_tx) - cb_occupation(ft245->buffer_tx) < 4) {
+ atomic_flag_clear_explicit(&lock, memory_order_release);
+ return false;
+ }
+
+ cb_push(ft245->buffer_tx, (word >> 0) & 0xFF);
+ cb_push(ft245->buffer_tx, (word >> 8) & 0xFF);
+ cb_push(ft245->buffer_tx, (word >> 16) & 0xFF);
+ cb_push(ft245->buffer_tx, (word >> 24) & 0xFF);
+
+ atomic_flag_clear_explicit(&lock, memory_order_release);
+
+ return true;
+}
+
+bool ft245_read_word_buffered(ft245_t *ft245, uint32_t *word)
+{
+ while(atomic_flag_test_and_set_explicit(&lock, memory_order_acquire));
+ if(cb_occupation(ft245->buffer_rx) < 4) {
+ atomic_flag_clear_explicit(&lock, memory_order_release);
+ return false;
+ }
+
+ uint8_t data = 0;
+ cb_pop(ft245->buffer_rx, data);
+ *word |= ((uint32_t) data) << 24;
+ cb_pop(ft245->buffer_rx, data);
+ *word |= ((uint32_t) data) << 16;
+ cb_pop(ft245->buffer_rx, data);
+ *word |= ((uint32_t) data) << 8;
+ cb_pop(ft245->buffer_rx, data);
+ *word |= ((uint32_t) data) << 0;
+
+ atomic_flag_clear_explicit(&lock, memory_order_release);
+
+ return true;
+}
+
+size_t ft245_available_read(ft245_t *ft245)
+{
+ return cb_occupation(ft245->buffer_rx);
+}
+
+size_t ft245_available_write(ft245_t *ft245)
+{
+ return (cb_size(ft245->buffer_tx) - cb_occupation(ft245->buffer_tx));
+} \ No newline at end of file
diff --git a/FT245.h b/FT245.h
new file mode 100644
index 0000000..4ccd118
--- /dev/null
+++ b/FT245.h
@@ -0,0 +1,235 @@
+#ifndef FT245_H
+#define FT245_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "circular_buffer.h"
+
+#define FT245_BUFFER_SIZE_TX 64
+#define FT245_BUFFER_SIZE_RX 64
+
+typedef circular_buffer_struct(uint8_t, FT245_BUFFER_SIZE_TX) buffer_tx_t;
+typedef circular_buffer_struct(uint8_t, FT245_BUFFER_SIZE_RX) buffer_rx_t;
+
+typedef struct ft245 {
+ // Options
+ bool full_word_mode;
+ // Ring buffers
+ buffer_tx_t buffer_tx;
+ buffer_rx_t buffer_rx;
+ // CLK state
+ bool clk_state;
+ uint8_t clk_count;
+ // To input
+ void (*const DATA0_to_input)(void);
+ void (*const DATA1_to_input)(void);
+ void (*const DATA2_to_input)(void);
+ void (*const DATA3_to_input)(void);
+ void (*const DATA4_to_input)(void);
+ void (*const DATA5_to_input)(void);
+ void (*const DATA6_to_input)(void);
+ void (*const DATA7_to_input)(void);
+ void (*const DATA8_to_input)(void);
+ void (*const DATA9_to_input)(void);
+ void (*const DATA10_to_input)(void);
+ void (*const DATA11_to_input)(void);
+ void (*const DATA12_to_input)(void);
+ void (*const DATA13_to_input)(void);
+ void (*const DATA14_to_input)(void);
+ void (*const DATA15_to_input)(void);
+ void (*const DATA16_to_input)(void);
+ void (*const DATA17_to_input)(void);
+ void (*const DATA18_to_input)(void);
+ void (*const DATA19_to_input)(void);
+ void (*const DATA20_to_input)(void);
+ void (*const DATA21_to_input)(void);
+ void (*const DATA22_to_input)(void);
+ void (*const DATA23_to_input)(void);
+ void (*const DATA24_to_input)(void);
+ void (*const DATA25_to_input)(void);
+ void (*const DATA26_to_input)(void);
+ void (*const DATA27_to_input)(void);
+ void (*const DATA28_to_input)(void);
+ void (*const DATA29_to_input)(void);
+ void (*const DATA30_to_input)(void);
+ void (*const DATA31_to_input)(void);
+ void (*const BE0_to_input)(void);
+ void (*const BE1_to_input)(void);
+ void (*const BE2_to_input)(void);
+ void (*const BE3_to_input)(void);
+ // To output
+ void (*const DATA0_to_output)(void);
+ void (*const DATA1_to_output)(void);
+ void (*const DATA2_to_output)(void);
+ void (*const DATA3_to_output)(void);
+ void (*const DATA4_to_output)(void);
+ void (*const DATA5_to_output)(void);
+ void (*const DATA6_to_output)(void);
+ void (*const DATA7_to_output)(void);
+ void (*const DATA8_to_output)(void);
+ void (*const DATA9_to_output)(void);
+ void (*const DATA10_to_output)(void);
+ void (*const DATA11_to_output)(void);
+ void (*const DATA12_to_output)(void);
+ void (*const DATA13_to_output)(void);
+ void (*const DATA14_to_output)(void);
+ void (*const DATA15_to_output)(void);
+ void (*const DATA16_to_output)(void);
+ void (*const DATA17_to_output)(void);
+ void (*const DATA18_to_output)(void);
+ void (*const DATA19_to_output)(void);
+ void (*const DATA20_to_output)(void);
+ void (*const DATA21_to_output)(void);
+ void (*const DATA22_to_output)(void);
+ void (*const DATA23_to_output)(void);
+ void (*const DATA24_to_output)(void);
+ void (*const DATA25_to_output)(void);
+ void (*const DATA26_to_output)(void);
+ void (*const DATA27_to_output)(void);
+ void (*const DATA28_to_output)(void);
+ void (*const DATA29_to_output)(void);
+ void (*const DATA30_to_output)(void);
+ void (*const DATA31_to_output)(void);
+ void (*const BE0_to_output)(void);
+ void (*const BE1_to_output)(void);
+ void (*const BE2_to_output)(void);
+ void (*const BE3_to_output)(void);
+ // Set
+ void (*const CLK_set)(void);
+ void (*const RXF_N_set)(void);
+ void (*const TXE_N_set)(void);
+ void (*const DATA0_set)(void);
+ void (*const DATA1_set)(void);
+ void (*const DATA2_set)(void);
+ void (*const DATA3_set)(void);
+ void (*const DATA4_set)(void);
+ void (*const DATA5_set)(void);
+ void (*const DATA6_set)(void);
+ void (*const DATA7_set)(void);
+ void (*const DATA8_set)(void);
+ void (*const DATA9_set)(void);
+ void (*const DATA10_set)(void);
+ void (*const DATA11_set)(void);
+ void (*const DATA12_set)(void);
+ void (*const DATA13_set)(void);
+ void (*const DATA14_set)(void);
+ void (*const DATA15_set)(void);
+ void (*const DATA16_set)(void);
+ void (*const DATA17_set)(void);
+ void (*const DATA18_set)(void);
+ void (*const DATA19_set)(void);
+ void (*const DATA20_set)(void);
+ void (*const DATA21_set)(void);
+ void (*const DATA22_set)(void);
+ void (*const DATA23_set)(void);
+ void (*const DATA24_set)(void);
+ void (*const DATA25_set)(void);
+ void (*const DATA26_set)(void);
+ void (*const DATA27_set)(void);
+ void (*const DATA28_set)(void);
+ void (*const DATA29_set)(void);
+ void (*const DATA30_set)(void);
+ void (*const DATA31_set)(void);
+ void (*const BE0_set)(void);
+ void (*const BE1_set)(void);
+ void (*const BE2_set)(void);
+ void (*const BE3_set)(void);
+ // Reset
+ void (*const CLK_reset)(void);
+ void (*const RXF_N_reset)(void);
+ void (*const TXE_N_reset)(void);
+ void (*const DATA0_reset)(void);
+ void (*const DATA1_reset)(void);
+ void (*const DATA2_reset)(void);
+ void (*const DATA3_reset)(void);
+ void (*const DATA4_reset)(void);
+ void (*const DATA5_reset)(void);
+ void (*const DATA6_reset)(void);
+ void (*const DATA7_reset)(void);
+ void (*const DATA8_reset)(void);
+ void (*const DATA9_reset)(void);
+ void (*const DATA10_reset)(void);
+ void (*const DATA11_reset)(void);
+ void (*const DATA12_reset)(void);
+ void (*const DATA13_reset)(void);
+ void (*const DATA14_reset)(void);
+ void (*const DATA15_reset)(void);
+ void (*const DATA16_reset)(void);
+ void (*const DATA17_reset)(void);
+ void (*const DATA18_reset)(void);
+ void (*const DATA19_reset)(void);
+ void (*const DATA20_reset)(void);
+ void (*const DATA21_reset)(void);
+ void (*const DATA22_reset)(void);
+ void (*const DATA23_reset)(void);
+ void (*const DATA24_reset)(void);
+ void (*const DATA25_reset)(void);
+ void (*const DATA26_reset)(void);
+ void (*const DATA27_reset)(void);
+ void (*const DATA28_reset)(void);
+ void (*const DATA29_reset)(void);
+ void (*const DATA30_reset)(void);
+ void (*const DATA31_reset)(void);
+ void (*const BE0_reset)(void);
+ void (*const BE1_reset)(void);
+ void (*const BE2_reset)(void);
+ void (*const BE3_reset)(void);
+ // Toggle
+ void (*const CLK_toggle)(void);
+ // Read
+ uint32_t (*const TXE_N_read)(void);
+ uint32_t (*const RXF_N_read)(void);
+ uint32_t (*const WR_N_read)(void);
+ uint32_t (*const SIWU_N_read)(void);
+ uint32_t (*const RD_N_read)(void);
+ uint32_t (*const OE_N_read)(void);
+ uint32_t (*const RST_N_read)(void);
+ uint32_t (*const DATA0_read)(void);
+ uint32_t (*const DATA1_read)(void);
+ uint32_t (*const DATA2_read)(void);
+ uint32_t (*const DATA3_read)(void);
+ uint32_t (*const DATA4_read)(void);
+ uint32_t (*const DATA5_read)(void);
+ uint32_t (*const DATA6_read)(void);
+ uint32_t (*const DATA7_read)(void);
+ uint32_t (*const DATA8_read)(void);
+ uint32_t (*const DATA9_read)(void);
+ uint32_t (*const DATA10_read)(void);
+ uint32_t (*const DATA11_read)(void);
+ uint32_t (*const DATA12_read)(void);
+ uint32_t (*const DATA13_read)(void);
+ uint32_t (*const DATA14_read)(void);
+ uint32_t (*const DATA15_read)(void);
+ uint32_t (*const DATA16_read)(void);
+ uint32_t (*const DATA17_read)(void);
+ uint32_t (*const DATA18_read)(void);
+ uint32_t (*const DATA19_read)(void);
+ uint32_t (*const DATA20_read)(void);
+ uint32_t (*const DATA21_read)(void);
+ uint32_t (*const DATA22_read)(void);
+ uint32_t (*const DATA23_read)(void);
+ uint32_t (*const DATA24_read)(void);
+ uint32_t (*const DATA25_read)(void);
+ uint32_t (*const DATA26_read)(void);
+ uint32_t (*const DATA27_read)(void);
+ uint32_t (*const DATA28_read)(void);
+ uint32_t (*const DATA29_read)(void);
+ uint32_t (*const DATA30_read)(void);
+ uint32_t (*const DATA31_read)(void);
+ uint32_t (*const BE0_read)(void);
+ uint32_t (*const BE1_read)(void);
+ uint32_t (*const BE2_read)(void);
+ uint32_t (*const BE3_read)(void);
+} ft245_t;
+
+void ft245_init(ft245_t *ft245);
+void ft245_periodic(ft245_t *ft245);
+bool ft245_write_buffered(ft245_t *ft245, uint8_t *data, size_t size);
+bool ft245_read_buffered(ft245_t *ft245, uint8_t *data, size_t size);
+bool ft245_write_word_buffered(ft245_t *ft245, uint32_t word);
+bool ft245_read_word_buffered(ft245_t *ft245, uint32_t *word);
+size_t ft245_available_read(ft245_t *ft245);
+size_t ft245_available_write(ft245_t *ft245);
+
+#endif \ No newline at end of file
diff --git a/circular_buffer.h b/circular_buffer.h
new file mode 100644
index 0000000..a12bbbc
--- /dev/null
+++ b/circular_buffer.h
@@ -0,0 +1,82 @@
+/*
+ * ------------------------------------------------------------
+ * "THE BEERWARE LICENSE" (Revision 42):
+ * diegohamilton26@gmail.com wrote this code. As long as you retain this
+ * notice, you can do whatever you want with this stuff. If we
+ * meet someday, and you think this stuff is worth it, you can
+ * buy me a beer in return,
+ * Diego Hamilton.
+ * ------------------------------------------------------------
+ */
+
+#ifndef _CIRCULAR_BUFFER_H
+#define _CIRCULAR_BUFFER_H
+
+#include <stddef.h>
+
+/*
+* BUF must be a pointer of any buffer with type 'NAME' defined.
+* ELEM must be a element (NOT A POINTER) of type T defined.
+*/
+
+#define circular_buffer_struct(T, SIZE) \
+ struct { \
+ size_t occup; \
+ size_t size; \
+ size_t head, tail; \
+ T data[SIZE]; \
+ }
+
+#define cb_init(BUF, SIZE) \
+ do { \
+ (BUF).size = SIZE; \
+ (BUF).occup = 0; \
+ (BUF).head = 0; \
+ (BUF).tail = 0; \
+ } while(0)
+
+#define cb_size(BUF) ((BUF).size)
+#define cb_full(BUF) ((BUF).occup == (BUF).size)
+#define cb_empty(BUF) ((BUF).occup == 0)
+#define cb_occupation(BUF) ((BUF).occup)
+#define cb_reset(BUF) \
+ do { \
+ (BUF).head = 0; \
+ (BUF).tail = 0; \
+ (BUF).occup = 0; \
+ } while(0)
+
+/* TODO: replace occup by calculations w/ head and tail? */
+#define cb_push(BUF, ELEM) \
+ do { \
+ ((BUF).data)[(BUF).tail] = (ELEM); \
+ if ((BUF).tail == cb_size(BUF) - 1) { \
+ (BUF).tail = 0; \
+ } else { \
+ (BUF).tail = ((BUF).tail + 1); \
+ } \
+ if (cb_full((BUF))) { \
+ if ((BUF).head == cb_size(BUF) - 1) { \
+ (BUF).head = 0; \
+ } else { \
+ (BUF).head = ((BUF).head + 1); \
+ } \
+ } else { \
+ (BUF).occup = (BUF).occup + 1; \
+ } \
+ } while(0)
+
+#define cb_pop(BUF, ELEM) \
+ do { \
+ if(!cb_empty((BUF))) { \
+ (ELEM) = (BUF).data[(BUF).head]; \
+ if ((BUF).head == cb_size(BUF) - 1) { \
+ (BUF).head = 0; \
+ } else { \
+ (BUF).head = ((BUF).head + 1); \
+ } \
+ (BUF).occup -= 1; \
+ } \
+ } while(0)
+
+#endif