]> rtime.felk.cvut.cz Git - eurobot/public.git/commitdiff
sick-tim3xx: Add first version of sick daemon.
authorMatous Pokorny <matous.pokorny@me.com>
Fri, 14 Sep 2012 14:03:40 +0000 (16:03 +0200)
committerMatous Pokorny <matous.pokorny@me.com>
Fri, 14 Sep 2012 14:03:40 +0000 (16:03 +0200)
src/sick-tim3xx/Makefile.omk
src/sick-tim3xx/sickd.c [new file with mode: 0644]
src/sick-tim3xx/tim3xx_example.c [moved from src/sick-tim3xx/tim3xx.c with 100% similarity]

index 1d6f0394a809cc40ec15a60c0b7fd27fb90482ff..039d3b892978faed4e8a8aa9509c04b9964f2b4c 100644 (file)
@@ -4,5 +4,8 @@
 INCLUDES += $(shell pkg-config libusb-1.0 --cflags)
 LDFLAGS += $(shell pkg-config libusb-1.0 --libs)
 
-bin_PROGRAMS = sick-tim
-sick-tim_SOURCES = tim3xx.c
+test_PROGRAMS = test_sick
+test_sick_SOURCES = tim3xx_example.c
+
+bin_PROGRAMS = sickd
+sickd_SOURCES = sickd.c
\ No newline at end of file
diff --git a/src/sick-tim3xx/sickd.c b/src/sick-tim3xx/sickd.c
new file mode 100644 (file)
index 0000000..637b468
--- /dev/null
@@ -0,0 +1,501 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb-1.0/libusb.h>
+#include <robottype.h>
+#include <roboorte_robottype.h>
+
+/**
+ * Function prototypes.
+ */
+ssize_t getSOPASDeviceList(libusb_context *ctx, uint16_t vendorID, uint16_t productID, libusb_device ***list);
+void freeSOPASDeviceList(libusb_device **list);
+void printUSBDeviceDetails(struct libusb_device_descriptor desc);
+void printUSBInterfaceDetails(libusb_device* device);
+
+void printSOPASDeviceInformation(ssize_t numberOfDevices, libusb_device** devices);
+int sendSOPASTelegram(libusb_device_handle* device_handle, const char* request, unsigned int timeout);
+int receiveSOPASTelegram(libusb_device_handle* device_handle, unsigned char* receiveBuffer, int receiveBufferSize, unsigned int timeout);
+int read_scan(libusb_device_handle* device_handle, unsigned short * ranges, unsigned short * intensities, int size);
+
+int main(void) {
+
+    printf("SICK TIM3xx daemon\n\n");
+
+    /*
+     * Create and initialize a new LIBUSB session.
+     */
+    libusb_context *ctx = NULL;
+    int result = libusb_init(&ctx);
+    if (result != 0) {
+        fprintf(stderr,"LIBUSB - Initialization failed with the following error code: %i.\n", result);
+    }
+
+    /*
+     * Set the verbosity level to 3 as suggested in the documentation.
+     */
+    libusb_set_debug(ctx, 3);
+
+    /*
+     * Get a list of all SICK TIM3xx devices connected to the USB bus.
+     *
+     * As a shortcut, you can also use the LIBUSB function:
+     * libusb_open_device_with_vid_pid(ctx, 0x19A2, 0x5001).
+     */
+    libusb_device **devices = NULL;
+    int vendorID = 0x19A2; // SICK AG
+    int deviceID = 0x5001; // TIM3XX
+    ssize_t numberOfDevices = getSOPASDeviceList(ctx, vendorID, deviceID, &devices);
+
+    /*
+     * If available, open the first SICK TIM3xx device.
+     */
+    if (numberOfDevices > 0) {
+
+        /*
+         * Print out the SOPAS device information to the console.
+         */
+        printSOPASDeviceInformation(numberOfDevices, devices);
+
+        /*
+         * Open the device handle and detach all kernel drivers.
+         */
+        libusb_device_handle *device_handle;
+        libusb_open(devices[0], &device_handle);
+        if (device_handle == NULL) {
+            fprintf(stderr, "\nLIBUSB - Cannot open device\n");
+        } else {
+            printf("\nLIBUSB - Device opened\n");
+        }
+
+        if (libusb_kernel_driver_active(device_handle, 0) == 1) {
+            printf("LIBUSB - Kernel driver active\n");
+            if (libusb_detach_kernel_driver(device_handle, 0) == 0) {
+                printf("LIBUSB - Kernel driver detached!\n");
+            }
+        }
+
+        /*
+         * Claim the interface 0
+         */
+        result = libusb_claim_interface(device_handle, 0);
+        if (result < 0) {
+            fprintf(stderr, "LIBUSB - Cannot claim interface\n");
+        } else {
+            printf("LIBUSB - Claimed interface\n");
+        }
+
+        /*
+         * Read the SOPAS variable 'LMDscandata' by name.
+         */
+//         const char requestScanData[] = { "\x02sRN LMDscandata\x03\0" };
+//         unsigned char receiveBuffer[65536];
+//         
+//         result = sendSOPASTelegram(device_handle, requestScanData, 500);
+//         if (result != 0) {
+//             fprintf(stderr, "SOPAS - Error sending command.\n");
+//         }
+//         
+//         result = receiveSOPASTelegram(device_handle, receiveBuffer,65535, 500);
+//         if (result != 0) {
+//             fprintf(stderr, "SOPAS - Error receiving command.\n");
+//         }
+//         
+//         printf("LIBUSB - Read data...  %s\n\n", receiveBuffer);
+        
+        unsigned short ranges[271];
+        unsigned short intensities[271];
+        read_scan(device_handle, ranges, intensities, 271);
+        
+        /*
+         * Release the interface
+         */
+        result = libusb_release_interface(device_handle, 0);
+        if (result != 0) {
+            fprintf(stderr, "LIBUSB - Cannot Release Interface\n");
+        }
+        printf("LIBUSB - Released Interface\n");
+
+        /*
+         * Close the device handle.
+         */
+        libusb_close(device_handle);
+    }
+    else
+    {
+        fprintf(stderr, "Error, no SICK Tim3xx device found\n\n");
+    }
+
+    /*
+     * Free the list of the USB devices.
+     */
+    freeSOPASDeviceList(devices);
+
+    /*
+     * Close the LIBUSB session.
+     */
+    libusb_exit(ctx);
+
+    printf("SICK TIM3xx daemon finished\n\n");
+
+    return EXIT_SUCCESS;
+}
+
+int read_scan(libusb_device_handle* device_handle, unsigned short * ranges, unsigned short * intensities, int size)
+{
+  int result = 0;
+  unsigned char receiveBuffer[65536];
+  unsigned char receiveBufferCopy[65536]; // only for debugging
+  int actual_length = 0;
+  static const size_t NUM_FIELDS = 580;
+  char* fields[NUM_FIELDS];
+  size_t count;
+  static unsigned int iteration_count = 0;
+
+  result = libusb_bulk_transfer(device_handle, (1 | LIBUSB_ENDPOINT_IN), receiveBuffer, 65535, &actual_length, 0);
+  if (result != 0)
+  {
+    if (result == LIBUSB_ERROR_TIMEOUT)
+    {
+      fprintf(stderr, "LIBUSB - Read Error: LIBUSB_ERROR_TIMEOUT.");
+      return EXIT_SUCCESS; // return success to continue looping
+    }
+    else
+    {
+      fprintf(stderr, "LIBUSB - Read Error: %i.", result);
+      return EXIT_FAILURE;
+    }
+  }
+
+  receiveBuffer[actual_length] = 0;
+  //printf("LIBUSB - Read data...  %s", receiveBuffer);
+
+  // ----- tokenize
+  //strncpy((char*)receiveBufferCopy, (char*)receiveBuffer, 65535); // receiveBuffer will be changed by strtok
+  //receiveBufferCopy[65535] = 0;
+
+  count = 0;
+  fields[count] = strtok((char *)receiveBuffer, " ");
+  // ROS_DEBUG("%d: %s ", count, fields[count]);
+
+  while (fields[count] != NULL)
+  {
+    count++;
+    if (count > NUM_FIELDS)
+      break;
+
+    fields[count] = strtok(NULL, " ");
+    // ROS_DEBUG("%d: %s ", count, fields[count]);
+  }
+
+  if (count < NUM_FIELDS)
+  {
+    fprintf(stderr, 
+        "received less fields than expected fields (actual: %zu, expected: %zu), ignoring scan", count, NUM_FIELDS);
+    // ROS_DEBUG("received message was: %s", receiveBufferCopy);
+    return EXIT_SUCCESS; // return success to continue looping
+  }
+  else if (count > NUM_FIELDS)
+  {
+    fprintf(stderr, "received more fields than expected (expected: %zu), ignoring scan", NUM_FIELDS);
+    // ROS_DEBUG("received message was: %s", receiveBufferCopy);
+    return EXIT_SUCCESS; // return success to continue looping
+  }
+
+  // ----- read fields into msg
+  //sensor_msgs::LaserScan msg;
+
+  // <STX> (\x02)
+  // 0: Type of command (SN)
+  // 1: Command (LMDscandata)
+  // 2: Firmware version number (1)
+  // 3: Device number (1)
+  // 4: Serial number (B96518)
+  // 5 + 6: Device Status (0 0 = ok, 0 1 = error)
+  // 7: Telegram counter (99)
+  // 8: Scan counter (9A)
+  // 9: Time since startup (13C8E59)
+  // 10: Time of transmission (13C9CBE)
+  // 11 + 12: Input status (0 0)
+  // 13 + 14: Output status (8 0)
+  // 15: Reserved Byte A (0)
+
+  // 16: Scanning Frequency (5DC)
+  unsigned short scanning_freq = -1;
+  sscanf(fields[16], "%hx", &scanning_freq);
+  //msg.scan_time = 1.0 / (scanning_freq / 100.0);
+  // ROS_DEBUG("hex: %s, scanning_freq: %d, scan_time: %f", fields[16], scanning_freq, msg.scan_time);
+
+  // 17: Measurement Frequency (36)
+  unsigned short measurement_freq = -1;
+  sscanf(fields[17], "%hx", &measurement_freq);
+  //msg.time_increment = 1.0 / (measurement_freq * 100.0);
+  // ROS_DEBUG("measurement_freq: %d, time_increment: %f", measurement_freq, msg.time_increment);
+
+  // 18: Number of encoders (0)
+  // 19: Number of 16 bit channels (1)
+  // 20: Measured data contents (DIST1)
+
+  // 21: Scaling factor (3F800000)
+  // ignored for now (is always 1.0):
+//      unsigned int scaling_factor_int = -1;
+//      sscanf(fields[21], "%x", &scaling_factor_int);
+//
+//      float scaling_factor = reinterpret_cast<float&>(scaling_factor_int);
+//      // ROS_DEBUG("hex: %s, scaling_factor_int: %d, scaling_factor: %f", fields[21], scaling_factor_int, scaling_factor);
+
+  // 22: Scaling offset (00000000) -- always 0
+  // 23: Starting angle (FFF92230)
+  int starting_angle = -1;
+  sscanf(fields[23], "%x", &starting_angle);
+  //msg.angle_min = (starting_angle / 10000.0) / 180.0 * M_PI - M_PI / 2;
+  // ROS_DEBUG("starting_angle: %d, angle_min: %f", starting_angle, msg.angle_min);
+
+  // 24: Angular step width (2710)
+  unsigned short angular_step_width = -1;
+  sscanf(fields[24], "%hx", &angular_step_width);
+  //msg.angle_increment = (angular_step_width / 10000.0) / 180.0 * M_PI;
+  //msg.angle_max = msg.angle_min + 270.0 * msg.angle_increment;
+
+  // adjust angle_min to min_ang config param
+  
+  int index_min = 0;
+//   while (msg.angle_min + msg.angle_increment < config_.min_ang)
+//   {
+//     msg.angle_min += msg.angle_increment;
+//     index_min++;
+//   }
+
+  // adjust angle_max to max_ang config param
+  int index_max = 270;
+  if (size <= index_max)
+  {
+    fprintf(stderr, "Size of fields ranges and intensities is small!");
+    return 1;
+  }
+//   while (msg.angle_max - msg.angle_increment > config_.max_ang)
+//   {
+//     msg.angle_max -= msg.angle_increment;
+//     index_max--;
+//   }
+  
+  //ROS_DEBUG("index_min: %d, index_max: %d", index_min, index_max);
+  // ROS_DEBUG("angular_step_width: %d, angle_increment: %f, angle_max: %f", angular_step_width, msg.angle_increment, msg.angle_max);
+
+  // 25: Number of data (10F)
+
+  // 26..296: Data_1 .. Data_n
+  //msg.ranges.resize(index_max - index_min + 1);
+  int j;
+  for (j = index_min; j <= index_max; ++j)
+  {
+    unsigned short range;
+    sscanf(fields[j + 26], "%hx", &range);
+    ranges[j - index_min] = range; // /1000.0;
+  }
+
+  // 297: Number of 8 bit channels (1)
+  // 298: Measured data contents (RSSI1)
+  // 299: Scaling factor (3F800000)
+  // 300: Scaling offset (00000000)
+  // 301: Starting angle (FFF92230)
+  // 302: Angular step width (2710)
+  // 303: Number of data (10F)
+  // 304..574: Data_1 .. Data_n
+  if (intensities != NULL)
+  {
+    //msg.intensities.resize(index_max - index_min + 1);
+    int j;
+    for (j = index_min; j <= index_max; ++j)
+    {
+      unsigned short intensity;
+      sscanf(fields[j + 304], "%hx", &intensity);
+      intensities[j - index_min] = intensity;
+    }
+  }
+
+  // 575: Position (0)
+  // 576: Name (0)
+  // 577: Comment (0)
+  // 578: Time information (0)
+  // 579: Event information (0)
+  // <ETX> (\x03)
+
+  //msg.range_min = 0.05;
+  //msg.range_max = 4.0;
+
+  // ----- adjust start time
+  // - last scan point = now  ==>  first scan point = now - 271 * time increment
+  //msg.header.stamp = start_time - ros::Duration().fromSec(271 * msg.time_increment);
+
+  // - shift forward to time of first published scan point
+  //msg.header.stamp += ros::Duration().fromSec((double)index_min * msg.time_increment);
+
+  // - add time offset (to account for USB latency etc.)
+  //msg.header.stamp += ros::Duration().fromSec(config_.time_offset);
+
+  //pub_.publish(msg);
+  return EXIT_SUCCESS;
+}
+
+/**
+ * Returns a list of USB devices currently attached to the system and matching the given vendorID and productID.
+ */
+ssize_t getSOPASDeviceList(libusb_context *ctx, uint16_t vendorID, uint16_t productID, libusb_device ***list) {
+
+    libusb_device **resultDevices = NULL;
+    ssize_t numberOfResultDevices = 0;
+
+    libusb_device **devices;
+    ssize_t numberOfDevices;
+
+    /*
+     * Get a list of all USB devices connected.
+     */
+    numberOfDevices = libusb_get_device_list(ctx, &devices);
+
+    /*
+     * Iterate through the list of the connected USB devices and search for devices with the given vendorID and prodcutID.
+     */
+    ssize_t i;
+    for (i = 0; i < numberOfDevices; i++) {
+
+        struct libusb_device_descriptor desc;
+        int result = libusb_get_device_descriptor(devices[i], &desc);
+        if (result < 0) {
+            fprintf(stderr, "LIBUSB - Failed to get device descriptor");
+        }
+
+        if (desc.idVendor == vendorID && desc.idProduct == 0x5001) {
+
+            /*
+             * Add the matching device to the function result list and increase the device reference count.
+             */
+            resultDevices = realloc(resultDevices, sizeof(libusb_device *) + (numberOfResultDevices + 1));
+            if (resultDevices == NULL) {
+                fprintf(stderr, "LIBUSB - Failed to allocate memory for the device result list.");
+            } else {
+                resultDevices[numberOfResultDevices] = devices[i];
+                resultDevices[numberOfResultDevices + 1] = NULL;
+                libusb_ref_device(devices[i]);
+                numberOfResultDevices++;
+            }
+        }
+    }
+
+    /*
+     * Free the list of the connected USB devices and decrease the device reference count.
+     */
+    libusb_free_device_list(devices, 1);
+
+    /*
+     * Prepare the return values of the function.
+     */
+    *list = resultDevices;
+    return numberOfResultDevices;
+}
+
+/*
+ * Free the list of devices obtained from the function 'getSOPASDeviceList'.
+ */
+void freeSOPASDeviceList(libusb_device **list) {
+
+    if (!list)
+        return;
+
+    int i = 0;
+    struct libusb_device *dev;
+    while ((dev = list[i++]) != NULL)
+        libusb_unref_device(dev);
+
+    free(list);
+}
+
+/*
+ * Print the device details such as USB device class, vendor id and product id to the console.
+ */
+void printUSBDeviceDetails(struct libusb_device_descriptor desc) {
+
+    printf("Device Class: 0x%x\n", desc.bDeviceClass);
+    printf("VendorID:     0x%x\n", desc.idVendor);
+    printf("ProductID:    0x%x\n", desc.idProduct);
+}
+
+
+/**
+ * Print the USB device information of the connected TIM3xx devices to the console.
+ */
+void printSOPASDeviceInformation(ssize_t numberOfDevices, libusb_device** devices) {
+    ssize_t i;
+    for (i = 0; i < numberOfDevices; i++) {
+        struct libusb_device_descriptor desc;
+        int result = libusb_get_device_descriptor(devices[i], &desc);
+        if (result < 0) {
+            fprintf(stderr, "LIBUSB - Failed to get device descriptor");
+        }
+        if (result == 0) {
+            printf("SICK AG - TIM3XX - [%i]\n", ((int)i + 1));
+            printf("----------------------------------------\n");
+            printUSBDeviceDetails(desc);
+            printf("----------------------------------------\n");
+        }
+    }
+
+    if (numberOfDevices == 0) {
+        printf("LIBUSB - No SICK TIM3xx device connected.\n");
+    }
+}
+
+/**
+ * Send a SOPAS command to the device.
+ * Example of the request: const char requestScanData[] = { "\x02sRN LMDscandata\x03\0" };
+ * \x02 - STX (Start of TeXt, start of the telegram)
+ * sRN - Read by Name
+ * LMDscandata - request for measured data
+ * \x03 - ETX (End of TeXt, end of the telegram)
+ * \0 - end of string
+ * For more details, see document "Telegrams for Configuring and Operating the LMS1xx, LMS5xx,
+ * TiM3xx, JEF300, JEF500".
+ */
+int sendSOPASTelegram(libusb_device_handle* device_handle, const char* request, unsigned int timeout) {
+
+    int result = 0;
+
+    /*
+     * Write a SOPAS variable read request to the device.
+     */
+    printf("\nLIBUSB - Write data... %s\n", request);
+
+    int actual = 0;
+    int requestLength = strlen(request);
+    result = libusb_bulk_transfer(device_handle, (2 | LIBUSB_ENDPOINT_OUT), (unsigned char*) request, requestLength, &actual, 0);
+    if (result != 0 || actual != requestLength) {
+        fprintf(stderr, "LIBUSB - Write Error: %i.\n", result);
+    }
+
+    return result;
+}
+
+/**
+ * Receive a SOPAS telegram from the device.
+ * For more details, see document "Telegrams for Configuring and Operating the LMS1xx, LMS5xx,
+ * TiM3xx, JEF300, JEF500".
+ */
+int receiveSOPASTelegram(libusb_device_handle* device_handle, unsigned char* receiveBuffer, int receiveBufferSize, unsigned int timeout) {
+
+    int result = 0;
+    int actual = 0;
+    
+    /*
+     * Read the SOPAS device response with the given timeout.
+     */
+    result = libusb_bulk_transfer(device_handle, (1 | LIBUSB_ENDPOINT_IN), receiveBuffer, receiveBufferSize, &actual, timeout);
+    if (result != 0) {
+        fprintf(stderr, "LIBUSB - Read Error: %i.\n", result);
+    }
+    
+    // Place zero on the end of the string
+    receiveBuffer[actual] = 0;
+
+    return result;
+}
\ No newline at end of file