/* * RSLIDAR System * Driver Interface * * Copyright 2015 RS Team * All rights reserved. * * Author: ruishi, Data:2015-12-25 * */ #include #include "sdkcommon.h" #include "hal/abs_rxtx.h" #include "hal/thread.h" #include "hal/locker.h" #include "hal/event.h" #include "rslidar_driver_serial.h" //#include using namespace std; #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif namespace rs { namespace standalone{ namespace rslidar { // Factory Impl RSlidarDriver * RSlidarDriver::CreateDriver() { return new RSlidarDriverSerialImpl(); } void RSlidarDriver::DisposeDriver(RSlidarDriver * drv) { delete drv; } // Serial Driver Impl RSlidarDriverSerialImpl::RSlidarDriverSerialImpl(): _isConnected(false), _isScanning(false) { _rxtx = rs::hal::serial_rxtx::CreateRxTx(); _flag_cached_scan_node_ping_pong = NOTE_BUFFER_PING; memset(_cached_scan_note_bufferPing, 0, sizeof(_cached_scan_note_bufferPing)); memset(_cached_scan_note_bufferPong, 0, sizeof(_cached_scan_note_bufferPong)); _cached_scan_node_count = 0; RunningStates = PORT_RDY; } RSlidarDriverSerialImpl::~RSlidarDriverSerialImpl() { disconnect(); rs::hal::serial_rxtx::ReleaseRxTx(_rxtx); } u_result RSlidarDriverSerialImpl::connect(const char * port_path, _u32 baudrate, _u32 flag) { rs::hal::AutoLocker l(_lock); if (isConnected()) return RESULT_ALREADY_DONE; if (!_rxtx) return RESULT_INSUFFICIENT_MEMORY; // establish the serial connection... if (!_rxtx->bind(port_path, baudrate) || !_rxtx->open()) { return RESULT_INVALID_DATA; } _rxtx->flush(0); _isConnected = true; _isGetData = true; return RESULT_OK; } void RSlidarDriverSerialImpl::disconnect() { if (!_isConnected) return ; stopScan(); _rxtx->close(); } bool RSlidarDriverSerialImpl::isConnected() { return _isConnected; } u_result RSlidarDriverSerialImpl::_cacheSerialData() { return RESULT_OK; } u_result RSlidarDriverSerialImpl::resetlidar(_u32 timeout) { _u8 param = 0x08; u_result ans; COMM_FRAME_T *response_header = reinterpret_cast(_paramReceiveBuf); if (!isConnected()) return RESULT_OPERATION_FAIL; _disableDataGrabbing(); { rs::hal::AutoLocker l(_lock); param = RESET_MODE; if (IS_FAIL(ans = _sendCommand(CMD_WORK_MODE, ¶m, 1))) { return ans; } if (IS_FAIL(ans = _waitResponseHeader(response_header, CMD_WORK_MODE, NULL,1, timeout))) { return ans; } if ((response_header->command&COMM_FRAME_ERROR) > 0) { return *(response_header->paramBuf); } } return RESULT_OK; } u_result RSlidarDriverSerialImpl::setMotorRpm(_u16 speed, _u32 timeout) { _u8 Data[] = { 0x23,0x01,0x67,0x45,0xAB,0x89,0xEF,0xCD,0x00,0x00}; u_result ans; COMM_FRAME_T *response_header = reinterpret_cast(_paramReceiveBuf); Data[8] = speed; Data[9] = speed >> 8; if (!isConnected()) return RESULT_OPERATION_FAIL; //_disableDataGrabbing(); { //rs::hal::AutoLocker l(_lock); if (IS_FAIL(ans = _sendCommand(CMD_SET_MOTOR_SPEED, &Data, 10))) { return ans; } if (IS_FAIL(ans = _waitResponseHeader(response_header, CMD_SET_MOTOR_SPEED, NULL,1, timeout))) { return ans; } if ((response_header->command&COMM_FRAME_ERROR) > 0) { return (*(response_header->paramBuf)); } } return RESULT_OK; } u_result RSlidarDriverSerialImpl::getDeviceInfo(LIDAR_RESPONSE_DEV_INFO_T * info, _u32 timeout) { u_result ans; COMM_FRAME_T *response_header = reinterpret_cast(_paramReceiveBuf); if (!isConnected()) return RESULT_OPERATION_FAIL; _disableDataGrabbing(); { rs::hal::AutoLocker l(_lock); if (IS_FAIL(ans = _sendCommand(CMD_READ_DEV_VER, NULL, 0))) { return ans; } if (IS_FAIL(ans = _waitResponseHeader(response_header, CMD_READ_DEV_VER, NULL,45, timeout))) { return ans; } if ((response_header->command&COMM_FRAME_ERROR) > 0) { return (*(response_header->paramBuf)); } memcpy(info, response_header->paramBuf, response_header->paramLen); } return RESULT_OK; } u_result RSlidarDriverSerialImpl::startScan(_u8 scanmode,_u32 timeout) { _u8 param = scanmode; u_result ans; COMM_FRAME_T *response_header = reinterpret_cast(_paramReceiveBuf); if (!isConnected()) return RESULT_OPERATION_FAIL; if (_isScanning) return RESULT_ALREADY_DONE; { rs::hal::AutoLocker l(_lock); _rxtx->flush(0); if (IS_FAIL(ans = _sendCommand(CMD_WORK_MODE, ¶m, 1))) { return ans; } /*if (IS_FAIL(ans = _waitResponseHeader(response_header, CMD_WORK_MODE, NULL, 1, timeout))) { return ans; } if ((response_header->command&COMM_FRAME_ERROR) > 0) { return (*(response_header->paramBuf)); } */ _isScanning = true; _cachethread = CLASS_THREAD(RSlidarDriverSerialImpl, _cacheScanData); } return RESULT_OK; } u_result RSlidarDriverSerialImpl::stopScan(_u32 timeout) { _u8 param = 0x00; u_result ans; COMM_FRAME_T *response_header = reinterpret_cast(_paramReceiveBuf); if (!isConnected()) return RESULT_OPERATION_FAIL; _disableDataGrabbing(); { rs::hal::AutoLocker l(_lock); if (IS_FAIL(ans = _sendCommand(CMD_WORK_MODE,¶m,1))) { return ans; } if (IS_FAIL(ans = _waitResponseHeader(response_header, CMD_WORK_MODE, NULL,1, timeout))) { return ans; } if ((response_header->command&COMM_FRAME_ERROR) > 0) { return (*(response_header->paramBuf)); } } return RESULT_OK; } u_result RSlidarDriverSerialImpl::_cacheScanData() { LIDAR_MEASURE_INFO_T *local_buf = NULL; size_t count = NUMBER_OF_TEETH; size_t scan_count = 0; u_result ans; _flag_cached_scan_node_ping_pong = NOTE_BUFFER_PING; local_buf = _cached_scan_note_bufferPong; _waitScanData(local_buf, count); // // always discard the first data since it may be incomplete count = NUMBER_OF_TEETH; while (_isScanning) { if (IS_FAIL(ans = _waitScanData(local_buf, count))) { if (!((ans == RESULT_OPERATION_TIMEOUT) || (ans == RESULT_RECEIVE_NODE_ERROR))) { _isScanning = false; return RESULT_OPERATION_FAIL; } } _lock.lock(); _flag_cached_scan_node_ping_pong = _flag_cached_scan_node_ping_pong ^ 0x01; if (NOTE_BUFFER_PING == _flag_cached_scan_node_ping_pong) { local_buf = _cached_scan_note_bufferPong; } else if (NOTE_BUFFER_PONG == _flag_cached_scan_node_ping_pong) { local_buf = _cached_scan_note_bufferPing; } else{} _cached_scan_node_count = count; _dataEvt.set(); _lock.unlock(); count = NUMBER_OF_TEETH; } _isScanning = false; return RESULT_OK; } u_result RSlidarDriverSerialImpl::_waitScanData(LIDAR_MEASURE_INFO_T * nodebuffer, size_t & count, _u32 timeout) { _u8 recvBuffer[1024]; _u16 frameLens = 0; _u16 paramLens = 0; _u16 angleRange = 0; float angleStep = 0; float speed; float angleoffset; bool flagOfNewNodes = false; _u16 crcCheckNum = 0,calcchecksum; _u16 sampleNumber = 0; _u16 sampleNumberCount = 0; if (!_isConnected) { count = 0; return RESULT_OPERATION_FAIL; } size_t recvNodeCount = 0; _u32 startTs = getms(); _u32 waitTime; u_result ans; while ((waitTime = getms() - startTs) <= timeout && recvNodeCount < count) { if (IS_FAIL(ans = _waitNode(recvBuffer, timeout - waitTime))) { return ans; } frameLens = (recvBuffer[2] << 8) | recvBuffer[1]; crcCheckNum = *(_u16 *)(recvBuffer + frameLens); calcchecksum = _checksum(recvBuffer, frameLens); angleRange = (recvBuffer[10] << 8) | recvBuffer[9]; if (crcCheckNum == calcchecksum) { paramLens = (recvBuffer[6] << 8) | recvBuffer[5]; sampleNumber = (paramLens - 4) / 2; if ((angleRange >= 35000) || (angleRange <= 100)) //find original point { flagOfNewNodes = true; recvNodeCount = 0; sampleNumberCount = 0; angleStep = 36000.0 / sampleNumber / NUMBER_OF_TEETH; } if (flagOfNewNodes) { speed = ((recvBuffer[8] << 8) | recvBuffer[7])*0.01; angleoffset = 0; for (int i = 0; i < sampleNumber; i++) { (nodebuffer + sampleNumberCount)->motorspeed = speed; (nodebuffer + sampleNumberCount)->angle = angleRange + i * angleStep; (nodebuffer + sampleNumberCount)->angleoffset = angleoffset; (nodebuffer + sampleNumberCount)->distance = (recvBuffer[12 + i * 2] << 8) | recvBuffer[11 + i * 2]; // printf("this is my shared data somehow"); printf("test \n"); sampleNumberCount++; } recvNodeCount++; } } else { RunningStates = CHKSUM_ERROR; continue; } if (recvNodeCount == count) { flagOfNewNodes = false; count = sampleNumberCount; return RESULT_OK; } } //CLogout("_waitScanData002:%d \r\n", sampleNumberCount); count = sampleNumberCount; return RESULT_OPERATION_TIMEOUT; } u_result RSlidarDriverSerialImpl::_waitNode(_u8 * nodeBuffer, _u32 timeout) { int recvPos = 0; _u32 startTs = getms(); _u8 recvBuffer[512]; _u32 waitTime; _u16 frameLens = 0; size_t recvSize; size_t remainSize; size_t pos; bool frameDataRcvFlag = false; char tmp_message[100]; memset(tmp_message, 0, 100); while ((waitTime = getms() - startTs) <= timeout) { if (false == frameDataRcvFlag) { //receive head info remainSize = sizeof(COMM_FRAME_T) - recvPos; } else { //receive data remainSize = frameLens + 2 - recvPos; } recvSize = 0; //printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); int ans = _rxtx->waitfordata(remainSize, timeout, &recvSize); if (ans == rs::hal::serial_rxtx::ANS_DEV_ERR) { return RESULT_OPERATION_FAIL; } if ((ans == rs::hal::serial_rxtx::ANS_TIMEOUT) && (0 == recvSize)) { GetLocalTime(&tm_time_out); int tm_cha = ((tm_time_out.wMinute - tm_error_frame.wMinute) * 60 + (tm_time_out.wSecond - tm_error_frame.wSecond)) * 1000 + (tm_time_out.wMilliseconds - tm_error_frame.wMilliseconds); if (tm_cha > 500) { _cprintf("[Eror]: Receive data timeout!\r\n"); RunningStates = RX_DATA_TIMOUT; continue; } } if (recvSize > remainSize) recvSize = remainSize; _rxtx->recvdata(recvBuffer, recvSize); for (pos = 0; pos < recvSize; ++pos) { _u8 currentByte = recvBuffer[pos]; if (0 == recvPos) { if (COMM_HEAD_FLAGE != currentByte) { frameDataRcvFlag = false; continue; } } else if (4 == recvPos) { frameLens = (nodeBuffer[2] << 8) | nodeBuffer[1]; //if ((frameLens > 300) || (recvPos < (sizeof(COMM_FRAME_T) - 1))) if (frameLens > 300) { recvPos = 0; frameLens = 0; frameDataRcvFlag = false; continue; } else frameDataRcvFlag = true; if (CMD_REPORT_DEV_ERROR == (currentByte&COMM_MASK)) { RunningStates = MOTOR_STALL; continue; } if (CMD_REPORT_DIST != (currentByte&COMM_MASK)) continue; } nodeBuffer[recvPos++] = currentByte; if ((recvPos >= (frameLens + 2))&&(recvPos > sizeof(COMM_FRAME_T))) { RunningStates = WORK_WELL; return RESULT_OK; } } } return RESULT_OPERATION_TIMEOUT; } u_result RSlidarDriverSerialImpl::grabScanData(LIDAR_MEASURE_INFO_T * nodebuffer, size_t & count, _u32 timeout) { switch (_dataEvt.wait(timeout)) { case rs::hal::Event::EVENT_TIMEOUT: count = 0; return RESULT_OPERATION_TIMEOUT; break; case rs::hal::Event::EVENT_OK: { rs::hal::AutoLocker l(_lock); size_t size_to_copy = min(count, _cached_scan_node_count); if (NOTE_BUFFER_PING == _flag_cached_scan_node_ping_pong) { memcpy(nodebuffer, _cached_scan_note_bufferPing, size_to_copy*sizeof(LIDAR_MEASURE_INFO_T)); } else if (NOTE_BUFFER_PONG == _flag_cached_scan_node_ping_pong) { memcpy(nodebuffer, _cached_scan_note_bufferPong, size_to_copy*sizeof(LIDAR_MEASURE_INFO_T)); } count = size_to_copy; _cached_scan_node_count = 0; } return RESULT_OK; break; default: count = 0; return RESULT_OPERATION_FAIL; break; } } u_result RSlidarDriverSerialImpl::ascendScanData(LIDAR_MEASURE_INFO_T * nodebuffer, size_t count) { float inc_origin_angle = 360.0/count; int i = 0; //Tune head for (i = 0; i < count; i++) { if(nodebuffer[i].distance == 0) { continue; } else { while(i != 0) { i--; float expect_angle = (nodebuffer[i+1].angle)/100.0f - inc_origin_angle; if (expect_angle < 0.0f) expect_angle = 0.0f; nodebuffer[i].angle = (_u16)(expect_angle * 100.0f); } break; } } // all the data is invalid if (i == count) return RESULT_OPERATION_FAIL; //Tune tail for (i = count - 1; i >= 0; i--) { if (nodebuffer[i].distance == 0) { continue; } else { while(i != (count - 1)) { i++; float expect_angle = (nodebuffer[i - 1].angle) / 100.0f + inc_origin_angle; if (expect_angle > 360.0f) expect_angle -= 360.0f; nodebuffer[i].angle = (_u16)(expect_angle * 100.0f); } break; } } //Fill invalid angle in the scan float frontAngle = (nodebuffer[0].angle) / 100.0f; for (i = 1; i < count; i++) { if (nodebuffer[i].distance == 0) { float expect_angle = frontAngle + i * inc_origin_angle; if (expect_angle > 360.0f) expect_angle -= 360.0f; nodebuffer[i].angle = (_u16)(expect_angle * 100.0f); } } // Reorder the scan according to the angle value for (i = 0; i < (count-1); i++){ for (int j = (i+1); j < count; j++){ if (nodebuffer[i].angle > nodebuffer[j].angle){ LIDAR_MEASURE_INFO_T temp = nodebuffer[i]; nodebuffer[i] = nodebuffer[j]; nodebuffer[j] = temp; } } } return RESULT_OK; } u_result RSlidarDriverSerialImpl::_sendCommand(_u8 cmd, const void * payload, size_t payloadsize) { _u16 checksum = 0; _u8 commBuf[1024] = {0}; COMM_FRAME_T *commFrameTmp = reinterpret_cast(commBuf); const _u8 *pPayload = reinterpret_cast(payload); if (!_isConnected) return RESULT_OPERATION_FAIL; commFrameTmp->framehead = COMM_HEAD_FLAGE; commFrameTmp->frameLen = sizeof(COMM_FRAME_T)+payloadsize; commFrameTmp->protocolver = 4; commFrameTmp->command = cmd; if (payloadsize && payload) { commFrameTmp->paramLen = payloadsize; } else { commFrameTmp->paramLen = 0; } if (payloadsize > 0) { for (int i = payloadsize-1; i >= 0; i--) *(commFrameTmp->paramBuf+i) = *(pPayload+i); } checksum = _checksum(commBuf, sizeof(COMM_FRAME_T) + payloadsize); commBuf[sizeof(COMM_FRAME_T)+payloadsize] = checksum; commBuf[sizeof(COMM_FRAME_T)+payloadsize + 1] = checksum >> 8; // send header first for (int i = 0; i < (sizeof(COMM_FRAME_T)+payloadsize + sizeof(_u16));i++) printf("%02x ", commBuf[i]); printf("\n"); _rxtx->senddata(commBuf, sizeof(COMM_FRAME_T)+payloadsize + sizeof(_u16)); return RESULT_OK; } u_result RSlidarDriverSerialImpl::_waitResponseHeader(COMM_FRAME_T * header, _u8 Cmmd,const void * payload, size_t payloadsize, _u32 timeout) { _u8 Data[512]; int recvPos = 0,readPos = 0,i; _u32 startTs = getms(); _u8 *headerBuffer = reinterpret_cast<_u8 *>(header); _u32 waitTime; _u16 framelen,checksumCac, checksumRcv; size_t remainSize = sizeof(COMM_FRAME_T) + payloadsize + sizeof(_u16); size_t recvSize; while ((waitTime = getms() - startTs) <= timeout) { int ans = _rxtx->waitfordata(remainSize, timeout - waitTime, &recvSize); if (ans == rs::hal::serial_rxtx::ANS_DEV_ERR) { return RESULT_OPERATION_FAIL; } else if (ans == rs::hal::serial_rxtx::ANS_TIMEOUT) { return RESULT_OPERATION_TIMEOUT; } if (recvSize > (sizeof(Data) - (recvPos & 0x1FF))) { _rxtx->recvdata(&Data[recvPos & 0x1FF], sizeof(Data) - (recvPos & 0x1FF)); _rxtx->recvdata(Data,recvSize - sizeof(Data) + (recvPos & 0x1FF)); } else _rxtx->recvdata(&Data[recvPos & 0x1FF], recvSize); recvPos += recvSize; if ((readPos + remainSize) > recvPos) continue; else { for (; readPos < recvPos; readPos++) { if (Data[readPos & 0x1FF] != COMM_HEAD_FLAGE) continue; else { framelen = (Data[(readPos + 2) & 0x1FF] << 8) | Data[(readPos + 1) & 0x1FF]; if (framelen > 100) continue; if ((framelen + 2) > (recvPos - readPos)) break; if ((Data[(readPos + 4) & 0x1FF]&COMM_MASK) != Cmmd) continue; checksumCac = _Cyclechecksum(Data,readPos,framelen,sizeof(Data)); checksumRcv = (Data[(readPos + framelen + 1) & 0x1FF] << 8) | Data[(readPos + framelen) & 0x1FF]; if (checksumCac == checksumRcv) { for (i = 0; i < (payloadsize + sizeof(COMM_FRAME_T)); i++) { *headerBuffer++ = Data[(readPos + i) & 0x1FF]; } return RESULT_OK; } else return RESULT_INVALID_DATA; } } } } return RESULT_OPERATION_TIMEOUT; } uint16_t RSlidarDriverSerialImpl::_Cyclechecksum(uint8_t *startByte, _u32 pos,uint16_t numBytes,_u32 buffersize) { uint16_t checksum = 0; // CRC���ұ��ָ�� while (numBytes--) { checksum += *(startByte + (pos%buffersize)); // ����CRC pos++; } return checksum; } uint16_t RSlidarDriverSerialImpl::_checksum(uint8_t *startByte, uint16_t numBytes) { uint16_t checksum = 0; // CRC���ұ��ָ�� while (numBytes--) { checksum += *startByte++; // ����CRC } return checksum; } void RSlidarDriverSerialImpl::_disableDataGrabbing() { _isScanning = false; _cachethread.join(); _rxtx->flush(0); } }}}