lase_edl_aqt.cpp

00001
00002 /***************************************************************************
00003  *  acqusition_thread.cpp - Thread that retrieves the laser data
00004  *
00005  *  Created: Wed Oct 08 13:42:32 2008
00006  *  Copyright  2002       Christian Fritz
00007  *             2008-2009  Tim Niemueller [www.niemueller.de]
00008  *
00009  ****************************************************************************/
00010
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL file in the doc directory.
00022  */
00023
00024 #include "lase_edl_aqt.h"
00025
00026 #include <core/threading/mutex.h>
00027
00028 #include <cstdlib>
00029 #include <cmath>
00030 #include <string>
00031 #include <cstdio>
00032
00033 using namespace fawkes;
00034
00035 const WORD  LaseEdlAcquisitionThread::RESETLEVEL_RESET                = 0x0000;
00036 const WORD  LaseEdlAcquisitionThread::RESETLEVEL_RESTART              = 0x0001;
00037 const WORD  LaseEdlAcquisitionThread::RESETLEVEL_HALT_IDLE            = 0x0002;
00038 const WORD  LaseEdlAcquisitionThread::RESETLEVEL_RELOAD_VOLTSET       = 0x0010;
00039 const WORD  LaseEdlAcquisitionThread::CONFIGITEM_ARCNET_HISTORIC      = 0x0000;
00040 const WORD  LaseEdlAcquisitionThread::CONFIGITEM_RS232_RS422          = 0x0001;
00041 const WORD  LaseEdlAcquisitionThread::CONFIGITEM_CAN                  = 0x0002;
00042 const WORD  LaseEdlAcquisitionThread::CONFIGITEM_SPI                  = 0x0003;
00043 const WORD  LaseEdlAcquisitionThread::CONFIGITEM_ARCNET               = 0x0004;
00044 const WORD  LaseEdlAcquisitionThread::CONFIGITEM_GLOBAL               = 0x0010;
00045 const WORD  LaseEdlAcquisitionThread::CONFIGDATA_LENGTH_RS232_RS422   = 4;
00046 const WORD  LaseEdlAcquisitionThread::CONFIGDATA_LENGTH_CAN           = 5;
00047 const WORD  LaseEdlAcquisitionThread::CONFIGDATA_LENGTH_ARCNET        = 2;
00048 const WORD  LaseEdlAcquisitionThread::CONFIGDATA_LENGTH_GLOBAL        = 3;
00049 const WORD  LaseEdlAcquisitionThread::SECTOR_0                        = 0x0000;
00050 const WORD  LaseEdlAcquisitionThread::SECTOR_1                        = 0x0001;
00051 const WORD  LaseEdlAcquisitionThread::SECTOR_2                        = 0x0002;
00052 const WORD  LaseEdlAcquisitionThread::SECTOR_3                        = 0x0003;
00053 const WORD  LaseEdlAcquisitionThread::SECTOR_4                        = 0x0004;
00054 const WORD  LaseEdlAcquisitionThread::SECTOR_5                        = 0x0005;
00055 const WORD  LaseEdlAcquisitionThread::SECTOR_6                        = 0x0006;
00056 const WORD  LaseEdlAcquisitionThread::SECTOR_7                        = 0x0007;
00057 const WORD  LaseEdlAcquisitionThread::SECTORFUNC_NOT_INITIALIZED      = 0x0000;
00058 const WORD  LaseEdlAcquisitionThread::SECTORFUNC_NO_MEASUREMENT       = 0x0001;
00059 const WORD  LaseEdlAcquisitionThread::SECTORFUNC_DUMMY_MEASUREMENT    = 0x0002;
00060 const WORD  LaseEdlAcquisitionThread::SECTORFUNC_NORMAL_MEASUREMENT   = 0x0003;
00061 const WORD  LaseEdlAcquisitionThread::SECTORFUNC_REFERENCE_TARGET     = 0x0004;
00062 const WORD  LaseEdlAcquisitionThread::FLASH_YES                       = 0x0001;
00063 const WORD  LaseEdlAcquisitionThread::FLASH_NO                        = 0x0000;
00064 const WORD  LaseEdlAcquisitionThread::PROFILENUM_CONTINUOUS           = 0x0000;
00065 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_NUMBER            = 0x0001;
00066 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_COUNTER           = 0x0002;
00067 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_LAYER             = 0x0004;
00068 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_SECTOR            = 0x0008;
00069 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_ANGLE_STEP        = 0x0010;
00070 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_NUM_SECT_POINTS   = 0x0020;
00071 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_TIMESTAMP_START   = 0x0040;
00072 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_START_DIRECTION   = 0x0080;
00073 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_DISTANCE          = 0x0100;
00074 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_DIRECTION         = 0x0200;
00075 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_ECHO_AMPLITUDE    = 0x0400;
00076 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_TIMESTAMP_END     = 0x0800;
00077 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_END_DIRECTION     = 0x1000;
00078 const WORD  LaseEdlAcquisitionThread::PROFILEFORMAT_SENSOR_MODE       = 0x2000;
00079
00080 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_STATUS             = 0x0100;
00081 const WORD  LaseEdlAcquisitionThread::CMD_GET_IDENTIFICATION          = 0x0101;
00082 const WORD  LaseEdlAcquisitionThread::CMD_GET_STATUS                  = 0x0102;
00083 const WORD  LaseEdlAcquisitionThread::CMD_GET_ERROR                   = 0x0103;
00084 const WORD  LaseEdlAcquisitionThread::CMD_GET_SIGNAL                  = 0x0104;
00085 const WORD  LaseEdlAcquisitionThread::CMD_SET_SIGNAL                  = 0x0105;
00086 const WORD  LaseEdlAcquisitionThread::CMD_REGISTER_APPLICATION        = 0x0106;
00087 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_CONFIG             = 0x0200;
00088 const WORD  LaseEdlAcquisitionThread::CMD_SET_CONFIG                  = 0x0201;
00089 const WORD  LaseEdlAcquisitionThread::CMD_GET_CONFIG                  = 0x0202;
00090 const WORD  LaseEdlAcquisitionThread::CMD_SET_SYNC_ABS                = 0x0203;
00091 const WORD  LaseEdlAcquisitionThread::CMD_SET_SYNC_REL                = 0x0204;
00092 const WORD  LaseEdlAcquisitionThread::CMD_SET_SYNC_CLOCK              = 0x0205;
00093 const WORD  LaseEdlAcquisitionThread::CMD_SET_ZONE                    = 0x0206;
00094 const WORD  LaseEdlAcquisitionThread::CMD_GET_ZONE                    = 0x0207;
00095 const WORD  LaseEdlAcquisitionThread::CMD_RELEASE_ZONE                = 0x0208;
00096 const WORD  LaseEdlAcquisitionThread::CMD_SET_FILTER                  = 0x0209;
00097 const WORD  LaseEdlAcquisitionThread::CMD_SET_FUNCTION                = 0x020A;
00098 const WORD  LaseEdlAcquisitionThread::CMD_GET_FUNCTION                = 0x020B;
00099 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_MEASUREMENT        = 0x0300;
00100 const WORD  LaseEdlAcquisitionThread::CMD_GET_PROFILE                 = 0x0301;
00101 const WORD  LaseEdlAcquisitionThread::CMD_CANCEL_PROFILE              = 0x0302;
00102 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_WORKING            = 0x0400;
00103 const WORD  LaseEdlAcquisitionThread::CMD_DO_RESET                    = 0x0401;
00104 const WORD  LaseEdlAcquisitionThread::CMD_TRANS_IDLE                  = 0x0402;
00105 const WORD  LaseEdlAcquisitionThread::CMD_TRANS_ROTATE                = 0x0403;
00106 const WORD  LaseEdlAcquisitionThread::CMD_TRANS_MEASURE               = 0x0404;
00107 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_MAINTENANCE        = 0x0500;
00108 const WORD  LaseEdlAcquisitionThread::CMD_DO_ADJUST                   = 0x0501;
00109 const WORD  LaseEdlAcquisitionThread::CMD_DO_TEST                     = 0x0502;
00110 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_INTERFACE_ROUTING  = 0x0600;
00111 const WORD  LaseEdlAcquisitionThread::CMD_COM_ATTACH                  = 0x0601;
00112 const WORD  LaseEdlAcquisitionThread::CMD_COM_DETACH                  = 0x0602;
00113 const WORD  LaseEdlAcquisitionThread::CMD_COM_INIT                    = 0x0603;
00114 const WORD  LaseEdlAcquisitionThread::CMD_COM_OUTPUT                  = 0x0604;
00115 const WORD  LaseEdlAcquisitionThread::CMD_COM_DATA                    = 0x0605;
00116 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_FILE               = 0x0700;
00117 const WORD  LaseEdlAcquisitionThread::CMD_DIR                         = 0x0701;
00118 const WORD  LaseEdlAcquisitionThread::CMD_SAVE                        = 0x0702;
00119 const WORD  LaseEdlAcquisitionThread::CMD_LOAD                        = 0x0703;
00120 const WORD  LaseEdlAcquisitionThread::CMD_DELETE                      = 0x0704;
00121 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_MONITOR            = 0x0900;
00122 const WORD  LaseEdlAcquisitionThread::CMD_MONITOR_ENABLE_LOG          = 0x0801;
00123 const WORD  LaseEdlAcquisitionThread::CMD_MONITOR_DISABLE_LOG         = 0x0802;
00124 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_ADJUST             = 0x7E00;
00125 const WORD  LaseEdlAcquisitionThread::SERVICEGROUP_SPECIAL            = 0x7F00;
00126 const WORD  LaseEdlAcquisitionThread::CMD_SERVICE_FAILURE             = 0x7F00;
00127 const WORD  LaseEdlAcquisitionThread::RESPONSE_BIT                    = 0x8000;
00128
00129
00130 const float LaseEdlAcquisitionThread::DISTANCE_FACTOR                 = 256.00;
00131
00132 
00133 /** @class LaseEdlAcquisitionThread "playerc_thread.h"
00134  * Laser acqusition thread for Lase EDL L A laser scanner.
00135  * This thread fetches the data from the laser.
00136  * @author Tim Niemueller
00137  * @author Christian Fritz
00138  */
00139
00140 
00141 /** Constructor. */
00142 LaseEdlAcquisitionThread::LaseEdlAcquisitionThread()
00143   : LaserAcquisitionThread("LaseEdlAcquisitionThread")
00144 {
00145   __pre_init_done = false;
00146 }
00147
00148
00149 void
00150 LaseEdlAcquisitionThread::pre_init(fawkes::Configuration *config,
00151                                    fawkes::Logger        *logger)
00152 {
00153   if (__pre_init_done)  return;
00154
00155   try {
00156     std::string canres  = config->get_string("/hardware/laser/canonical_resolution");
00157     if (canres == "low") {
00158       __cfg_rotation_freq = 20;
00159       __cfg_angle_step    = 16;
00160     } else if (canres == "high") {
00161       __cfg_rotation_freq = 15;
00162       __cfg_angle_step    =  8;
00163     } else {
00164       logger->log_error(name(), "Canonical resolution %s is invalid, must be 'low' "
00165                         "or 'high', trying to read raw config data");
00166       throw Exception("");
00167     }
00168     logger->log_debug(name(), "Using canonical resolution %s, freq: %u, angle step: %u",
00169                       canres.c_str(), __cfg_rotation_freq, __cfg_angle_step);
00170   } catch (Exception &e) {
00171     // exceptions thrown here will propagate
00172     __cfg_rotation_freq  = config->get_uint("/hardware/laser/rotation_freq");
00173     __cfg_angle_step     = config->get_uint("/hardware/laser/angle_step");
00174   }
00175
00176   try {
00177     __cfg_use_default    = config->get_bool("/hardware/laser/use_default");
00178     __cfg_set_default    = config->get_bool("/hardware/laser/set_default");
00179     __cfg_max_pulse_freq = config->get_uint("/hardware/laser/max_pulse_freq");
00180     __cfg_profile_format = config->get_uint("/hardware/laser/profile_format");
00181     __cfg_can_id         = config->get_uint("/hardware/laser/can_id");
00182     __cfg_can_id_resp    = config->get_uint("/hardware/laser/can_id_resp");
00183     __cfg_sensor_id      = config->get_uint("/hardware/laser/sensor_id");
00184     __cfg_sensor_id_resp = config->get_uint("/hardware/laser/sensor_id_resp");
00185     __cfg_btr0btr1       = config->get_uint("/hardware/laser/btr0btr1");
00186     __cfg_port           = config->get_uint("/hardware/laser/port");
00187     __cfg_irq            = config->get_uint("/hardware/laser/irq");
00188     __cfg_num_init_tries = config->get_uint("/hardware/laser/num_init_tries");
00189     __cfg_mount_rotation = config->get_float("/hardware/laser/mount_rotation");
00190
00191     __min_angle_step     = calc_angle_step(__cfg_rotation_freq, __cfg_max_pulse_freq);
00192     if ( __cfg_angle_step < __min_angle_step ) {
00193       logger->log_warn(name(), "Configured angle step %u less than required minimum "
00194                        "of %u, raising to minimum", __cfg_angle_step, __min_angle_step);
00195       __cfg_angle_step = __min_angle_step;
00196     }
00197     __number_of_values = 16 * 360 / __cfg_angle_step;
00198
00199     if ( (__number_of_values != 360) && (__number_of_values != 720) ) {
00200       throw Exception("At the moment only configurations with 360 or 720 "
00201                       "laser beams are supported, but %u requested", __number_of_values);
00202     }
00203
00204     _distances_size = _echoes_size = __number_of_values;
00205
00206     std::string interface_type = config->get_string("/hardware/laser/interface_type");
00207     if ( interface_type == "usb" ) {
00208       __cfg_interface_type = HW_USB;
00209     } else {
00210       throw Exception("Unknown interface type %s", interface_type.c_str());
00211     }
00212
00213   } catch (Exception &e) {
00214     e.append("Could not read all required config values for %s", name());
00215     throw;
00216   }
00217
00218   __pre_init_done = true;
00219 }
00220
00221 void
00222 LaseEdlAcquisitionThread::init()
00223 {
00224   pre_init(config, logger);
00225
00226   init_bus();
00227
00228   for (unsigned int i = 1; i <= __cfg_num_init_tries; ++i) {
00229
00230     try {
00231       CANCEL_PROFILE();
00232     } catch (Exception &e) {
00233       // ignored, happens often
00234     }
00235
00236     try {
00237       logger->log_debug("LaseEdlAcquisitionThread", "Resetting Laser");
00238       DO_RESET(RESETLEVEL_HALT_IDLE);
00239
00240       if ( ! __cfg_use_default ) {
00241         logger->log_debug("LaseEdlAcquisitionThread", "Setting configuration");
00242         // set configuration (rotation and anglestep)
00243         SET_CONFIG(CONFIGITEM_GLOBAL, CONFIGDATA_LENGTH_GLOBAL,
00244                    __cfg_sensor_id, __cfg_rotation_freq, __cfg_angle_step);
00245
00246         // set functions (sector definition)
00247         SET_FUNCTION(SECTOR_0, SECTORFUNC_NORMAL_MEASUREMENT,
00248                      (16 * 360) - __cfg_angle_step,
00249                      __cfg_set_default ? FLASH_YES : FLASH_NO);
00250         SET_FUNCTION(SECTOR_1, SECTORFUNC_NOT_INITIALIZED, 0,
00251                      __cfg_set_default ? FLASH_YES : FLASH_NO);
00252       }
00253
00254       logger->log_debug("LaseEdlAcquisitionThread", "Starting rotating");
00255       TRANS_ROTATE(__cfg_rotation_freq);
00256       logger->log_debug("LaseEdlAcquisitionThread", "Starting measuring");
00257       TRANS_MEASURE();
00258       logger->log_debug("LaseEdlAcquisitionThread", "Enable profile retrieval");
00259       GET_PROFILE(PROFILENUM_CONTINUOUS, __cfg_profile_format);
00260
00261       break; // break for loop if initialization was successful
00262     } catch (Exception &e) {
00263       if (i < __cfg_num_init_tries) {
00264         logger->log_warn("LaseEdlAcquisitionThread", "Initialization, retrying %d more times", __cfg_num_init_tries - i);
00265         logger->log_warn("LaseEdlAcquisitionThread", e);
00266       } else {
00267         logger->log_error("LaseEdlAcquisitionThread", "Initialization failed, giving up after %u tries", __cfg_num_init_tries);
00268         throw;
00269       }
00270     }
00271   }
00272
00273   _distances  = (float *)malloc(sizeof(float) * __number_of_values);
00274   _echoes     = (float *)malloc(sizeof(float) * __number_of_values);
00275 }
00276
00277
00278 void
00279 LaseEdlAcquisitionThread::finalize()
00280 {
00281   free(_distances);
00282   free(_echoes);
00283   _distances = _echoes = NULL;
00284
00285   logger->log_debug("LaseEdlAcquisitionThread", "Resetting laser");
00286   DO_RESET(RESETLEVEL_HALT_IDLE);
00287 }
00288
00289
00290 void
00291 LaseEdlAcquisitionThread::loop()
00292 {
00293   process_profiles();
00294 }
00295
00296
00297 unsigned int
00298 LaseEdlAcquisitionThread::calc_angle_step(unsigned int rotation_freq,
00299                                           unsigned int max_pulse_freq)
00300 {
00301   float tmp;
00302   unsigned int rv;
00303   tmp = ( ((float)max_pulse_freq) / 360.0 ) / ((float)rotation_freq);
00304   tmp = ceil( (1 / tmp) * 16.0 );
00305   rv  = (unsigned int)tmp;
00306
00307   if (rv == 7 || rv == 11 || rv == 13 || rv == 14)  rv++;
00308
00309   return rv;
00310 }
00311
00312
00313 void
00314 LaseEdlAcquisitionThread::init_bus()
00315 {
00316   __handle = CAN_Open(__cfg_interface_type, 0, __cfg_port, __cfg_irq);
00317   if (__handle == NULL) {
00318     throw Exception("Cannot open CAN bus");
00319   }
00320   if (CAN_Init(__handle, __cfg_btr0btr1, CAN_INIT_TYPE_ST) != CAN_ERR_OK) {
00321     throw Exception("Cannot initialize CAN bus");
00322   }
00323 }
00324
00325
00326 void
00327 LaseEdlAcquisitionThread::send(WORD *data, int n)
00328 {
00329   TPCANMsg msg;
00330   msg.ID      = __cfg_can_id;
00331   msg.MSGTYPE = MSGTYPE_STANDARD;
00332   msg.LEN     = 0;
00333
00334   int send_words = 0;
00335   WORD number_of_frames = 0;
00336
00337   // special case for less or equal two words 
00338   if (n <= 2) {
00339     number_of_frames = 1;
00340     append_to_msg( (WORD)0, &msg);
00341     append_to_msg( (WORD)__cfg_sensor_id, &msg);
00342     if (n >= 1) {
00343       append_to_msg( data[0], &msg);
00344     }
00345     if (n == 2) {
00346       append_to_msg( data[1], &msg);
00347     }
00348     //printf("send (1): "); print_message(&msg);
00349     if (CAN_Write( __handle, &msg ) != CAN_ERR_OK) {
00350       throw Exception("Laser send() failed (1)");
00351     }
00352
00353   } else { // more than 2 words
00354     number_of_frames = ((n - 1) / 3) + 1;
00355     if ((n-1) % 3 != 0) {
00356       ++number_of_frames;
00357     }
00358     append_to_msg( (WORD)0xFFFF, &msg);
00359     append_to_msg( number_of_frames, &msg);
00360     append_to_msg( (WORD)__cfg_sensor_id, &msg);
00361     append_to_msg( data[send_words++], &msg);
00362     // printf("send (2): "); print_message(&msg);
00363     if (CAN_Write( __handle, &msg ) != CAN_ERR_OK) {
00364       throw Exception("Laser send() failed (2)");
00365     }
00366
00367     for (WORD f=number_of_frames-1; f > 1; --f ) {
00368       msg.LEN = 0;
00369       append_to_msg( f, &msg);
00370       append_to_msg( data[send_words++], &msg);
00371       append_to_msg( data[send_words++], &msg);
00372       append_to_msg( data[send_words++], &msg);
00373       // printf("send (3): "); print_message(&msg);
00374       if (CAN_Write( __handle, &msg ) != CAN_ERR_OK) {
00375         throw Exception("Laser send() failed (3)");
00376       }
00377     }
00378     // last frame
00379     msg.LEN = 0;
00380     append_to_msg( (WORD)0x0001, &msg);
00381     for (int i=send_words; i < n; i++) {
00382       append_to_msg( data[send_words++], &msg);
00383     }
00384     // printf("send (4): "); print_message(&msg);
00385     if (CAN_Write( __handle, &msg ) != CAN_ERR_OK) {
00386       throw Exception("Laser send() failed (3)");
00387     }
00388   }
00389 }
00390
00391
00392 int
00393 LaseEdlAcquisitionThread::recv(WORD **data, bool allocate)
00394 {
00395   TPCANMsg msg;
00396   // read from CAN BUS
00397   if (CAN_Read( __handle, &msg) != CAN_ERR_OK) {
00398     throw Exception("Laser recv() failed (1)");
00399   }
00400   // If msg wasn't send by our laser: ignore it
00401   if (msg.ID != __cfg_can_id_resp) {
00402     logger->log_warn("LaseEdlAcquisitionThread", "CAN ID is not the expected ID, "
00403                      "ignoring message");
00404     return -1;
00405   }
00406
00407   int  number_of_incoming_frames = 0;
00408   WORD number_of_incoming_words = 0;
00409   int  msg_index = 0;
00410   int  data_index = 0;
00411   WORD read;
00412
00413   read = get_word_from_msg(&msg, &msg_index);
00414
00415   // seek for beginning of a block
00416   while ((read != 0x0000) && (read != 0xFFFF) ) {
00417     if (CAN_Read( __handle, &msg) != CAN_ERR_OK) {
00418       throw Exception("Laser recv() failed (2)");
00419     }
00420     msg_index = 0;
00421     read = get_word_from_msg( &msg, &msg_index);
00422   }
00423
00424   // got legal block: process it
00425   if (read == 0x0000) { // receiving only one frame
00426     read = get_word_from_msg( &msg, &msg_index);
00427     if (read != __cfg_sensor_id_resp) {
00428       logger->log_warn("LaseEdlAcquisitionThread", "Sensor ID is not the expected ID, "
00429                        "ignoring message");
00430       return -1;
00431     }
00432     number_of_incoming_words = (msg.LEN - msg_index) / 2;
00433     if (allocate) {
00434       (*data) = (WORD*)malloc( sizeof(WORD)* (number_of_incoming_words));
00435     }
00436     for (int i=0; i < number_of_incoming_words; ++i) {
00437       (*data)[i] = get_word_from_msg( &msg, &msg_index);
00438     }
00439     // printf("Received (1): "); print_word_array(number_of_incoming_words, *data);
00440     return number_of_incoming_words;
00441   } else if (read == 0xFFFF) {
00442     // get number of incoming frames
00443     number_of_incoming_frames = get_word_from_msg( &msg, &msg_index);
00444     if (allocate) {
00445       (*data) = (WORD*)malloc( sizeof(WORD)* (number_of_incoming_frames * 6 + 1));
00446     }
00447     data_index = 0;
00448
00449     // get sensor response ID
00450     read = get_word_from_msg( &msg, &msg_index);
00451     if (read != __cfg_sensor_id_resp) {
00452       logger->log_warn("LaseEdlAcquisitionThread", "Sensor ID is not the expected ID, "
00453                        "ignoring message");
00454       return -1;
00455     }
00456
00457     // two words remaining in first message
00458     (*data)[data_index++] = get_word_from_msg( &msg, &msg_index);
00459
00460     // process all frames
00461     for (WORD f=number_of_incoming_frames-1; f > 0; --f ) {
00462       msg_index = 0;
00463
00464       if (CAN_Read( __handle, &msg) != CAN_ERR_OK) {
00465         throw Exception("Laser recv() failed (3)");
00466       }
00467
00468       // get and verify frame number indicator
00469       read = get_word_from_msg( &msg, &msg_index);
00470       if (read != f) {
00471         logger->log_warn("LaseEdlAcquisitionThread","Recv protocol violation, "
00472                          "wrong frame number: expected %u, but got %u", f, read);
00473         return -1;
00474       }
00475
00476       // process all words in frame
00477       number_of_incoming_words = (msg.LEN - msg_index) >> 1;
00478       for (int i=0; i < number_of_incoming_words; ++i) {
00479         (*data)[data_index++] = get_word_from_msg( &msg, &msg_index);
00480       }
00481     }
00482
00483     // printf("Received (2): "); print_word_array(data_index, *data);
00484
00485     // might be different from number_of_incoming_words,
00486     // since last message can be not full
00487     return data_index;
00488
00489   } else {
00490     logger->log_warn("LaseEdlAcquisitionThread", "Recv got strange first response word (neigther 0 nor FFFF)\n");
00491   }
00492   return -1;
00493 }
00494
00495
00496 inline void
00497 LaseEdlAcquisitionThread::append_to_msg(WORD word, TPCANMsg *msg)
00498 {
00499   BYTE byte;
00500   byte = word >> 8;
00501   msg->DATA[(msg->LEN)++] = byte;
00502   byte = word;
00503   msg->DATA[(msg->LEN)++] = byte;
00504 }
00505
00506
00507 inline void
00508 LaseEdlAcquisitionThread::append_to_msg(BYTE byte, TPCANMsg *msg)
00509 {
00510   msg->DATA[(msg->LEN)++] = byte;
00511 }
00512
00513 inline WORD
00514 LaseEdlAcquisitionThread::get_word_from_msg(TPCANMsg *msg, int *index)
00515 {
00516   WORD rv  = msg->DATA[(*index)++] << 8;
00517   rv += msg->DATA[((*index)++)];
00518   return rv;
00519 }
00520
00521
00522 WORD *
00523 LaseEdlAcquisitionThread::make_word_array(int count, ...) {
00524   va_list word_list;
00525   va_start(word_list, count);
00526   WORD *rtv;
00527   rtv = (WORD*)malloc( sizeof(WORD) * count);
00528   for (int i=0; i<count; ++i) {
00529     rtv[i] = (WORD) va_arg(word_list, int);
00530   }
00531   va_end(word_list);
00532   return rtv;
00533 }
00534
00535
00536 int
00537 LaseEdlAcquisitionThread::compare_word_arrays(int count, WORD* a, WORD* b)
00538 {
00539   for (int i=0; i < count; ++i) {
00540     if (a[i] != b[i]) {
00541       return 0;
00542     }
00543   }
00544   return 1;
00545 }
00546
00547
00548 void
00549 LaseEdlAcquisitionThread::print_word_array(int count, WORD* a)
00550 {
00551   for (int i=0; i < count; ++i) {
00552     printf("%04x ", a[i]);
00553   }
00554   printf("\n");
00555 }
00556
00557
00558 void
00559 LaseEdlAcquisitionThread::print_message(TPCANMsg *m)
00560 {
00561   int i;
00562   printf("%c %c 0x%08x %1d  ",
00563          (m->MSGTYPE & MSGTYPE_RTR)      ? 'r' : 'm',
00564          (m->MSGTYPE & MSGTYPE_EXTENDED) ? 'e' : 's',
00565          m->ID,
00566          m->LEN);
00567
00568   for (i = 0; i < m->LEN; i++) {
00569     printf("0x%02x ", m->DATA[i]);
00570   }
00571
00572   printf("\n");
00573 }
00574
00575 void
00576 LaseEdlAcquisitionThread::process_profiles()
00577 {
00578   WORD* real_response;
00579   WORD* expected_response = make_word_array( 2, respcode(CMD_GET_PROFILE),
00580                                              __cfg_profile_format);
00581   int response_size = recv(&real_response);
00582   if (response_size == -1) {
00583     logger->log_warn("LaseEdlAcquisitionThread", "process_profiles(): recv() failed");
00584     return;
00585   }
00586
00587   // wrong answer ?
00588   if (! compare_word_arrays( 2, real_response, expected_response )) {
00589     logger->log_warn("LaseEdlAcquisitionThread", "process_profiles(): Invalid response received");
00590     return;
00591   }
00592   // wrong number of values ?
00593   if ( (response_size - 3 != (int)__number_of_values) &&
00594        (response_size - 3 != 2 * (int)__number_of_values) ) {
00595     logger->log_warn("LaseEdlAcquisitionThread", "number of received values "
00596                      "doesn't match my expectations, recvd %d, expected %d",
00597                      response_size - 3, __number_of_values);
00598     return;
00599   }
00600
00601   // extract data from response
00602   register float dist = 0;
00603   register int echo = 0;
00604   register int dist_index = (int)roundf(__cfg_mount_rotation * 16 / __cfg_angle_step);
00605   register int echo_index = dist_index;
00606
00607   _data_mutex->lock();
00608   _new_data = true;
00609
00610   // see which data is requested
00611   if (__cfg_profile_format == PROFILEFORMAT_DISTANCE ) {
00612     // only distances
00613     for (int i=3; i < response_size; i++ ) {
00614       dist = ((float)real_response[i]) / DISTANCE_FACTOR;
00615       _distances[dist_index++] = dist;
00616       if (dist_index >= (int)__number_of_values) dist_index = 0;
00617     }
00618
00619   } else if (__cfg_profile_format == (PROFILEFORMAT_DISTANCE | PROFILEFORMAT_ECHO_AMPLITUDE) ) {
00620     // distances + echos
00621     for (int i=3; i < response_size; ) {
00622       dist = ((float)real_response[i]) / DISTANCE_FACTOR;
00623       _distances[dist_index++] = dist;
00624       if (dist_index >= (int)__number_of_values) dist_index = 0;
00625       i++;
00626       echo = real_response[i];
00627       _echoes[echo_index++] = echo;
00628       if (echo_index >= (int)__number_of_values) echo_index = 0;
00629       i++;
00630     }
00631
00632
00633   } else if (__cfg_profile_format == PROFILEFORMAT_ECHO_AMPLITUDE ) {
00634     // only echos
00635     for (int i=3; i < response_size; i++ ) {
00636       echo = real_response[i];
00637       _echoes[echo_index++] = echo;
00638       if (echo_index >= (int)__number_of_values) echo_index = 0;
00639     }
00640   }
00641
00642   _data_mutex->unlock();
00643
00644   free( real_response );
00645   free( expected_response );
00646 }
00647
00648
00649 void
00650 LaseEdlAcquisitionThread::send_and_check(WORD *command_data, int command_length,
00651                                        WORD *expected_response, int n,
00652                                        WORD **real_response, int *response_size)
00653 {
00654   bool keep_response = (real_response != NULL);
00655   WORD **response;
00656   WORD *local_response;
00657   if (keep_response) {
00658     response = real_response;
00659   } else {
00660     response = &local_response;
00661   }
00662   send(command_data, command_length);
00663   int  response_s = recv(response);
00664
00665   if (response_s <= 0) {
00666     throw Exception("Did not receive data for command");
00667   }
00668
00669   bool match = compare_word_arrays(n, *response, expected_response);
00670
00671   if ( ! match || ! keep_response ) {
00672     free(*response);
00673   }
00674   free(expected_response);
00675   free(command_data);
00676
00677   if ( ! match) {
00678     throw Exception("Response to query did not match expectation");
00679   }
00680
00681   if ( response_size != NULL ) {
00682     *response_size = response_s;
00683   }
00684 }
00685
00686 void
00687 LaseEdlAcquisitionThread::SET_CONFIG( WORD config_item, int k, ...)
00688 {
00689   WORD *command;
00690   command = (WORD*)malloc( sizeof(WORD) * (2+k) );
00691   command[0] = CMD_SET_CONFIG;
00692   command[1] = config_item;
00693   va_list word_list;
00694   va_start( word_list, k);
00695   for (int i=0; i<k; ++i) {
00696     command[i+2] = (WORD) va_arg( word_list, int);
00697   }
00698   va_end( word_list );
00699
00700   send_and_check(command, 2+k, make_word_array(2, respcode(CMD_SET_CONFIG), 0x0000), 2);
00701 }
00702
00703
00704 void
00705 LaseEdlAcquisitionThread::SET_FUNCTION(WORD sect_num, WORD sect_func,
00706                                        WORD sect_stop, WORD flash )
00707 {
00708   WORD* command = make_word_array(5, CMD_SET_FUNCTION, sect_num, sect_func,
00709                                   sect_stop, flash);
00710   send_and_check(command, 5, make_word_array(2, respcode(CMD_SET_FUNCTION), sect_num), 2);
00711 }
00712
00713
00714 void
00715 LaseEdlAcquisitionThread::GET_PROFILE( WORD prof_num, WORD prof_format)
00716 {
00717   WORD* command = make_word_array(3, CMD_GET_PROFILE, prof_num, prof_format);
00718   send_and_check(command, 3,
00719                  make_word_array(2, respcode(CMD_GET_PROFILE), prof_format), 2);
00720 }
00721
00722
00723 void
00724 LaseEdlAcquisitionThread::CANCEL_PROFILE()
00725 {
00726   send_and_check(make_word_array(1, CMD_CANCEL_PROFILE), 1,
00727                  make_word_array( 1, respcode(CMD_CANCEL_PROFILE)), 1);
00728 }
00729
00730
00731 void
00732 LaseEdlAcquisitionThread::DO_RESET(WORD reset_level)
00733 {
00734   WORD* command = make_word_array( 2, CMD_DO_RESET, reset_level);
00735   send_and_check(command, 2, make_word_array(2, respcode(CMD_DO_RESET), reset_level), 2);
00736 }
00737
00738
00739 void
00740 LaseEdlAcquisitionThread::TRANS_IDLE()
00741 {
00742   WORD* command = make_word_array( 1, CMD_TRANS_IDLE);
00743   WORD* real_response;
00744   int   response_size;
00745
00746   send_and_check(command, 1, make_word_array( 1, respcode(CMD_TRANS_IDLE)), 1, &real_response, &response_size);
00747
00748   bool failed = (real_response[response_size-1] != 0x0001);
00749   free(real_response);
00750   if (failed) throw Exception("Failed to set trans idle");
00751 }
00752
00753
00754 void
00755 LaseEdlAcquisitionThread::TRANS_ROTATE(WORD frequency)
00756 {
00757   WORD* command = make_word_array( 2, CMD_TRANS_ROTATE, frequency);
00758   WORD* real_response;
00759   int   response_size;
00760   send_and_check(command, 2, make_word_array( 1, respcode(CMD_TRANS_ROTATE)), 1,
00761                  &real_response, &response_size);
00762
00763   bool failed = (real_response[response_size-1] != 0x0002);
00764   free(real_response);
00765   if ( failed )  throw Exception("Failed to set trans rotate");
00766 }
00767
00768
00769 void
00770 LaseEdlAcquisitionThread::TRANS_MEASURE()
00771 {
00772   WORD* command = make_word_array( 1, CMD_TRANS_MEASURE);
00773   WORD* real_response;
00774   int   response_size;
00775   send_and_check(command, 1, make_word_array( 1, respcode(CMD_TRANS_MEASURE)),
00776                  1, &real_response, &response_size);
00777
00778   bool failed = (real_response[response_size-2] != 0x0003) ||
00779                 (real_response[response_size-1] != 0x0000);
00780   unsigned int error_code = real_response[response_size-1];
00781   free(real_response);
00782   if ( failed )  throw Exception("Failed set trans measure, error code %u", error_code);
00783 }