All Classes Namespaces Files Functions Variables Enumerations Enumerator
libs/range_sensor/c/urg_ctrl.c
Go to the documentation of this file.
00001 
00010 #include "math_utils.h"
00011 #include "urg_ctrl.h"
00012 #include "scip_handler.h"
00013 #include "urg_errno.h"
00014 #include "serial_ctrl.h"
00015 #include "serial_utils.h"
00016 #include "serial_errno.h"
00017 #include "urg_ticks.h"
00018 #include "urg_delay.h"
00019 #include <string.h>
00020 #include <stdlib.h>
00021 #include <stdio.h>
00022 
00023 #if defined(WINDOWS_OS)
00024 #define snprintf _snprintf
00025 #endif
00026 
00027 
00028 enum {
00029   ScipTimeout = 1000,      
00030   EachTimeout = 100 * 2,   
00032   InvalidRange = -1,
00033 };
00034 
00035 
00036 void urg_initialize(urg_t *urg)
00037 {
00038   serial_initialize(&urg->serial_);
00039   urg->errno_ = UrgNoError;
00040   urg->last_timestamp_ = 0;
00041 }
00042 
00043 
00044 static int urg_firstConnection(urg_t *urg, long baudrate)
00045 {
00046   long try_baudrates[] = { 115200, 19200, 38400 };
00047   int try_size = sizeof(try_baudrates) / sizeof(try_baudrates[0]);
00048   long pre_ticks;
00049   int reply = 0;
00050   int ret;
00051   int i;
00052 
00053   /* The baud rate to be connected is replaced with the first element
00054      of the array. */
00055   for (i = 1; i < try_size; ++i) {
00056     if (baudrate == try_baudrates[i]) {
00057       long swap_tmp = try_baudrates[i];
00058       try_baudrates[i] = try_baudrates[0];
00059       try_baudrates[0] = swap_tmp;
00060       break;
00061     }
00062   }
00063 
00064   /* Try to connect with the specified baudrate , and check for response */
00065   for (i = 0; i < try_size; ++i) {
00066 
00067     /* Change host side baudrate  */
00068     ret = serial_setBaudrate(&urg->serial_, try_baudrates[i]);
00069     if (ret < 0) {
00070       return ret;
00071     }
00072 
00073     serial_clear(&urg->serial_);
00074 
00075     /* Send QT command */
00076     ret = scip_qt(&urg->serial_, &reply, ScipWaitReply);
00077     if (ret == UrgSerialRecvFail) {
00078       /* If there is no response, consider that there is mismatch in baudrate */
00079       continue;
00080     }
00081 
00082     if ((ret == UrgMismatchResponse) && (reply != -0xE)) {
00083       /* Process when response from MD/MS command is received  */
00084       /* Read out all data and then proceed for the next one */
00085       /* (reply == -0xE) means SCIP1.1 error 'E' */
00086       serial_clear(&urg->serial_);
00087       serial_skip(&urg->serial_, ScipTimeout, EachTimeout);
00088       reply = 0x00;
00089     }
00090 
00091     /* If the response is returned, consider that sensor is already in SCIP2.0
00092        mode and no need to send SCIP2.0 */
00093     if (reply != 0x00) {
00094       if ((ret = scip_scip20(&urg->serial_)) < 0) {
00095         /* If there is no response , continue with other baudrate */
00096         continue;
00097       }
00098       if (ret == 12) {
00099         /* SCIP1.1 protocol */
00100         return UrgScip10;
00101       }
00102     }
00103 
00104     /* Returns if there is no need to change baudrate */
00105     if (baudrate == try_baudrates[i]) {
00106       return 0;
00107     }
00108 
00109     /* Change the baud rate as specified by URG */
00110     pre_ticks = urg_ticks();
00111     if (scip_ss(&urg->serial_, baudrate) < 0) {
00112       return UrgSsFail;
00113 
00114     } else {
00115       /* In case of serial communication, it is necessary to wait for
00116          one scan after baud rate is changed. */
00117       long reply_msec = urg_ticks() - pre_ticks;
00118       urg_delay((reply_msec * 4 / 3) + 10);
00119 
00120       return serial_setBaudrate(&urg->serial_, baudrate);
00121     }
00122   }
00123 
00124   return UrgAdjustBaudrateFail;
00125 }
00126 
00127 
00128 static void urg_t_initialize(urg_t *urg)
00129 {
00130   urg->parameters_.area_max_ = 0;
00131   urg->parameters_.scan_rpm_ = 0;
00132   urg->parameters_.sensor_type[0] = '\0';
00133   urg->remain_byte_ = 0;
00134 }
00135 
00136 
00137 /* Open serial device and initialize URG */
00138 int urg_connect(urg_t *urg, const char *device, long baudrate)
00139 {
00140   int ret;
00141   urg_t_initialize(urg);
00142 
00143   /* Open serial communication */
00144   ret = serial_connect(&urg->serial_, device, baudrate);
00145   if (ret != 0) {
00146     urg->errno_ = UrgSerialConnectionFail;
00147     return ret;
00148   }
00149   // change timestamp resolution in Windows OS
00150   urg_delay(0);
00151 
00152   /* URG connection */
00153   ret = urg_firstConnection(urg, baudrate);
00154   if (ret < 0) {
00155     urg->errno_ = ret;
00156     serial_disconnect(&urg->serial_);
00157     return ret;
00158   }
00159 
00160   /* Update parameter information, nothing but an initialization */
00161   ret = scip_pp(&urg->serial_, &urg->parameters_);
00162   if (ret < 0) {
00163     urg->errno_ = ret;
00164     serial_disconnect(&urg->serial_);
00165     return ret;
00166   }
00167   urg->skip_lines_ = 1;
00168   urg->skip_frames_ = 0;
00169   urg->capture_times_ = 0;
00170   urg->is_laser_on_ = UrgLaserUnknown;
00171   urg->remain_times_ = 0;
00172 
00173   urg->errno_ = UrgNoError;
00174   return 0;
00175 }
00176 
00177 
00178 void urg_disconnect(urg_t *urg)
00179 {
00180   /* To stop MD/MS command */
00181   urg_laserOff(urg);
00182   serial_skip(&urg->serial_, ScipTimeout, EachTimeout);
00183 
00184   /* Disconnect serial connection */
00185   serial_disconnect(&urg->serial_);
00186 }
00187 
00188 
00189 int urg_isConnected(const urg_t *urg)
00190 {
00191   /* Return 0, if serial connectionis valid */
00192   return serial_isConnected(&urg->serial_);
00193 }
00194 
00195 
00196 const char *urg_error(const urg_t *urg)
00197 {
00198   return urg_strerror(urg->errno_);
00199 }
00200 
00201 
00202 int urg_versionLines(urg_t *urg, char* lines[], int lines_max)
00203 {
00204   if (! urg_isConnected(urg)) {
00205     return -1;
00206   }
00207   return scip_vv(&urg->serial_, lines, lines_max);
00208 }
00209 
00210 
00211 /* Send PP command. Analyse and store the response */
00212 int urg_parameters(urg_t *urg, urg_parameter_t* parameters)
00213 {
00214   if (urg_isConnected(urg)) {
00215     *parameters = urg->parameters_;
00216   } else {
00217     scip_pp(&urg->serial_, &urg->parameters_);
00218     if (parameters) {
00219       *parameters = urg->parameters_;
00220     }
00221   }
00222 
00223   urg->errno_ = UrgNoError;
00224   return 0;
00225 }
00226 
00227 
00228 const char* urg_model(const urg_t *urg)
00229 {
00230   return urg->parameters_.sensor_type;
00231 }
00232 
00233 
00234 int urg_dataMax(const urg_t *urg)
00235 {
00236   return urg->parameters_.area_max_ + 1;
00237 }
00238 
00239 
00240 int urg_scanMsec(const urg_t *urg)
00241 {
00242   int scan_rpm = urg->parameters_.scan_rpm_;
00243   return (scan_rpm <= 0) ? 1 : (1000 * 60 / scan_rpm);
00244 }
00245 
00246 
00247 long urg_maxDistance(const urg_t *urg)
00248 {
00249   return urg->parameters_.distance_max_;
00250 }
00251 
00252 
00253 long urg_minDistance(const urg_t *urg)
00254 {
00255   return urg->parameters_.distance_min_;
00256 }
00257 
00258 
00259 int urg_setSkipLines(urg_t *urg, int lines)
00260 {
00261   /* Register number of lines to be skipped */
00262   if (lines == 0) {
00263     lines = 1;
00264   }
00265   if ((lines < 0) || (lines > 99)) {
00266     return -1;
00267   }
00268 
00269   urg->skip_lines_ = lines;
00270   return 0;
00271 }
00272 
00273 
00274 int urg_setSkipFrames(urg_t *urg, int frames)
00275 {
00276   /* Register number of frames to be skipped */
00277   if ((frames < 0) || (frames > 9)) {
00278     return -1;
00279   }
00280 
00281   urg->skip_frames_ = frames;
00282   return 0;
00283 }
00284 
00285 
00286 int urg_setCaptureTimes(urg_t *urg, int times)
00287 {
00288   /* Register frequency at which MD/MS data is received */
00289   if ((times < 0) || (times >= 100)) {
00290     urg->capture_times_ = 0;
00291   } else {
00292     urg->capture_times_ = times;
00293   }
00294 
00295   return 0;
00296 }
00297 
00298 
00299 int urg_remainCaptureTimes(const urg_t *urg)
00300 {
00301   if (urg->capture_times_ == 0) {
00302     /* Get data infinitely */
00303     return 100;
00304 
00305   } else {
00306     return urg->remain_times_;
00307   }
00308 }
00309 
00310 
00311 int urg_requestData(urg_t *urg,
00312                     urg_request_type request_type,
00313                     int first_index,
00314                     int last_index)
00315 {
00316   char buffer[] = "MDsssseeeellstt\n";
00317 
00318   if (first_index == URG_FIRST) {
00319     first_index = urg->parameters_.area_min_;
00320   }
00321   if (last_index == URG_LAST) {
00322     last_index = urg->parameters_.area_max_;
00323   }
00324 
00325   if ((request_type == URG_GD) || (request_type == URG_GS) ||
00326       (request_type == URG_GD_INTENSITY)) {
00327 
00328     /* In case of GD/GS */
00329     snprintf(buffer, 14, "G%c%04d%04d%02d\n",
00330              (((request_type == URG_GD) ||
00331                (request_type == URG_GD_INTENSITY)) ? 'D' : 'S'),
00332              first_index, last_index,
00333              urg->skip_lines_);
00334 
00335     /* Switch on the laser if laser is in off state */
00336     if (urg->is_laser_on_ != UrgLaserOn) {
00337       int ret = urg_laserOn(urg);
00338       if (ret < 0) {
00339         return ret;
00340       }
00341     }
00342 
00343   } else if ((request_type == URG_MD) || (request_type == URG_MS) ||
00344              (request_type == URG_MD_INTENSITY)) {
00345     char type = (request_type == URG_MS) ? 'S' : 'D';
00346 
00347     /* In case of MD/MS */
00348     snprintf(buffer, 17, "M%c%04d%04d%02d%d%02d\n",
00349              type,
00350              first_index, last_index,
00351              urg->skip_lines_,
00352              urg->skip_frames_,
00353              urg->capture_times_);
00354     urg->remain_times_ = urg->capture_times_;
00355 
00356   } else {
00357     urg->errno_ = UrgInvalidArgs;;
00358     return urg->errno_;
00359   }
00360 
00361   if ((request_type == URG_GD_INTENSITY) ||
00362       (request_type == URG_MD_INTENSITY)) {
00363     if (! strcmp("UTM-30LX", urg->parameters_.sensor_type)) {
00364       if (request_type == URG_GD_INTENSITY) {
00365         urg->errno_ = UtmNoGDIntensity;
00366         return urg->errno_;
00367       }
00368       /* use ME command in TOF series */
00369       buffer[0] = 'M';
00370       buffer[1] = 'E';
00371 
00372       /* cluster value */
00373       buffer[10] = '0';
00374       buffer[11] = '2';
00375 
00376     } else {
00377       /* AM series */
00378       buffer[10] = 'F';
00379       buffer[11] = 'F';
00380     }
00381   }
00382 
00383   return scip_send(&urg->serial_, buffer);
00384 }
00385 
00386 
00387 /* Decode 6bit data of URG */
00388 static long decode(const char* data, int data_byte)
00389 {
00390   const char* p = data;
00391   const char* last_p = p + data_byte;
00392 
00393   int value = 0;
00394   while (p < last_p) {
00395     value <<= 6;
00396     value &= ~0x3f;
00397     value |= *p++ - 0x30;
00398   }
00399   return value;
00400 }
00401 
00402 
00403 static int convertRawData(long data[], int data_max,
00404                           const char* buffer, int buffer_size, int filled,
00405                           int data_bytes, int skip_lines,
00406                           int store_last, urg_t* urg)
00407 {
00408   int n;
00409   int i;
00410   int j;
00411   int remain_byte = urg->remain_byte_;
00412   long length;
00413   long *data_p = data + filled;
00414 
00415   if (data_max > store_last) {
00416     data_max = store_last;
00417   }
00418 
00419   if (filled == 0) {
00420     /* Initialize the number of data, which are remained when the first time
00421        is called  */
00422     remain_byte = 0;
00423   }
00424 
00425   if (buffer_size <= 0) {
00426     return filled;
00427   }
00428 
00429   /* If there is any data left, then process that data */
00430   if (remain_byte > 0) {
00431     memcpy(&urg->remain_data_[remain_byte], buffer, data_bytes - remain_byte);
00432     n = skip_lines;
00433     if ((filled + n) > data_max) {
00434       n = data_max - filled;
00435     }
00436     length = decode(urg->remain_data_, data_bytes);
00437     for (j = 0; j < n; ++j) {
00438       *data_p++ = length;
00439     }
00440     filled += n;
00441   }
00442 
00443   /* Process one line of data */
00444   n = buffer_size - data_bytes;
00445   for (i = (data_bytes - remain_byte) % data_bytes; i <= n; i += data_bytes) {
00446     length = decode(&buffer[i], data_bytes);
00447     for (j = 0; j < skip_lines; ++j) {
00448       if (filled >= data_max) {
00449         return data_max;
00450       }
00451       *data_p++ = length;
00452       ++filled;
00453     }
00454   }
00455 
00456   /* Save the remaining data */
00457   urg->remain_byte_ = buffer_size - i;
00458   memcpy(urg->remain_data_, &buffer[i], urg->remain_byte_);
00459 
00460   return filled;
00461 }
00462 
00463 
00464 static int checkSum(const char buffer[], int size, char actual_sum)
00465 {
00466   const char *p = buffer;
00467   const char *last_p = p + size;
00468   char expected_sum = 0x00;
00469 
00470   while (p < last_p) {
00471     expected_sum += *p++;
00472   }
00473   expected_sum = (expected_sum & 0x3f) + 0x30;
00474 
00475   return (expected_sum == actual_sum) ? 0 : -1;
00476 }
00477 
00478 
00479 static int atoi_substr(const char *str, size_t len)
00480 {
00481   char buffer[13];
00482 
00483   strncpy(buffer, str, len);
00484   buffer[len] = '\0';
00485 
00486   return atoi(buffer);
00487 }
00488 
00489 
00490 static int internal_receiveData(urg_t *urg, long data[], int data_max,
00491                                 int store_first, int store_last,
00492                                 int skip_lines)
00493 {
00494   enum {
00495     EchoBack = 0,
00496     ReplyCode,
00497     Timestamp,
00498 
00499     False = 0,
00500     True = 1,
00501 
00502     MD_MS_Length = 15,          /* Length of MD, MS */
00503     GD_GS_Length = 12,          /* Length of GD, GS */
00504   };
00505 
00506   int lines = 0;
00507   char buffer[UrgLineWidth];
00508   int filled = 0;
00509   int is_echoback = False;
00510   int n;
00511 
00512   char current_type[] = "xx";
00513   int current_first = -1;
00514   //int current_last = -1;
00515   //int current_skip_lines = -1;
00516   //int current_skip_frames = -1;
00517   //int current_capture_times = -1;
00518   int current_data_bytes = 3;
00519   int dummy_last;
00520   int timeout = ScipTimeout;
00521 
00522   /* Initialization of time stamp */
00523   urg->last_timestamp_ = UrgInvalidTimestamp;
00524 
00525   urg->errno_ = UrgNoResponse;
00526 
00527   while (1) {
00528     n = serial_getLine(&urg->serial_, buffer, ScipLineWidth, timeout);
00529     //fprintf(stderr, "%d: %s\n", urg_ticks(), buffer);
00530     if (n <= 0) {
00531       if (is_echoback) {
00532         is_echoback = False;
00533         lines = 0;
00534         continue;
00535       }
00536       break;
00537     }
00538 
00539     if (lines > 0) {
00540       /* ignore echoback */
00541       if (checkSum(buffer, n - 1, buffer[n - 1]) < 0) {
00542         urg->errno_ = UrgInvalidResponse;
00543         lines = 0;
00544         filled = 0;
00545         is_echoback = False;
00546         continue;
00547       }
00548     }
00549 
00550     if (lines > Timestamp) {
00551       /* convert data */
00552       filled = convertRawData(data, data_max, buffer, n - 1, filled,
00553                               current_data_bytes, skip_lines,
00554                               store_last, urg);
00555 
00556     } else if (lines == EchoBack) {
00557 
00558       if ((n != GD_GS_Length) && (n != MD_MS_Length)) {
00559         /* Return if response is not GD/GS, MD/MS */
00560         urg->errno_ = UrgInvalidResponse;
00561         lines = 0;
00562         filled = 0;
00563         is_echoback = False;
00564         continue;
00565       }
00566       /* Response command */
00567       current_type[0] = buffer[0];
00568       current_type[1] = buffer[1];
00569 
00570       /* Initialisation of receiving settings */
00571       current_first = atoi_substr(&buffer[2], 4);
00572       //current_last = atoi_substr(&buffer[6], 4);
00573       //current_skip_lines = atoi_substr(&buffer[10], 2);
00574 
00575       if ((current_first - store_first) >= data_max) {
00576         /* no data */
00577         return 0;
00578       }
00579 
00580       /* Arrangement of dummy data */
00581       dummy_last = current_first - store_first;
00582       for (filled = 0; filled < dummy_last; ++filled) {
00583         data[filled] = InvalidRange;
00584       }
00585 
00586       if (n == GD_GS_Length) {
00587         /* Ignore receive frame settings and number of frames settings for
00588            GD/GS command */
00589         urg->remain_times_ = 0;
00590 
00591       } else {
00592         //current_skip_frames = atoi_substr(&buffer[12], 1);
00593         //current_capture_times = atoi_substr(&buffer[13], 2);
00594 
00595         /* In case of MD/MS, store the remaining number of scans. */
00596         urg->remain_times_ = atoi(&buffer[13]);
00597       }
00598       current_data_bytes = (current_type[1] == 'S') ? 2 : 3;
00599 
00600     } else if (lines == ReplyCode) {
00601       if (! strncmp(buffer, "10", 2)) {
00602         urg->is_laser_on_ = UrgLaserOff;
00603       }
00604 
00605       /* If response is "0B", ignore all response. Because there is a
00606          possibility that the correspondence of the response shifts. */
00607       if (! strncmp(buffer, "0B", 2)) {
00608         serial_skip(&urg->serial_, ScipTimeout, timeout);
00609       }
00610 
00611       /* In case of MD/MS, response = "00" means transition request and hence
00612          readout one more line, and then reset the process */
00613       if (current_type[0] == 'M' && (! strncmp(buffer, "00", 2))) {
00614         is_echoback = True;
00615       }
00616 
00617     } else if (lines == Timestamp) {
00618       urg->last_timestamp_ = decode(buffer, 4);
00619     }
00620 
00621     ++lines;
00622     timeout = EachTimeout;
00623   }
00624 
00625   if (filled <= 0) {
00626     return urg->errno_;
00627   } else {
00628 #if 0
00629     // fill to urg->parameters_.area_max_ or data_max
00630     int last_index = data_max;
00631     if (urg->parameters_.area_max_ < last_index) {
00632       last_index = urg->parameters_.area_max_;
00633     }
00634     for (; filled <= last_index; ++filled) {
00635       data[filled] = InvalidRagne;
00636     }
00637 #endif
00638 
00639     return filled;
00640   }
00641 }
00642 
00643 
00644 int urg_receiveData(urg_t *urg, long data[], int data_max)
00645 {
00646   if (! urg_isConnected(urg)) {
00647     return -1;
00648   }
00649   return internal_receiveData(urg, data, data_max,
00650                               0, data_max, urg->skip_lines_);
00651 }
00652 
00653 
00654 int urg_receiveDataWithIntensity(urg_t *urg, long data[], int data_max,
00655                                  long intensity[])
00656 {
00657   int i;
00658   int n;
00659 
00660   n = internal_receiveData(urg, data, data_max,
00661                            0, data_max, urg->skip_lines_);
00662 
00663   for (i = 0; i < n; i += 2) {
00664     long length = data[i];
00665 
00666     if ((i + 1) < data_max) {
00667       long intensity_value = data[i + 1];
00668       intensity[i] = intensity_value;
00669       intensity[i + 1] = intensity_value;
00670       data[i + 1] = length;
00671     }
00672   }
00673   return n;
00674 }
00675 
00676 
00677 int urg_receivePartialData(urg_t *urg, long data[], int data_max,
00678                            int first_index, int last_index)
00679 {
00680   return internal_receiveData(urg, data, data_max, first_index, last_index, 1);
00681 }
00682 
00683 
00684 long urg_recentTimestamp(const urg_t *urg)
00685 {
00686   /* Return latest time stamp */
00687   return urg->last_timestamp_;
00688 }
00689 
00690 
00691 double urg_index2rad(const urg_t *urg, int index)
00692 {
00693   double radian = (2.0 * M_PI) *
00694     (index - urg->parameters_.area_front_) / urg->parameters_.area_total_;
00695 
00696   return radian;
00697 }
00698 
00699 
00700 int urg_index2deg(const urg_t *urg, int index)
00701 {
00702   int degree = (int)floor((urg_index2rad(urg, index) * 180 / M_PI) + 0.5);
00703 
00704   return degree;
00705 }
00706 
00707 
00708 int urg_rad2index(const urg_t *urg, double radian)
00709 {
00710   int index =
00711     (int)floor((((radian * urg->parameters_.area_total_) / (2.0*M_PI))
00712                 + urg->parameters_.area_front_) + 0.5);
00713 
00714   if (index < 0) {
00715     index = 0;
00716   } else if (index > urg->parameters_.area_max_) {
00717     index = urg->parameters_.area_max_;
00718   }
00719   return index;
00720 }
00721 
00722 
00723 int urg_deg2index(const urg_t *urg, int degree)
00724 {
00725   return urg_rad2index(urg, M_PI * degree / 180.0);
00726 }
00727 
00728 
00729 int urg_laserOn(urg_t *urg)
00730 {
00731   /* send BM command */
00732   int expected_ret[] = { 0, 2, -1 };
00733   int send_n = scip_send(&urg->serial_, "BM\n");
00734   if (send_n != 3) {
00735     /* !!! urg->errno = UrgSendFail; */
00736     return SerialSendFail;
00737   }
00738   if (scip_recv(&urg->serial_, "BM", NULL, expected_ret, ScipTimeout) == 0) {
00739     urg->is_laser_on_ = UrgLaserOn;
00740   }
00741 
00742   return 0;
00743 }
00744 
00745 
00746 int urg_laserOff(urg_t *urg)
00747 {
00748   return scip_qt(&urg->serial_, NULL, ScipWaitReply);
00749 }
00750 
00751 
00752 int urg_reboot(urg_t *urg)
00753 {
00754   int expected_ret[][2] = {
00755     { 1, -1 },
00756     { 0, -1 },
00757   };
00758   int send_n;
00759   int recv_n;
00760   int i;
00761 
00762   urg_laserOff(urg);
00763 
00764   /* send RB twice */
00765   for (i = 0; i < 2; ++i) {
00766     send_n = scip_send(&urg->serial_, "RB\n");
00767     if (send_n != 3) {
00768       return SerialSendFail;
00769     }
00770 
00771     recv_n = scip_recv(&urg->serial_, "RB", NULL,
00772                        expected_ret[i], ScipTimeout);
00773     if (recv_n < 0) {
00774       return recv_n;
00775     }
00776   }
00777 
00778   /* disconnect immediately */
00779   urg_disconnect(urg);
00780 
00781   return 0;
00782 }
00783 
00784 
00785 int urg_reset(urg_t *urg)
00786 {
00787   return urg_reboot(urg);
00788 }
00789 
00790 
00791 int urg_enableTimestampMode(urg_t *urg)
00792 {
00793   /* Send TM0 */
00794   int expected_ret[] = { 0, 2, -1 };
00795   int send_n = scip_send(&urg->serial_, "TM0\n");
00796   if (send_n != 4) {
00797     return SerialSendFail;
00798   }
00799   return scip_recv(&urg->serial_, "TM", NULL, expected_ret, ScipTimeout);
00800 }
00801 
00802 
00803 int urg_disableTimestampMode(urg_t *urg)
00804 {
00805   /* Send TM2 */
00806   int expected_ret[] = { 0, 3, -1 };
00807   int send_n = scip_send(&urg->serial_, "TM2\n");
00808   if (send_n != 4) {
00809     return SerialSendFail;
00810   }
00811   return scip_recv(&urg->serial_, "TM", NULL, expected_ret, ScipTimeout);
00812 }
00813 
00814 
00815 long urg_currentTimestamp(urg_t *urg)
00816 {
00817   char buffer[ScipLineWidth];
00818   long timestamp = -1;
00819   int ret = 0;
00820   int n;
00821 
00822   /* Send TM1 */
00823   int expected_ret[] = { 0, -1 };
00824   int send_n = scip_send(&urg->serial_, "TM1\n");
00825   if (send_n != 4) {
00826     return SerialSendFail;
00827   }
00828   ret = scip_recv(&urg->serial_, "TM", NULL, expected_ret, ScipTimeout);
00829   if (ret != 0) {
00830     return ret;
00831   }
00832 
00833   /* Decode the timestamp and return */
00834   n = serial_getLine(&urg->serial_, buffer, ScipLineWidth, ScipTimeout);
00835   if (n == 5) {
00836     timestamp = decode(buffer, 4);
00837   }
00838 
00839   /* Read and throw the last response */
00840   n = serial_recv(&urg->serial_, buffer, 1, ScipTimeout);
00841   if (! serial_isLF(buffer[0])) {
00842     serial_ungetc(&urg->serial_, buffer[0]);
00843   }
00844 
00845   return timestamp;
00846 }