aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2012-06-14 16:08:01 +0200
committerJakob Odersky <jodersky@gmail.com>2012-06-14 16:08:01 +0200
commit774eb21b30cddabf002d65bc686cf2450f82c8a0 (patch)
treefcbdfc04bae1466fcde6fdd753044fa9aede7597
parent9c5d35731c84d74e97b4fe24c9b58b11e969c687 (diff)
downloadk8055-774eb21b30cddabf002d65bc686cf2450f82c8a0.tar.gz
k8055-774eb21b30cddabf002d65bc686cf2450f82c8a0.tar.bz2
k8055-774eb21b30cddabf002d65bc686cf2450f82c8a0.zip
total refactor
*Devices are no longer handled by their port numbers but by passing a `device structure'. This eliminates the need of a global variable, associating port numbers to devices. *Analog inputs/outputs and counters are zero-indexed in their names, i.e. `analog1' is now called `analog0' in any definitions
-rw-r--r--src/k8055.c220
-rw-r--r--src/k8055.h81
2 files changed, 128 insertions, 173 deletions
diff --git a/src/k8055.c b/src/k8055.c
index 4a2fd3e..d136a4a 100644
--- a/src/k8055.c
+++ b/src/k8055.c
@@ -98,31 +98,36 @@
#define USB_IN_EP 0x81 /* USB Input endpoint */
#define USB_TIMEOUT 20 /* [ms] */
+#define WRITE_TRIES 3 /* maximum number of write tries */
+#define READ_TRIES 3/* maximum number of read tries */
+
#define IN_DIGITAL_OFFSET 0
-#define IN_ANALOG_1_OFFSET 2
-#define IN_ANALOG_2_OFFSET 3
-#define IN_COUNTER_1_OFFSET 4
-#define IN_COUNTER_2_OFFSET 6
+#define IN_ANALOG_0_OFFSET 2
+#define IN_ANALOG_1_OFFSET 3
+#define IN_COUNTER_0_OFFSET 4
+#define IN_COUNTER_1_OFFSET 6
+#define OUT_CMD_OFFEST 0
#define OUT_DIGITAL_OFFSET 1
-#define OUT_ANALOG_1_OFFSET 2
-#define OUT_ANALOG_2_OFFSET 3
-#define OUT_COUNTER_1_OFFSET 4
-#define OUT_COUNTER_2_OFFSET 5
-#define OUT_COUNTER_1_DEBOUNCE_OFFSET 6
-#define OUT_COUNTER_2_DEBOUNCE_OFFSET 7
+#define OUT_ANALOG_0_OFFSET 2
+#define OUT_ANALOG_1_OFFSET 3
+#define OUT_COUNTER_0_OFFSET 4
+#define OUT_COUNTER_1_OFFSET 5
+#define OUT_COUNTER_0_DEBOUNCE_OFFSET 6
+#define OUT_COUNTER_1_DEBOUNCE_OFFSET 7
#define CMD_RESET 0
#define CMD_SET_DEBOUNCE_1 1
#define CMD_SET_DEBOUNCE_2 2
-#define CMD_RESET_COUNTER_1 3
-#define CMD_RESET_COUNTER_2 4
+#define CMD_RESET_COUNTER_0 3
+#define CMD_RESET_COUNTER_1 4
#define CMD_SET_ANALOG_DIGITAL 5
-#include <libusb.h>
+#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
+#include <libusb.h>
#include "k8055.h"
/** Represents a Vellemean K8055 USB board. */
@@ -131,30 +136,18 @@ typedef struct k8055_device {
/** Data last read from device, used by read_data(). */
unsigned char data_in[PACKET_LENGTH];
- /** Data to be sent to the device, used by write_data(). */
+ /** Data to be sent to the device, used by k8055_write_data(). */
unsigned char data_out[PACKET_LENGTH];
/** Underlying libusb handle to device. NULL if the device is not open. */
libusb_device_handle *device_handle;
} k8055_device;
-
-/* Global Variables
-* ================
-* Yes, unfortunately. However, as this program is meant to be a driver,
-* access to these variables from the outside should not occur. */
-
/** Libusb context. */
static libusb_context* context = NULL;
-
-/** This array contains all K8055 devices, regardless of their connection status. The index corresponds to a device's port. */
-static k8055_device devices[K8055_MAX_DEVICES];
-
+static int k8055_open_devices = 0;
static int DEBUG = 0;
-/* end global variables */
-
-
/** Prints the given message to standard output if debugging is enabled. */
static void print_error(const char * str) {
if (DEBUG) {
@@ -162,24 +155,19 @@ static void print_error(const char * str) {
}
}
-/** Retrieves the number of open devices. Internally, a device is open if it's libusb device handle is not null. */
-int k8055_count_open_devices() {
- int r = 0;
- for (int i = 0; i < K8055_MAX_DEVICES; ++i) {
- if (devices[i].device_handle != NULL) r += 1;
+int k8055_open_device(int port, k8055_device** device) {
+ if (port < 0 || K8055_MAX_DEVICES <= port) {
+ print_error("invalid port number, port p should be 0<=p<=3");
+ return K8055_ERROR_INDEX;
}
- return r;
-}
-int k8055_open_device(int port) {
- if (k8055_count_open_devices() == 0) { /* no devices are open */
+ if (k8055_open_devices == 0) { /* no devices are open */
int r = libusb_init(&context); /* initialize a new context */
if (r < 0) {
print_error("could not initialize libusb");
return K8055_ERROR_INIT_LIBUSB; /* return error code in case of error */
}
-
}
libusb_device **connected_devices = NULL;
@@ -228,43 +216,46 @@ int k8055_open_device(int port) {
print_error("could not claim interface");
return K8055_ERROR_OPEN;
}
-
- devices[port].device_handle = handle; /* mark device as open by assigning it a libusb device handle */
+
+ k8055_device* _device = NULL;
+ _device = malloc(sizeof(k8055_device));
+ if (_device == NULL) {
+ print_error("could not allocate memory for device");
+ return K8055_ERROR_MEM;
+ }
+
+ (*_device).device_handle = handle;
+ *device = _device;
+ k8055_open_devices += 1;
return 0;
}
-void k8055_close_device(int port) {
- if (devices[port].device_handle == NULL) /* already closed */
- return;
-
- libusb_release_interface(devices[port].device_handle, 0);
- libusb_close(devices[port].device_handle);
- devices[port].device_handle = NULL;
- if (k8055_count_open_devices() == 0) libusb_exit(context);
+void k8055_close_device(k8055_device* device) {
+ libusb_release_interface(device->device_handle, 0);
+ libusb_close(device->device_handle);
+ device->device_handle = NULL;
+ free(device);
+ device = NULL;
+
+ k8055_open_devices -= 1;
+
+ if (k8055_open_devices <= 0) libusb_exit(context);
}
-/** Writes the actual contained in the device's data_out field to the usb endpoint.
- * @return K8055_ERROR_INDEX if port is an invalid index
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+/** Writes the actual data contained in the device's data_out field to the usb endpoint.
+ * @return K8055_ERROR_CLOSED if the board is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process */
-static int write_data(int port) {
+static int k8055_write_data(k8055_device* device) {
int write_status = 0;
- if (port < 0 || K8055_MAX_DEVICES <= port) {
- print_error("invalid port number, port p should be 0<=p<=3");
- return K8055_ERROR_INDEX;
- }
-
- if (devices[port].device_handle == 0) {
- print_error("unable to write to port, device not open");
+ if (device->device_handle == NULL) {
+ print_error("unable to write data, device not open");
return K8055_ERROR_CLOSED;
}
- k8055_device *device = &devices[port];
-
int transferred = 0;
- for(int i=0; i < 3; ++i) {
+ for(int i=0; i < WRITE_TRIES; ++i) { /* number of tries on failure */
write_status = libusb_interrupt_transfer(
device->device_handle,
USB_OUT_EP,
@@ -282,27 +273,19 @@ static int write_data(int port) {
}
/** Reads data from the usb endpoint into the device's data_in field.
- * @return K8055_ERROR_INDEX if port is an invalid index
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_CLOSED if the board is not open
* @return K8055_ERROR_READ if another error occurred during the read process */
-static int read_data(int port, int cycles) {
+static int read_data(k8055_device* device, int cycles) {
int read_status = 0;
- if (port < 0 || K8055_MAX_DEVICES <= port) {
- print_error("invalid port number, port p should be 0<=p<=3");
- return K8055_ERROR_INDEX;
- }
-
- if (devices[port].device_handle == 0) {
- print_error("unable to read from port, device not open");
+ if (device->device_handle == NULL) {
+ print_error("unable to read data, device not open");
return K8055_ERROR_CLOSED;
}
- k8055_device *device = &devices[port];
-
int transferred = 0;
- for(int i = 0; i < 3; ++i) {
- for(int j = 0; j < cycles; ++j) { /* read twice to get fresh data, (i.e. circumvent some kind of buffer) */
+ for(int i = 0; i < READ_TRIES; ++i) { /* number of tries on failure */
+ for(int j = 0; j < cycles; ++j) { /* read at least twice to get fresh data, (i.e. circumvent some kind of buffer) */
read_status = libusb_interrupt_transfer(
device->device_handle,
USB_IN_EP,
@@ -320,8 +303,7 @@ static int read_data(int port, int cycles) {
return 0;
}
-static int int_to_debounce(int x) {
- int t = x;
+static int k8055_int_to_debounce(int t) {
/* the velleman k8055 use a exponetial formula to split up the
DebounceTime 0-7450 over value 1-255. I've tested every value and
found that the formula dbt=0,338*value^1,8017 is closest to
@@ -337,15 +319,13 @@ static int int_to_debounce(int x) {
return t;
}
-int k8055_set_all_digital(int port, int bitmask) {
- k8055_device *device = &devices[port];
+int k8055_set_all_digital(k8055_device* device, int bitmask) {
device->data_out[OUT_DIGITAL_OFFSET] = bitmask;
- device->data_out[0] = CMD_SET_ANALOG_DIGITAL;
- return write_data(port);
+ device->data_out[OUT_CMD_OFFEST] = CMD_SET_ANALOG_DIGITAL;
+ return k8055_write_data(device);
}
-int k8055_set_digital(int port, int channel, int value) {
- k8055_device *device = &devices[port];
+int k8055_set_digital(k8055_device* device, int channel, int value) {
unsigned char data = device->data_out[OUT_DIGITAL_OFFSET];
if (value == 0) /* off */
@@ -354,94 +334,82 @@ int k8055_set_digital(int port, int channel, int value) {
data = data | (1 << channel);
device->data_out[OUT_DIGITAL_OFFSET] = data;
- device->data_out[0] = CMD_SET_ANALOG_DIGITAL;
- return write_data(port);
+ device->data_out[OUT_CMD_OFFEST] = CMD_SET_ANALOG_DIGITAL;
+ return k8055_write_data(device);
}
-int k8055_set_all_analog(int port, int analog1, int analog2) {
- k8055_device *device = &devices[port];
+int k8055_set_all_analog(k8055_device* device, int analog0, int analog1) {
+ device->data_out[OUT_ANALOG_0_OFFSET] = analog0;
device->data_out[OUT_ANALOG_1_OFFSET] = analog1;
- device->data_out[OUT_ANALOG_2_OFFSET] = analog2;
- device->data_out[0] = CMD_SET_ANALOG_DIGITAL;
- return write_data(port);
+ device->data_out[OUT_CMD_OFFEST] = CMD_SET_ANALOG_DIGITAL;
+ return k8055_write_data(device);
}
-int k8055_set_analog(int port, int channel, int value) {
- k8055_device *device = &devices[port];
+int k8055_set_analog(k8055_device* device, int channel, int value) {
if (channel == 0) {
- device->data_out[OUT_ANALOG_1_OFFSET] = value;
+ device->data_out[OUT_ANALOG_0_OFFSET] = value;
} else if (channel == 1) {
- device->data_out[OUT_ANALOG_2_OFFSET] = value;
+ device->data_out[OUT_ANALOG_1_OFFSET] = value;
} else {
print_error("can't write to unknown analog port");
return K8055_ERROR_INDEX;
}
- device->data_out[0] = CMD_SET_ANALOG_DIGITAL;
- return write_data(port);
+ device->data_out[OUT_CMD_OFFEST] = CMD_SET_ANALOG_DIGITAL;
+ return k8055_write_data(device);
}
-int k8055_reset_counter(int port, int counter) {
- k8055_device *device = &devices[port];
+int k8055_reset_counter(k8055_device* device, int counter) {
if (counter == 0) {
- device->data_out[OUT_COUNTER_1_OFFSET] = 0;
- device->data_out[0] = CMD_RESET_COUNTER_1;
+ device->data_out[OUT_COUNTER_0_OFFSET] = 0;
+ device->data_out[OUT_CMD_OFFEST] = CMD_RESET_COUNTER_0;
} else if (counter == 1) {
- device->data_out[OUT_COUNTER_2_OFFSET] = 0;
- device->data_out[0] = CMD_RESET_COUNTER_2;
+ device->data_out[OUT_COUNTER_1_OFFSET] = 0;
+ device->data_out[OUT_CMD_OFFEST] = CMD_RESET_COUNTER_1;
} else {
print_error("can't reset unknown counter");
return K8055_ERROR_INDEX;
}
- return write_data(port);
+ return k8055_write_data(device);
}
-int k8055_set_debounce_time(int port, int counter, int debounce) {
- k8055_device *device = &devices[port];
+int k8055_set_debounce_time(k8055_device* device, int counter, int debounce) {
if (counter == 0) {
- device->data_out[OUT_COUNTER_1_DEBOUNCE_OFFSET] = int_to_debounce(debounce);
- device->data_out[0] = CMD_SET_DEBOUNCE_1;
+ device->data_out[OUT_COUNTER_0_DEBOUNCE_OFFSET] = k8055_int_to_debounce(debounce);
+ device->data_out[OUT_CMD_OFFEST] = CMD_SET_DEBOUNCE_1;
} else if (counter == 1) {
- device->data_out[OUT_COUNTER_2_DEBOUNCE_OFFSET] = int_to_debounce(debounce);
- device->data_out[0] = CMD_SET_DEBOUNCE_2;
+ device->data_out[OUT_COUNTER_1_DEBOUNCE_OFFSET] = k8055_int_to_debounce(debounce);
+ device->data_out[OUT_CMD_OFFEST] = CMD_SET_DEBOUNCE_2;
} else {
print_error("can't set debounce time for unknown counter");
return K8055_ERROR_INDEX;
}
- return write_data(port);
+ return k8055_write_data(device);
}
-static int get_all_cycle(int port, int *bitmask, int *analog1, int *analog2, int *counter1, int *counter2, int cycles) {
- int r = read_data(port, cycles);
+int k8055_get_all_input(k8055_device* device, int *bitmask, int *analog0, int *analog1, int *counter0, int *counter1, int quick) {
+ int cycles = 2;
+ if (quick) cycles = 1;
+ int r = read_data(device, cycles);
if (r != 0) return r;
- k8055_device *device = &devices[port];
-
if (bitmask != NULL)
*bitmask = (
((device->data_in[IN_DIGITAL_OFFSET] >> 4) & 0x03) | /* Input 1 and 2 */
((device->data_in[IN_DIGITAL_OFFSET] << 2) & 0x04) | /* Input 3 */
((device->data_in[IN_DIGITAL_OFFSET] >> 3) & 0x18)); /* Input 4 and 5 */
+ if (analog0 != NULL)
+ *analog0 = device->data_in[IN_ANALOG_0_OFFSET];
if (analog1 != NULL)
*analog1 = device->data_in[IN_ANALOG_1_OFFSET];
- if (analog2 != NULL)
- *analog2 = device->data_in[IN_ANALOG_2_OFFSET];
+ if (counter0 != NULL)
+ *counter0 = (int) device->data_in[IN_COUNTER_0_OFFSET + 1] << 8 | device->data_in[IN_COUNTER_0_OFFSET];
if (counter1 != NULL)
*counter1 = (int) device->data_in[IN_COUNTER_1_OFFSET + 1] << 8 | device->data_in[IN_COUNTER_1_OFFSET];
- if (counter2 != NULL)
- *counter2 = (int) device->data_in[IN_COUNTER_2_OFFSET + 1] << 8 | device->data_in[IN_COUNTER_2_OFFSET];
return 0;
}
-
-int k8055_get_all_input(int port, int *bitmask, int *analog1, int *analog2, int *counter1, int *counter2) {
- return get_all_cycle(port, bitmask, analog1, analog2, counter1, counter2, 2);
-}
-
-int k8055_quick_get_all_input(int port, int *bitmask, int *analog1, int *analog2, int *counter1, int *counter2) {
- return get_all_cycle(port, bitmask, analog1, analog2, counter1, counter2, 1);
-}
diff --git a/src/k8055.h b/src/k8055.h
index 21f6ae9..9b29a29 100644
--- a/src/k8055.h
+++ b/src/k8055.h
@@ -33,9 +33,12 @@
extern "C" {
#endif
+typedef struct k8055_device k8055_device;
+
enum k8055_error_code {
K8055_SUCCESS = 0,
- K8055_ERROR = -1, K8055_ERROR_INIT_LIBUSB = -2, /* error during libusb initialization */
+ K8055_ERROR = -1,
+ K8055_ERROR_INIT_LIBUSB = -2, /* error during libusb initialization */
K8055_ERROR_NO_DEVICES = -3, /* no usb devices found on host machine */
K8055_ERROR_NO_K8055 = -4, /* Velleman k8055 cannot be found (on given port) */
K8055_ERROR_ACCESS = -6, /* access denied (insufficient permissions) */
@@ -43,100 +46,84 @@ enum k8055_error_code {
K8055_ERROR_CLOSED = -8, /* device is already closed */
K8055_ERROR_WRITE = -9, /* write error */
K8055_ERROR_READ = -10, /* read error */
- K8055_ERROR_INDEX = -11 /* invalid argument (i.e. trying to access analog channel >= 2) */
+ K8055_ERROR_INDEX = -11, /* invalid argument (i.e. trying to access analog channel >= 2) */
+ K8055_ERROR_MEM = -12 /* memory allocation error */
};
/**Opens a K8055 device on the given port (i.e. address).
* @return 0 on success
+ * @return K8055_ERROR_INDEX if port is an invalid index
* @return K8055_ERROR_INIT_LIBUSB on libusb initialization error
* @return K8055_ERROR_NO_DEVICES if no usb devices are found on host system
* @return K8055_ERROR_NO_K8055 if no K8055 board is found at the given port
* @return K8055_ERROR_ACCESS if permission is denied to access a usb port
* @return K8055_ERROR_OPEN if another error occured preventing the board to be opened */
-int k8055_open_device(int port);
+int k8055_open_device(int port, k8055_device** device);
-/** Closes a board at the given port. */
-void k8055_close_device(int port);
+/** Closes the given device. */
+void k8055_close_device(k8055_device* port);
/**Sets all digital ouputs according to the given bitmask.
* @param port address of board
* @param bitmask '1' for 'on', '0' for 'off'
- * @return K8055_ERROR_INDEX if port is an invalid index
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process */
-int k8055_set_all_digital(int port, int bitmask);
+int k8055_set_all_digital(k8055_device*, int bitmask);
/**Sets a digital output at given channel.
* @param port address of board
* @param channel channel of port
* @param value output status: '1' for 'on', '0' for 'off'
- * @return K8055_ERROR_INDEX if port is an invalid index
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process */
-int k8055_set_digital(int port, int channel, int value);
+int k8055_set_digital(k8055_device*, int channel, int value);
/**Sets the values of both analog outputs.
* @param port address of board
- * @param analog1 value of first analog output
- * @param analog2 value of second analog output
- * @return K8055_ERROR_INDEX if port is an invalid index
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @param analog0 value of first analog output
+ * @param analog1 value of second analog output
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process */
-int k8055_set_all_analog(int port, int analog1, int analog2);
+int k8055_set_all_analog(k8055_device*, int analog0, int analog1);
/**Sets the value for an analog output at a given channel.
* @param port address of board
* @param channel channel of analog output (zero indexed)
* @param value value of analog output [0-255]
- * @return K8055_ERROR_INDEX if port or channel are an invalid indices
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_INDEX if channel is an invalid index
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process */
-int k8055_set_analog(int port, int channel, int value);
+int k8055_set_analog(k8055_device*, int channel, int value);
/**Resets a hardware integrated counter of the Velleman K8055 board.
* @param port address of board
* @param counter index of counter (zero indexed)
- * @return K8055_ERROR_INDEX if port or counter are invalid indices
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_INDEX if counter is an invalid index
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process */
-int k8055_reset_counter(int port, int counter);
+int k8055_reset_counter(k8055_device*, int counter);
/**Sets the debounce time of a hardware integrated counter of the Velleman K8055 board.
* @param port address of board
* @param counter index of counter (zero indexed)
* @param debounce debounce value
- * @return K8055_ERROR_INDEX if port or counter are invalid indices
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_INDEX if counter is an invalid index
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_WRITE if another error occurred during the write process*/
-int k8055_set_debounce_time(int port, int counter, int debounce);
-
-/**Reads all current data of a given board into the passed parameters. NULL is a valid parameter.
- * Data is read twice from the borad to circumvent some kind of buffer and get actual data.
- * @param port address of board
- * @param digitalBitmask bitmask value of digital inputs
- * @param analog1 value of first analog input
- * @param analog2 value of second analog input
- * @param counter1 value of first counter
- * @param counter2 value of second counter
- * @return 0 on success
- * @return K8055_ERROR_INDEX if port or counter are invalid indices
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
- * @return K8055_ERROR_READ if another error occurred during the read process */
-int k8055_get_all_input(int port, int *digitalBitmask, int *analog1, int *analog2, int *counter1, int *counter2);
+int k8055_set_debounce_time(k8055_device*, int counter, int debounce);
/**Reads all current data of a given board into the passed parameters. NULL is a valid parameter.
- * This function reads data once from the board and no guarantee of actuality is given.
+ * Unless quick is set, data is read twice from the board to circumvent some kind of buffer and get current data.
* @param port address of board
* @param digitalBitmask bitmask value of digital inputs
- * @param analog1 value of first analog input
- * @param analog2 value of second analog input
- * @param counter1 value of first counter
- * @param counter2 value of second counter
+ * @param analog0 value of first analog input
+ * @param analog1 value of second analog input
+ * @param counter0 value of first counter
+ * @param counter1 value of second counter
* @return 0 on success
- * @return K8055_ERROR_INDEX if port or counter are invalid indices
- * @return K8055_ERROR_CLOSED if the board associated to the given port is not open
+ * @return K8055_ERROR_CLOSED if the given device is not open
* @return K8055_ERROR_READ if another error occurred during the read process */
-int k8055_quick_get_all_input(int port, int *digitalBitmask, int *analog1, int *analog2, int *counter1, int *counter2);
+int k8055_get_all_input(k8055_device*, int *digitalBitmask, int *analog0, int *analog1, int *counter0, int *counter1, int quick);
#ifdef __cplusplus
}