Discussion:
Short example showing async read and write
Uwe Bonnes
2018-05-31 13:24:42 UTC
Permalink
From 8b3de1f2b75119eb6d13761018085112b4bc2457 Mon Sep 17 00:00:00 2001
From: Uwe Bonnes <***@elektron.ikp.physik.tu-darmstadt.de>
Date: Thu, 31 May 2018 15:22:05 +0200
Subject: examples/async.c : Short example using async reda/write.

---
examples/CMakeLists.txt | 2 +
examples/async.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 149 insertions(+)
create mode 100644 examples/async.c

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 97ab096..6155756 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -14,6 +14,7 @@ add_executable(serial_test serial_test.c)
add_executable(baud_test baud_test.c)
add_executable(stream_test stream_test.c)
add_executable(eeprom eeprom.c)
+add_executable(async async.c)

# Linkage
target_link_libraries(simple ftdi1)
@@ -26,6 +27,7 @@ target_link_libraries(serial_test ftdi1)
target_link_libraries(baud_test ftdi1)
target_link_libraries(stream_test ftdi1)
target_link_libraries(eeprom ftdi1)
+target_link_libraries(async ftdi1)

# libftdi++ examples
if( FTDIPP )
diff --git a/examples/async.c b/examples/async.c
new file mode 100644
index 0000000..08457b9
--- /dev/null
+++ b/examples/async.c
@@ -0,0 +1,147 @@
+/* LIBFTDI EEPROM access example
+
+ This program is distributed under the GPL, version 2
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <ftdi.h>
+
+int main(int argc, char **argv)
+{
+ struct ftdi_context *ftdi;
+ int do_read = 0;
+ int do_write = 0;
+ int i, f, retval;
+
+ if ((ftdi = ftdi_new()) == 0)
+ {
+ fprintf(stderr, "Failed to allocate ftdi structure :%s \n",
+ ftdi_get_error_string(ftdi));
+ return EXIT_FAILURE;
+ }
+
+ while ((i = getopt(argc, argv, "brw")) != -1)
+ {
+ switch (i)
+ {
+ case 'b':
+ do_read = 1;
+ do_write = 1;
+ break;
+ case 'r':
+ do_read = 1;
+ break;
+ case 'w':
+ do_write = 1;
+ break;
+ default:
+ fprintf(stderr, "usage: %s [options]\n", *argv);
+ fprintf(stderr, "\t-b do synchronous read and write\n");
+ fprintf(stderr, "\t-r do synchronous read\n");
+ fprintf(stderr, "\t-w do synchronous write\n");
+ retval = -1;
+ goto done;
+ }
+ }
+
+ // Select first interface
+ ftdi_set_interface(ftdi, INTERFACE_ANY);
+
+ struct ftdi_device_list *devlist;
+ int res;
+ if ((res = ftdi_usb_find_all(ftdi, &devlist, 0, 0)) < 0)
+ {
+ fprintf(stderr, "No FTDI with default VID/PID found\n");
+ retval = EXIT_FAILURE;
+ goto do_deinit;
+ }
+ if (res > 0)
+ {
+ int i = 1;
+ f = ftdi_usb_open_dev(ftdi, devlist[0].dev);
+ if (f < 0)
+ {
+ fprintf(stderr, "Unable to open device %d: (%s)",
+ i, ftdi_get_error_string(ftdi));
+ retval = -1;
+ goto do_deinit;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "No devices found\n");
+ retval = -1;
+ goto do_deinit;
+ }
+ ftdi_list_free(&devlist);
+ int err = ftdi_usb_purge_buffers(ftdi);
+ if (err != 0) {
+ fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
+ err, ftdi_get_error_string(ftdi));
+ retval = -1;
+ goto do_deinit;
+ }
+ /* Reset MPSSE controller. */
+ err = ftdi_set_bitmode(ftdi, 0, BITMODE_RESET);
+ if (err != 0) {
+ fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
+ err, ftdi_get_error_string(ftdi));
+ retval = -1;
+ goto do_deinit;
+ }
+ /* Enable MPSSE controller. Pin directions are set later.*/
+ err = ftdi_set_bitmode(ftdi, 0, BITMODE_MPSSE);
+ if (err != 0) {
+ fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
+ err, ftdi_get_error_string(ftdi));
+ return -1;
+ }
+ uint8_t ftdi_init[15] = {TCK_DIVISOR, 0x00, 0x00,
+ SET_BITS_HIGH, 0, 0xff,
+ GET_BITS_HIGH,
+ SET_BITS_HIGH, 0x55, 0xff,
+ GET_BITS_HIGH,
+ SET_BITS_HIGH, 0xaa, 0xff,
+ GET_BITS_HIGH};
+ struct ftdi_transfer_control *tc_read;
+ struct ftdi_transfer_control *tc_write;
+ uint8_t data[3];
+ if (do_read) {
+ tc_read = ftdi_read_data_submit(ftdi, data, 3);
+ }
+ if (do_write) {
+ tc_write = ftdi_write_data_submit(ftdi, ftdi_init, 15);
+ int transfer = ftdi_transfer_data_done(tc_write);
+ printf("Async write %d\n", transfer);
+ } else {
+ int written = ftdi_write_data(ftdi, ftdi_init, 15);
+ if (written != 15) {
+ printf("Sync write failed\n");
+ }
+ }
+ if (do_read) {
+ int transfer = ftdi_transfer_data_done(tc_read);
+ printf("Async Read %d\n", transfer);
+ } else {
+ int index = 0;
+ while (index < 3) {
+ int res = ftdi_read_data(ftdi, data + index, 3 - index);
+ if (res < 0) {
+ printf("Async read failure at %d\n", index);
+ } else {
+ index += res;
+ }
+ }
+ }
+ printf("Read %02x %02x %02x\n", data[0], data[1], data[2]);
+done:
+ ftdi_usb_close(ftdi);
+do_deinit:
+ ftdi_free(ftdi);
+ return retval;
+}
--
2.13.6
--
Uwe Bonnes ***@elektron.ikp.physik.tu-darmstadt.de

--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Thomas Jarosch
2018-06-01 08:20:41 UTC
Permalink
Good morning Uwe,
Post by Uwe Bonnes
From 8b3de1f2b75119eb6d13761018085112b4bc2457 Mon Sep 17 00:00:00 2001
Date: Thu, 31 May 2018 15:22:05 +0200
Subject: examples/async.c : Short example using async reda/write.
applied, thanks! It's very good to have more example code.


May I ask for a small follow up patch as this is an
example code others could learn from?

- Replace magic numbers "15" and "3" in the code with constants.

- Have a short description what the code does at the beginning
of the file. Ideally describe that it's using MPSEE mode or
actually why it's using that.


In fact it currently states:

"LIBFTDI EEPROM access example"

:D

- Regarding the "while (index < 3)" loop: Here's a part that
I'm a bit unsure about: Should we add a safety exit condition
to the loop?

[Just a few days ago I debugged a full spool partiton on a customer
machine because the fax subsystem was stuck in an endless loop
outputting five log messages per second. The code in question included a newly
added rate limiting code and other safety measures, but somehow the
exit condition of the loop still wasn't triggered]

NASA "code rule" number two comes to mind:
https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code

"2. All loops must have fixed bounds. This prevents runaway code."


Cheers,
Thomas




--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Uwe Bonnes
2018-06-01 09:26:52 UTC
Permalink
Hello Thomas,
...
Thomas> May I ask for a small follow up patch as this is an example code
Thomas> others could learn from?

Thomas> - Replace magic numbers "15" and "3" in the code with constants.

Thomas> - Have a short description what the code does at the beginning
Thomas> of the file. Ideally describe that it's using MPSEE mode or
Thomas> actually why it's using that.


Thomas> In fact it currently states:

Thomas> "LIBFTDI EEPROM access example"

Thomas> :D

Thomas> - Regarding the "while (index < 3)" loop: Here's a part that I'm
Thomas> a bit unsure about: Should we add a safety exit condition to the
Thomas> loop?

Thomas> [Just a few days ago I debugged a full spool partiton on a
Thomas> customer machine because the fax subsystem was stuck in an
Thomas> endless loop outputting five log messages per second. The code
Thomas> in question included a newly added rate limiting code and other
Thomas> safety measures, but somehow the exit condition of the loop
Thomas> still wasn't triggered]

Thomas> NASA "code rule" number two comes to mind:
Thomas> https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code

Thomas> "2. All loops must have fixed bounds. This prevents runaway
Thomas> code."

Are checks and a resulting break allowed inside an infinit loop?

Please find a code cleanup appended.

Bye
--
Uwe Bonnes ***@elektron.ikp.physik.tu-darmstadt.de

Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 1623569 ------- Fax. 06151 1623305 ---------
From 687cd1de886b40a70c3d1998463505e9c6db8916 Mon Sep 17 00:00:00 2001
From: Uwe Bonnes <***@elektron.ikp.physik.tu-darmstadt.de>
Date: Fri, 1 Jun 2018 11:18:01 +0200
Subject: examples/async.c: Cleanup and explanations.

---
examples/async.c | 56 ++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 44 insertions(+), 12 deletions(-)

diff --git a/examples/async.c b/examples/async.c
index 08457b9..0589479 100644
--- a/examples/async.c
+++ b/examples/async.c
@@ -1,8 +1,22 @@
-/* LIBFTDI EEPROM access example
+/* Libftdi example for asynchronous read/write.

This program is distributed under the GPL, version 2
*/

+/* This programm switches to MPSSE mode, and sets and then reads back
+ * the high byte 3 times with three different values.
+ * The expected read values are hard coded in ftdi_init
+ * with 0x00, 0x55 and 0xaa
+ *
+ * Make sure that that nothing else drives some bit of the high byte
+ * or expect a collision for a very short time and some differences
+ * in the data read back.
+ *
+ * Result should be the same without any option or with either
+ * -r or -w or -b.
+ */
+
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -49,7 +63,7 @@ int main(int argc, char **argv)
}
}

- // Select first interface
+ /* Select first free interface */
ftdi_set_interface(ftdi, INTERFACE_ANY);

struct ftdi_device_list *devlist;
@@ -101,41 +115,59 @@ int main(int argc, char **argv)
err, ftdi_get_error_string(ftdi));
return -1;
}
- uint8_t ftdi_init[15] = {TCK_DIVISOR, 0x00, 0x00,
+#define DATA_TO_READ 3
+ uint8_t ftdi_init[] = {TCK_DIVISOR, 0x00, 0x00,
+ /* Set High byte to zero.*/
SET_BITS_HIGH, 0, 0xff,
GET_BITS_HIGH,
+ /* Set High byte to 0x55.*/
SET_BITS_HIGH, 0x55, 0xff,
GET_BITS_HIGH,
+ /* Set High byte to 0xaa.*/
SET_BITS_HIGH, 0xaa, 0xff,
- GET_BITS_HIGH};
+ GET_BITS_HIGH,
+ /* Set back to high impedance.*/
+ SET_BITS_HIGH, 0x00, 0x00 };
struct ftdi_transfer_control *tc_read;
struct ftdi_transfer_control *tc_write;
uint8_t data[3];
if (do_read) {
- tc_read = ftdi_read_data_submit(ftdi, data, 3);
+ tc_read = ftdi_read_data_submit(ftdi, data, DATA_TO_READ);
}
if (do_write) {
- tc_write = ftdi_write_data_submit(ftdi, ftdi_init, 15);
+ tc_write = ftdi_write_data_submit(ftdi, ftdi_init, sizeof(ftdi_init));
int transfer = ftdi_transfer_data_done(tc_write);
- printf("Async write %d\n", transfer);
+ if (transfer != sizeof(ftdi_init)) {
+ printf("Async write failed : %d\n", transfer);
+ }
} else {
- int written = ftdi_write_data(ftdi, ftdi_init, 15);
- if (written != 15) {
- printf("Sync write failed\n");
+ int written = ftdi_write_data(ftdi, ftdi_init, sizeof(ftdi_init));
+ if (written != sizeof(ftdi_init)) {
+ printf("Sync write failed: %d\n", written);
}
}
if (do_read) {
int transfer = ftdi_transfer_data_done(tc_read);
- printf("Async Read %d\n", transfer);
+ if (transfer != DATA_TO_READ) {
+ printf("Async Read failed:%d\n", transfer);
+ }
} else {
int index = 0;
- while (index < 3) {
+ ftdi->usb_read_timeout = 1;
+ int i = 1000; /* Fail if read did not succeed in 1 second.*/
+ while (i--) {
int res = ftdi_read_data(ftdi, data + index, 3 - index);
if (res < 0) {
printf("Async read failure at %d\n", index);
} else {
index += res;
}
+ if (res == 3) {
+ break;
+ }
+ }
+ if (i < 1) {
+ printf("Async read unsuccessfull\n");
}
}
printf("Read %02x %02x %02x\n", data[0], data[1], data[2]);
--
2.13.6


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Thomas Jarosch
2018-06-01 16:40:15 UTC
Permalink
Hi Uwe,
Post by Uwe Bonnes
https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety->> Critical_Code
Are checks and a resulting break allowed inside an infinit loop?
good question, actually I don't know.
Post by Uwe Bonnes
Please find a code cleanup appended.
applied, thanks. Now we can fly to Mars using this example ;)

Cheers,
Thomas




--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Loading...