+
+//-----------------------------------------------------------------------------
+// General class macro definitions and typedefs
+//-----------------------------------------------------------------------------
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET ~(0)
+#endif
+
+#define SOCKET_SENDFILE_BLOCKSIZE 8192
+
+namespace ydlidar {
+namespace core {
+using namespace common;
+namespace network {
+
+
+/// Provides a platform independent class to for socket development.
+/// This class is designed to abstract socket communication development in a
+/// platform independent manner.
+/// - Socket types
+/// -# CActiveSocket Class
+/// -# CPassiveSocket Class
+class CSimpleSocket : public ChannelDevice {
+ public:
+ /// Defines the three possible states for shuting down a socket.
+ typedef enum {
+ Receives = SHUT_RD, ///< Shutdown passive socket.
+ Sends = SHUT_WR, ///< Shutdown active socket.
+ Both = SHUT_RDWR ///< Shutdown both active and passive sockets.
+ } CShutdownMode;
+
+ /// Defines the socket types defined by CSimpleSocket class.
+ typedef enum {
+ SocketTypeInvalid = 0, ///< Invalid socket type.
+ SocketTypeTcp, ///< Defines socket as TCP socket.
+ SocketTypeUdp, ///< Defines socket as UDP socket.
+ SocketTypeTcp6, ///< Defines socket as IPv6 TCP socket.
+ SocketTypeUdp6, ///< Defines socket as IPv6 UDP socket.
+ SocketTypeRaw ///< Provides raw network protocol access.
+ } CSocketType;
+
+ /// Defines all error codes handled by the CSimpleSocket class.
+ typedef enum {
+ SocketError = -1, ///< Generic socket error translates to error below.
+ SocketSuccess = 0, ///< No socket error.
+ SocketInvalidSocket, ///< Invalid socket handle.
+ SocketInvalidAddress, ///< Invalid destination address specified.
+ SocketInvalidPort, ///< Invalid destination port specified.
+ SocketConnectionRefused, ///< No server is listening at remote address.
+ SocketTimedout, ///< Timed out while attempting operation.
+ SocketEwouldblock, ///< Operation would block if socket were blocking.
+ SocketNotconnected, ///< Currently not connected.
+ SocketEinprogress, ///< Socket is non-blocking and the connection cannot be completed immediately
+ SocketInterrupted, ///< Call was interrupted by a signal that was caught before a valid connection arrived.
+ SocketConnectionAborted, ///< The connection has been aborted.
+ SocketProtocolError, ///< Invalid protocol for operation.
+ SocketFirewallError, ///< Firewall rules forbid connection.
+ SocketInvalidSocketBuffer, ///< The receive buffer point outside the process's address space.
+ SocketConnectionReset, ///< Connection was forcibly closed by the remote host.
+ SocketAddressInUse, ///< Address already in use.
+ SocketInvalidPointer, ///< Pointer type supplied as argument is invalid.
+ SocketEunknown ///< Unknown error please report to mark@carrierlabs.com
+ } CSocketError;
+
+ public:
+ explicit CSimpleSocket(CSocketType type = SocketTypeTcp);
+ explicit CSimpleSocket(CSimpleSocket &socket);
+
+ virtual ~CSimpleSocket() {
+ if (m_pBuffer != NULL) {
+ delete [] m_pBuffer;
+ m_pBuffer = NULL;
+ }
+ };
+
+ static void WSACleanUp();
+
+
+ /// Initialize instance of CSocket. This method MUST be called before an
+ /// object can be used. Errors : CSocket::SocketProtocolError,
+ /// CSocket::SocketInvalidSocket,
+ /// @return true if properly initialized.
+ virtual bool Initialize(void);
+
+ /// Close socket
+ /// @return true if successfully closed otherwise returns false.
+ virtual bool Close(void);
+
+ /// Shutdown shut down socket send and receive operations
+ /// CShutdownMode::Receives - Disables further receive operations.
+ /// CShutdownMode::Sends - Disables further send operations.
+ /// CShutdownBoth:: - Disables further send and receive operations.
+ /// @param nShutdown specifies the type of shutdown.
+ /// @return true if successfully shutdown otherwise returns false.
+ virtual bool Shutdown(CShutdownMode nShutdown);
+
+ /// Examine the socket descriptor sets currently owned by the instance of
+ /// the socket class (the readfds, writefds, and errorfds parameters) to
+ /// see whether some of their descriptors are ready for reading, are ready
+ /// for writing, or have an exceptional condition pending, respectively.
+ /// Block until an event happens on the specified file descriptors.
+ /// @return true if socket has data ready, or false if not ready or timed out.
+ virtual bool Select(void) {
+ return Select(0, 0);
+ };
+
+ /// Examine the socket descriptor sets currently owned by the instance of
+ /// the socket class (the readfds, writefds, and errorfds parameters) to
+ /// see whether some of their descriptors are ready for reading, are ready
+ /// for writing, or have an exceptional condition pending, respectively.
+ /// @param nTimeoutSec timeout in seconds for select.
+ /// @param nTimeoutUSec timeout in micro seconds for select.
+ /// @return true if socket has data ready, or false if not ready or timed out.
+ virtual bool Select(int32_t nTimeoutSec, int32_t nTimeoutUSec);
+
+
+ virtual int WaitForData(size_t data_count, uint32_t timeout,
+ size_t *returned_size);
+
+ /// Does the current instance of the socket object contain a valid socket
+ /// descriptor.
+ /// @return true if the socket object contains a valid socket descriptor.
+ virtual bool IsSocketValid(void) {
+ return (m_socket != SocketError);
+ };
+
+ /// Provides a standard error code for cross platform development by
+ /// mapping the operating system error to an error defined by the CSocket
+ /// class.
+ void TranslateSocketError(void);
+
+ /// Returns a human-readable description of the given error code
+ /// or the last error code of a socket
+ static const char *DescribeError(CSocketError err);
+ ///
+ /// \brief DescribeError
+ /// \return
+ ///
+ virtual const char *DescribeError() {
+ return DescribeError(m_socketErrno);
+ };
+
+ /// Attempts to receive a block of data on an established connection.
+ /// @param nMaxBytes maximum number of bytes to receive.
+ /// @param pBuffer, memory where to receive the data,
+ /// NULL receives to internal buffer returned with GetData()
+ /// Non-NULL receives directly there, but GetData() will return WRONG ptr!
+ /// @return number of bytes actually received.
+ /// @return of zero means the connection has been shutdown on the other side.
+ /// @return of -1 means that an error has occurred.
+ virtual int32_t Receive(int32_t nMaxBytes = 1, uint8_t *pBuffer = 0);
+
+ /// Attempts to send a block of data on an established connection.
+ /// @param pBuf block of data to be sent.
+ /// @param bytesToSend size of data block to be sent.
+ /// @return number of bytes actually sent.
+ /// @return of zero means the connection has been shutdown on the other side.
+ /// @return of -1 means that an error has occurred.
+ virtual int32_t Send(const uint8_t *pBuf, size_t bytesToSend);
+
+ /// Attempts to send at most nNumItem blocks described by sendVector
+ /// to the socket descriptor associated with the socket object.
+ /// @param sendVector pointer to an array of iovec structures
+ /// @param nNumItems number of items in the vector to process
+ ///
\b NOTE: Buffers are processed in the order specified.
+ /// @return number of bytes actually sent, return of zero means the
+ /// connection has been shutdown on the other side, and a return of -1
+ /// means that an error has occurred.
+ virtual int32_t Send(const struct iovec *sendVector, int32_t nNumItems);
+
+ /// Copies data between one file descriptor and another.
+ /// On some systems this copying is done within the kernel, and thus is
+ /// more efficient than the combination of CSimpleSocket::Send and
+ /// CSimpleSocket::Receive, which would require transferring data to and
+ /// from user space.
+ ///
\b Note: This is available on all implementations, but the kernel
+ /// implementation is only available on Unix type systems.
+ /// @param nOutFd descriptor opened for writing.
+ /// @param nInFd descriptor opened for reading.
+ /// @param pOffset from which to start reading data from input file.
+ /// @param nCount number of bytes to copy between file descriptors.
+ /// @return number of bytes written to the out socket descriptor.
+ virtual int32_t SendFile(int32_t nOutFd, int32_t nInFd, off_t *pOffset,
+ int32_t nCount);
+
+ /// Returns blocking/non-blocking state of socket.
+ /// @return true if the socket is non-blocking, else return false.
+ bool IsNonblocking(void) {
+ return (m_bIsBlocking == false);
+ };
+
+ /// Set the socket to blocking.
+ /// @return true if successful set to blocking, else return false;
+ bool SetBlocking(void);
+
+ /// Set the socket as non-blocking.
+ /// @return true if successful set to non-blocking, else return false;
+ bool SetNonblocking(void);
+
+ /// Get a pointer to internal receive buffer. The user MUST not free this
+ /// pointer when finished. This memory is managed internally by the CSocket
+ /// class.
+ /// @return pointer to data if valid, else returns NULL.
+ uint8_t *GetData(void) {
+ return m_pBuffer;
+ };
+
+ /// Returns the number of bytes received on the last call to
+ /// CSocket::Receive().
+ /// @return number of bytes received.
+ int32_t GetBytesReceived(void) {
+ return m_nBytesReceived;
+ };
+
+ /// Returns the number of bytes sent on the last call to
+ /// CSocket::Send().
+ /// @return number of bytes sent.
+ int32_t GetBytesSent(void) {
+ return m_nBytesSent;
+ };
+
+ /// Controls the actions taken when CSimpleSocket::Close is executed on a
+ /// socket object that has unsent data. The default value for this option
+ /// is \b off.
+ /// - Following are the three possible scenarios.
+ /// -# \b bEnable is false, CSimpleSocket::Close returns immediately, but
+ /// any unset data is transmitted (after CSimpleSocket::Close returns)
+ /// -# \b bEnable is true and \b nTime is zero, CSimpleSocket::Close return
+ /// immediately and any unsent data is discarded.
+ /// -# \b bEnable is true and \b nTime is nonzero, CSimpleSocket::Close does
+ /// not return until all unsent data is transmitted (or the connection is
+ /// Closed by the remote system).
+ ///
+ /// @param bEnable true to enable option false to disable option.
+ /// @param nTime time in seconds to linger.
+ /// @return true if option successfully set
+ bool SetOptionLinger(bool bEnable, uint16_t nTime);
+
+ /// Tells the kernel that even if this port is busy (in the TIME_WAIT state),
+ /// go ahead and reuse it anyway. If it is busy, but with another state,
+ /// you will still get an address already in use error.
+ /// @return true if option successfully set
+ bool SetOptionReuseAddr();
+
+ /// Gets the timeout value that specifies the maximum number of seconds a
+ /// call to CSimpleSocket::Open waits until it completes.
+ /// @return the length of time in seconds
+ int32_t GetConnectTimeoutSec(void) {
+ return m_stConnectTimeout.tv_sec;
+ };
+
+ /// Gets the timeout value that specifies the maximum number of microseconds
+ /// a call to CSimpleSocket::Open waits until it completes.
+ /// @return the length of time in microseconds
+ int32_t GetConnectTimeoutUSec(void) {
+ return m_stConnectTimeout.tv_usec;
+ };
+
+ /// Sets the timeout value that specifies the maximum amount of time a call
+ /// to CSimpleSocket::Receive waits until it completes. Use the method
+ /// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
+ /// If a call to CSimpleSocket::Receive has blocked for the specified length of
+ /// time without receiving additional data, it returns with a partial count
+ /// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data
+ /// were received.
+ /// @param nConnectTimeoutSec of timeout in seconds.
+ /// @param nConnectTimeoutUsec of timeout in microseconds.
+ /// @return true if socket connection timeout was successfully set.
+ void SetConnectTimeout(int32_t nConnectTimeoutSec,
+ int32_t nConnectTimeoutUsec = 0) {
+ m_stConnectTimeout.tv_sec = nConnectTimeoutSec;
+ m_stConnectTimeout.tv_usec = nConnectTimeoutUsec;
+ };
+
+ /// Gets the timeout value that specifies the maximum number of seconds a
+ /// a call to CSimpleSocket::Receive waits until it completes.
+ /// @return the length of time in seconds
+ int32_t GetReceiveTimeoutSec(void) {
+ return m_stRecvTimeout.tv_sec;
+ };
+
+ /// Gets the timeout value that specifies the maximum number of microseconds
+ /// a call to CSimpleSocket::Receive waits until it completes.
+ /// @return the length of time in microseconds
+ int32_t GetReceiveTimeoutUSec(void) {
+ return m_stRecvTimeout.tv_usec;
+ };
+
+ /// Sets the timeout value that specifies the maximum amount of time a call
+ /// to CSimpleSocket::Receive waits until it completes. Use the method
+ /// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
+ /// If a call to CSimpleSocket::Receive has blocked for the specified length of
+ /// time without receiving additional data, it returns with a partial count
+ /// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data
+ /// were received.
+ /// @param nRecvTimeoutSec of timeout in seconds.
+ /// @param nRecvTimeoutUsec of timeout in microseconds.
+ /// @return true if socket timeout was successfully set.
+ bool SetReceiveTimeout(int32_t nRecvTimeoutSec, int32_t nRecvTimeoutUsec = 0);
+
+ /// Enable/disable multicast for a socket. This options is only valid for
+ /// socket descriptors of type CSimpleSocket::SocketTypeUdp.
+ /// @return true if multicast was enabled or false if socket type is not
+ /// CSimpleSocket::SocketTypeUdp and the error will be set to
+ /// CSimpleSocket::SocketProtocolError
+ bool SetMulticast(bool bEnable, uint8_t multicastTTL = 1);
+
+ /// Return true if socket is multicast or false is socket is unicast
+ /// @return true if multicast is enabled
+ bool GetMulticast() {
+ return m_bIsMulticast;
+ };
+
+ /// Bind socket to a specific interface when using multicast.
+ /// @return true if successfully bound to interface
+ bool BindInterface(const char *pInterface);
+
+ /// Gets the timeout value that specifies the maximum number of seconds a
+ /// a call to CSimpleSocket::Send waits until it completes.
+ /// @return the length of time in seconds
+ int32_t GetSendTimeoutSec(void) {
+ return m_stSendTimeout.tv_sec;
+ };
+
+ /// Gets the timeout value that specifies the maximum number of microseconds
+ /// a call to CSimpleSocket::Send waits until it completes.
+ /// @return the length of time in microseconds
+ int32_t GetSendTimeoutUSec(void) {
+ return m_stSendTimeout.tv_usec;
+ };
+
+ /// Gets the timeout value that specifies the maximum amount of time a call
+ /// to CSimpleSocket::Send waits until it completes.
+ /// @return the length of time in seconds
+ bool SetSendTimeout(int32_t nSendTimeoutSec, int32_t nSendTimeoutUsec = 0);
+
+ /// Returns the last error that occured for the instace of the CSimpleSocket
+ /// instance. This method should be called immediately to retrieve the
+ /// error code for the failing mehtod call.
+ /// @return last error that occured.
+ CSocketError GetSocketError(void) {
+ return m_socketErrno;
+ };
+
+ /// Get the total time the of the last operation in milliseconds.
+ /// @return number of milliseconds of last operation.
+ uint32_t GetTotalTimeMs() {
+ return m_timer.GetMilliSeconds();
+ };
+
+ /// Get the total time the of the last operation in microseconds.
+ /// @return number of microseconds or last operation.
+ uint64_t GetTotalTimeUsec() {
+ return m_timer.GetMicroSeconds();
+ };
+
+ /// Return Differentiated Services Code Point (DSCP) value currently set on the socket object.
+ /// @return DSCP for current socket object.
+ ///
\b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
+ int GetSocketDscp(void);
+
+ /// Set Differentiated Services Code Point (DSCP) for socket object.
+ /// @param nDscp value of TOS setting which will be converted to DSCP
+ /// @return true if DSCP value was properly set
+ ///
\b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
+ bool SetSocketDscp(int nDscp);
+
+ /// Return socket descriptor
+ /// @return socket descriptor which is a signed 32 bit integer.
+ SOCKET GetSocketDescriptor() {
+ return m_socket;
+ };
+
+ /// Return socket descriptor
+ /// @return socket descriptor which is a signed 32 bit integer.
+ CSocketType GetSocketType() {
+ return m_nSocketType;
+ };
+
+ /// set socket descriptor
+ void SetSocketType(const CSocketType &type) {
+ m_nSocketType = type;
+ }
+
+ /// Returns clients Internet host address as a string in standard numbers-and-dots notation.
+ /// @return NULL if invalid
+ const char *GetClientAddr() {
+ return inet_ntoa(m_stClientSockaddr.sin_addr);
+ };
+
+ /// Returns the port number on which the client is connected.
+ /// @return client port number.
+ uint16_t GetClientPort() {
+ return m_stClientSockaddr.sin_port;
+ };
+
+ /// Returns server Internet host address as a string in standard numbers-and-dots notation.
+ /// @return NULL if invalid
+ const char *GetServerAddr() {
+ return inet_ntoa(m_stServerSockaddr.sin_addr);
+ };
+
+ /// Returns the port number on which the server is connected.
+ /// @return server port number.
+ uint16_t GetServerPort() {
+ return ntohs(m_stServerSockaddr.sin_port);
+ };
+
+ /// Get the TCP receive buffer window size for the current socket object.
+ ///
\b NOTE: Linux will set the receive buffer to twice the value passed.
+ /// @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
+ uint32_t GetReceiveWindowSize() {
+ return GetWindowSize(SO_RCVBUF);
+ };
+
+ /// Get the TCP send buffer window size for the current socket object.
+ ///
\b NOTE: Linux will set the send buffer to twice the value passed.
+ /// @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
+ uint32_t GetSendWindowSize() {
+ return GetWindowSize(SO_SNDBUF);
+ };
+
+ /// Set the TCP receive buffer window size for the current socket object.
+ ///
\b NOTE: Linux will set the receive buffer to twice the value passed.
+ /// @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
+ uint32_t SetReceiveWindowSize(uint32_t nWindowSize) {
+ return SetWindowSize(SO_RCVBUF, nWindowSize);
+ };
+
+ /// Set the TCP send buffer window size for the current socket object.
+ ///
\b NOTE: Linux will set the send buffer to twice the value passed.
+ /// @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
+ uint32_t SetSendWindowSize(uint32_t nWindowSize) {
+ return SetWindowSize(SO_SNDBUF, nWindowSize);
+ };
+
+ /// Disable the Nagle algorithm (Set TCP_NODELAY to true)
+ /// @return false if failed to set socket option otherwise return true;
+ bool DisableNagleAlgoritm();
+
+ /// Enable the Nagle algorithm (Set TCP_NODELAY to false)
+ /// @return false if failed to set socket option otherwise return true;
+ bool EnableNagleAlgoritm();
+
+ virtual bool Open(const char *pAddr, uint16_t nPort) {
+ return true;
+ }
+
+ ///
+ /// \brief bindport
+ /// \return
+ ///
+ virtual bool bindport(const char *, uint32_t);
+
+ ///
+ /// \brief open
+ /// \return
+ ///
+ virtual bool open();
+
+ ///
+ /// \brief isOpen
+ /// \return
+ ///
+ virtual bool isOpen();
+
+ ///
+ /// \brief closePort
+ ///
+ virtual void closePort();
+
+ ///
+ /// \brief flush
+ ///
+ virtual void flush();
+
+ ///
+ /// \brief available
+ /// \return
+ ///
+ virtual size_t available();
+
+ ///
+ /// \brief readSize
+ /// \param size
+ /// \return
+ ///
+ virtual std::string readSize(size_t size = 1);
+
+ ///
+ /// \brief waitfordata
+ /// \param data_count
+ /// \param timeout
+ /// \param returned_size
+ /// \return
+ ///
+ virtual int waitfordata(size_t data_count, uint32_t timeout = -1,
+ size_t *returned_size = NULL);
+
+ ///
+ /// \brief writeData
+ /// \param data
+ /// \param size
+ /// \return
+ ///
+ virtual size_t writeData(const uint8_t *data, size_t size);
+
+ ///
+ /// \brief readData
+ /// \param data
+ /// \param size
+ /// \return
+ ///
+ virtual size_t readData(uint8_t *data, size_t size);
+
+
+ protected:
+ /// Set internal socket error to that specified error
+ /// @param error type of error
+ void SetSocketError(CSimpleSocket::CSocketError error) {
+ m_socketErrno = error;
+ };
+
+ /// Set object socket handle to that specified as parameter
+ /// @param socket value of socket descriptor
+ void SetSocketHandle(SOCKET socket) {
+ m_socket = socket;
+ };
+
+ /// Flush the socket descriptor owned by the object.
+ /// @return true data was successfully sent, else return false;
+ bool Flush();
+
+ private:
+ /// Generic function used to get the send/receive window size
+ /// @return zero on failure else the number of bytes of the TCP window size if successful.
+ uint32_t GetWindowSize(uint32_t nOptionName);
+
+ /// Generic function used to set the send/receive window size
+ /// @return zero on failure else the number of bytes of the TCP window size if successful.
+ uint32_t SetWindowSize(uint32_t nOptionName, uint32_t nWindowSize);
+
+
+ /// Attempts to send at most nNumItem blocks described by sendVector
+ /// to the socket descriptor associated with the socket object.
+ /// @param sendVector pointer to an array of iovec structures
+ /// @param nNumItems number of items in the vector to process
+ ///
\b Note: This implementation is for systems that don't natively
+ /// support this functionality.
+ /// @return number of bytes actually sent, return of zero means the
+ /// connection has been shutdown on the other side, and a return of -1
+ /// means that an error has occurred.
+ int32_t Writev(const struct iovec *pVector, size_t nCount);
+
+
+
+ CSimpleSocket *operator=(CSimpleSocket &socket);
+
+ protected:
+ SOCKET m_socket; /// socket handle
+ CSocketError m_socketErrno; /// number of last error
+ uint8_t *m_pBuffer; /// internal send/receive buffer
+ int32_t
+ m_nBufferSize; /// size of internal send/receive buffer
+ int32_t m_nSocketDomain; /// socket type PF_INET, PF_INET6
+ CSocketType m_nSocketType; /// socket type - UDP, TCP or RAW
+ int32_t m_nBytesReceived; /// number of bytes received
+ int32_t m_nBytesSent; /// number of bytes sent
+ uint32_t m_nFlags; /// socket flags
+ bool m_bIsBlocking; /// is socket blocking
+ bool m_bIsMulticast; /// is the UDP socket multicast;
+ struct timeval m_stConnectTimeout; /// connection timeout
+ struct timeval m_stRecvTimeout; /// receive timeout
+ struct timeval m_stSendTimeout; /// send timeout
+ struct sockaddr_in m_stServerSockaddr; /// server address
+ struct sockaddr_in m_stClientSockaddr; /// client address
+ struct sockaddr_in m_stMulticastGroup; /// multicast group to bind to
+ struct linger m_stLinger; /// linger flag
+ CStatTimer m_timer; /// internal statistics.
+#if defined(_WIN32)
+ WSADATA m_hWSAData; /// Windows
+#endif
+ fd_set m_writeFds; /// write file descriptor set
+ fd_set m_readFds; /// read file descriptor set
+ fd_set m_errorFds; /// error file descriptor set
+
+ std::string m_addr;
+ uint32_t m_port;
+ bool m_open;
+};
+
+}//namespace socket
+}//namespace core
+}//namespace ydlidar
+
+
+#endif /* __SOCKET_H__ */
+
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/network/StatTimer.h b/src/spark_driver/lidar/YDLidar-SDK/core/network/StatTimer.h
new file mode 100644
index 0000000..a4a5527
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/network/StatTimer.h
@@ -0,0 +1,150 @@
+/*----------------------------------------------------------------------------*/
+/* */
+/* StatTimer.h: interface for the CStatTimer class. */
+/* */
+/* Author: Mark Carrier (mark@carrierlabs.com) */
+/* */
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2006 CarrierLabs, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 4. The name "CarrierLabs" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * mark@carrierlabs.com.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *----------------------------------------------------------------------------*/
+#ifndef __CSTATTIMER_H__
+#define __CSTATTIMER_H__
+
+#include
+
+#if defined(_WIN32)
+#include
+#include
+#else
+#include
+#include
+#endif
+
+
+#if defined(_WIN32)
+#if !defined (_WINSOCK2API_) && !defined(_WINSOCKAPI_)
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif
+
+inline static int gettimeofday(struct timeval *tv, void *tz) {
+ union {
+ long long ns100;
+ FILETIME t;
+ } now;
+ GetSystemTimeAsFileTime(&now.t);
+ tv->tv_usec = long((now.ns100 / 10LL) % 1000000LL);
+ tv->tv_sec = long((now.ns100 - 116444736000000000LL) / 10000000LL);
+ return 0;
+}
+#undef HAS_CLOCK_GETTIME
+
+#endif
+
+
+#define GET_CLOCK_COUNT(x) gettimeofday(x, NULL)
+
+#include
+
+
+/// Class to abstract socket communications in a cross platform manner.
+/// This class is designed
+class CStatTimer {
+ public:
+ CStatTimer() {
+ memset(&m_startTime, 0, sizeof(struct timeval));
+ memset(&m_endTime, 0, sizeof(struct timeval));
+ };
+
+ ~CStatTimer() {
+ };
+
+ void Initialize() {
+ memset(&m_startTime, 0, sizeof(struct timeval));
+ memset(&m_endTime, 0, sizeof(struct timeval));
+ };
+
+ struct timeval GetStartTime() {
+ return m_startTime;
+ };
+ void SetStartTime() {
+ GET_CLOCK_COUNT(&m_startTime);
+ };
+
+ struct timeval GetEndTime() {
+ return m_endTime;
+ };
+ void SetEndTime() {
+ GET_CLOCK_COUNT(&m_endTime);
+ };
+
+ uint32_t GetMilliSeconds() {
+ return (CalcTotalUSec() / MILLISECONDS_CONVERSION);
+ };
+ uint64_t GetMicroSeconds() {
+ return (CalcTotalUSec());
+ };
+ uint32_t GetSeconds() {
+ return (CalcTotalUSec() / MICROSECONDS_CONVERSION);
+ };
+
+ static uint64_t GetCurrentTime() {
+#if HAS_CLOCK_GETTIME
+ struct timespec tim;
+ clock_gettime(CLOCK_REALTIME, &tim);
+ return (uint64_t)(tim.tv_sec * 1000000000LL + tim.tv_nsec);
+#else
+ struct timeval timeofday;
+ gettimeofday(&timeofday, NULL);
+ return (uint64_t)(timeofday.tv_sec * 1000000000LL + timeofday.tv_usec * 1000);
+#endif
+ };
+
+ private:
+ uint32_t CalcTotalUSec() {
+ return (((m_endTime.tv_sec - m_startTime.tv_sec) * MICROSECONDS_CONVERSION) +
+ (m_endTime.tv_usec - m_startTime.tv_usec));
+ };
+
+
+ private:
+ struct timeval m_startTime;
+ struct timeval m_endTime;
+};
+
+#endif // __CSTATTIMER_H__
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/CMakeLists.txt b/src/spark_driver/lidar/YDLidar-SDK/core/serial/CMakeLists.txt
new file mode 100644
index 0000000..023cc81
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/CMakeLists.txt
@@ -0,0 +1,10 @@
+aux_include_directory(. HDRS)
+aux_src_directory(. SRCS)
+add_to_ydlidar_headers(${HDRS})
+add_to_ydlidar_sources(${SRCS})
+
+subdirlist(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR})
+foreach(subdir ${SUBDIRS})
+ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/${subdir} )
+ add_subdirectory(${subdir})
+endforeach()
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/common.h b/src/spark_driver/lidar/YDLidar-SDK/core/serial/common.h
new file mode 100644
index 0000000..9a4b1c4
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/common.h
@@ -0,0 +1,48 @@
+/*********************************************************************
+* Software License Agreement (BSD License)
+*
+* Copyright (c) 2018, EAIBOT, Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of the Willow Garage nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*********************************************************************/
+#pragma once
+
+#if defined(_WIN32)
+#include "impl\windows\win.h"
+#include "impl\windows\win_serial.h"
+#elif defined(__GNUC__)
+#include "impl/unix/unix.h"
+#include "impl/unix/unix_serial.h"
+#else
+#error "unsupported target"
+#endif
+#include
+#include
+#include
+
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/CMakeLists.txt b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/CMakeLists.txt
new file mode 100644
index 0000000..cae8ed3
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/CMakeLists.txt
@@ -0,0 +1,8 @@
+IF (WIN32)
+add_subdirectory(windows)
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/windows)
+ELSE()
+add_subdirectory(unix)
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/unix)
+ENDIF()
+
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/CMakeLists.txt b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/CMakeLists.txt
new file mode 100644
index 0000000..a224b85
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/CMakeLists.txt
@@ -0,0 +1,4 @@
+aux_include_directory(. HDRS)
+aux_src_directory(. SRCS)
+add_to_ydlidar_headers(${HDRS})
+add_to_ydlidar_sources(${SRCS})
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/list_ports_linux.cpp b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/list_ports_linux.cpp
new file mode 100644
index 0000000..ce571d2
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/list_ports_linux.cpp
@@ -0,0 +1,332 @@
+#if defined(__linux__)
+
+/*
+ * Copyright (c) 2014 Craig Lilley
+ * This software is made available under the terms of the MIT licence.
+ * A copy of the licence can be obtained from:
+ * http://opensource.org/licenses/MIT
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+using namespace ydlidar::core;
+using ydlidar::core::serial::PortInfo;
+using std::istringstream;
+using std::ifstream;
+using std::getline;
+using std::vector;
+using std::string;
+using std::cout;
+using std::endl;
+
+static vector glob(const vector &patterns);
+static string basename(const string &path);
+static string dirname(const string &path);
+static bool path_exists(const string &path);
+static string realpath(const string &path);
+static string usb_sysfs_friendly_name(const string &sys_usb_path,
+ string &device_id);
+static vector get_sysfs_info(const string &device_path);
+static string read_line(const string &file);
+static string usb_sysfs_hw_string(const string &sysfs_path);
+static string format(const char *format, ...);
+
+vector
+glob(const vector &patterns) {
+ vector paths_found;
+
+ if (patterns.size() == 0) {
+ return paths_found;
+ }
+
+ glob_t glob_results;
+
+ int glob_retval = glob(patterns[0].c_str(), 0, NULL, &glob_results);
+
+ vector::const_iterator iter = patterns.begin();
+
+ while (++iter != patterns.end()) {
+ glob_retval = glob(iter->c_str(), GLOB_APPEND, NULL, &glob_results);
+ }
+
+ for (size_t path_index = 0; path_index < glob_results.gl_pathc; path_index++) {
+ paths_found.push_back(glob_results.gl_pathv[path_index]);
+ }
+
+ globfree(&glob_results);
+
+ return paths_found;
+}
+
+string
+basename(const string &path) {
+ size_t pos = path.rfind("/");
+
+ if (pos == std::string::npos) {
+ return path;
+ }
+
+ return string(path, pos + 1, string::npos);
+}
+
+string
+dirname(const string &path) {
+ size_t pos = path.rfind("/");
+
+ if (pos == std::string::npos) {
+ return path;
+ } else if (pos == 0) {
+ return "/";
+ }
+
+ return string(path, 0, pos);
+}
+
+bool
+path_exists(const string &path) {
+ struct stat sb;
+
+ if (stat(path.c_str(), &sb) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+string
+realpath(const string &path) {
+ char *real_path = realpath(path.c_str(), NULL);
+
+ string result;
+
+ if (real_path != NULL) {
+ result = real_path;
+
+ free(real_path);
+ }
+
+ return result;
+}
+
+string
+usb_sysfs_friendly_name(const string &sys_usb_path, string &device_id) {
+ unsigned int device_number = 0;
+
+ istringstream(read_line(sys_usb_path + "/devnum")) >> device_number;
+
+ string manufacturer = read_line(sys_usb_path + "/manufacturer");
+
+ string product = read_line(sys_usb_path + "/product");
+
+ string serial = read_line(sys_usb_path + "/serial");
+
+ device_id = read_line(sys_usb_path + "/devpath");
+
+ if (manufacturer.empty() && product.empty() && serial.empty()) {
+ return "";
+ }
+
+ return format("%s %s %s", manufacturer.c_str(), product.c_str(),
+ serial.c_str());
+}
+
+vector
+get_sysfs_info(const string &device_path) {
+ string device_name = basename(device_path);
+
+ string friendly_name;
+
+ string hardware_id;
+
+ string device_id;
+
+ string sys_device_path = format("/sys/class/tty/%s/device",
+ device_name.c_str());
+
+ if (device_name.compare(0, 6, "ttyUSB") == 0) {
+ sys_device_path = dirname(dirname(realpath(sys_device_path)));
+
+ if (path_exists(sys_device_path)) {
+ friendly_name = usb_sysfs_friendly_name(sys_device_path, device_id);
+
+ hardware_id = usb_sysfs_hw_string(sys_device_path);
+ }
+ } else if (device_name.compare(0, 6, "ttyACM") == 0) {
+ sys_device_path = dirname(realpath(sys_device_path));
+
+ if (path_exists(sys_device_path)) {
+ friendly_name = usb_sysfs_friendly_name(sys_device_path, device_id);
+
+ hardware_id = usb_sysfs_hw_string(sys_device_path);
+ }
+ } else {
+ // Try to read ID string of PCI device
+
+ string sys_id_path = sys_device_path + "/id";
+
+ if (path_exists(sys_id_path)) {
+ hardware_id = read_line(sys_id_path);
+ }
+ }
+
+ if (friendly_name.empty()) {
+ friendly_name = device_name;
+ }
+
+ if (hardware_id.empty()) {
+ hardware_id = "n/a";
+ }
+
+ vector result;
+ result.push_back(friendly_name);
+ result.push_back(hardware_id);
+ result.push_back(device_id);
+
+ return result;
+}
+
+string
+read_line(const string &file) {
+ ifstream ifs(file.c_str(), ifstream::in);
+
+ string line;
+
+ if (ifs) {
+ getline(ifs, line);
+ }
+
+ return line;
+}
+
+string
+format(const char *format, ...) {
+ va_list ap;
+
+ size_t buffer_size_bytes = 256;
+
+ string result;
+
+ char *buffer = (char *)malloc(buffer_size_bytes);
+
+ if (buffer == NULL) {
+ return result;
+ }
+
+ bool done = false;
+
+ unsigned int loop_count = 0;
+
+ while (!done) {
+ va_start(ap, format);
+
+ int return_value = vsnprintf(buffer, buffer_size_bytes, format, ap);
+
+ if (return_value < 0) {
+ done = true;
+ } else if (return_value >= (int)buffer_size_bytes) {
+ // Realloc and try again.
+
+ buffer_size_bytes = return_value + 1;
+
+ char *new_buffer_ptr = (char *)realloc(buffer, buffer_size_bytes);
+
+ if (new_buffer_ptr == NULL) {
+ done = true;
+ } else {
+ buffer = new_buffer_ptr;
+ }
+ } else {
+ result = buffer;
+ done = true;
+ }
+
+ va_end(ap);
+
+ if (++loop_count > 5) {
+ done = true;
+ }
+ }
+
+ free(buffer);
+
+ return result;
+}
+
+string
+usb_sysfs_hw_string(const string &sysfs_path) {
+ string serial_number = read_line(sysfs_path + "/serial");
+
+ if (serial_number.length() > 0) {
+ serial_number = format("SNR=%s", serial_number.c_str());
+ }
+
+ string vid = read_line(sysfs_path + "/idVendor");
+
+ string pid = read_line(sysfs_path + "/idProduct");
+
+ return format("USB VID:PID=%s:%s %s", vid.c_str(), pid.c_str(),
+ serial_number.c_str());
+}
+
+vector
+serial::list_ports() {
+ vector results;
+
+ vector search_globs;
+ search_globs.push_back("/dev/ttyACM*");
+ search_globs.push_back("/dev/ttyS*");
+ search_globs.push_back("/dev/ttyUSB*");
+ search_globs.push_back("/dev/tty.*");
+ search_globs.push_back("/dev/cu.*");
+
+ vector devices_found = glob(search_globs);
+
+ vector::iterator iter = devices_found.begin();
+
+ while (iter != devices_found.end()) {
+ string device = *iter++;
+
+ vector sysfs_info = get_sysfs_info(device);
+
+ string friendly_name = sysfs_info[0];
+
+ string hardware_id = sysfs_info[1];
+
+ string device_id = sysfs_info[2];
+
+ std::size_t found = hardware_id.find("10c4:ea60");
+ std::size_t found1 = hardware_id.find("0483:5740");
+
+
+ if (found != std::string::npos || found1 != std::string::npos) {
+ PortInfo device_entry;
+ device_entry.port = device;
+ device_entry.description = friendly_name;
+ device_entry.hardware_id = hardware_id;
+ device_entry.device_id = device_id;
+ results.push_back(device_entry);
+ }
+
+
+
+ }
+
+ return results;
+}
+
+#endif // defined(__linux__)
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/lock.c b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/lock.c
new file mode 100644
index 0000000..87f4891
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/lock.c
@@ -0,0 +1,796 @@
+/*
+ * lock.c
+ *
+ * Created on: 28 Mar 2018
+ * Author: Tony
+ * E-Mail: Tony@gmail.com
+ */
+#include "lock.h"
+
+#ifndef WIN32
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef LFS
+/*----------------------------------------------------------
+ lfs_lock
+ accept: The name of the device to try to lock
+ perform: Create a lock file if there is not one already using a
+ lock file server.
+ return: 1 on failure 0 on success
+ exceptions: none
+ comments:
+----------------------------------------------------------*/
+int lfs_lock(const char *filename, int pid) {
+ int s;
+ int ret;
+ int size = 1024;
+ char *buffer = malloc(size);
+ struct sockaddr_in addr;
+
+ if (!(s = socket(AF_INET, SOCK_STREAM, 0)) > 0) {
+ free(buffer);
+ return 1;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(50001);
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (!connect(s, (struct sockaddr *) &addr, sizeof(addr)) == 0) {
+ free(buffer);
+ return 1;
+ }
+
+ ret = recv(s, buffer, size, 0);
+ sprintf(buffer, "lock %s %i\n", filename, pid);
+ /* printf( "%s", buffer ); */
+ send(s, buffer, strlen(buffer), 0);
+ ret = recv(s, buffer, size, 0);
+
+ if (ret > 0) {
+ buffer[ret] = '\0';
+ /* printf( "Message recieved: %s", buffer ); */
+ }
+
+ send(s, "quit\n", strlen("quit\n"), 0);
+ close(s);
+
+ /* printf("%s\n", buffer); */
+ if (buffer[0] == '2') {
+ return 0;
+ }
+
+ free(buffer);
+ return 1;
+}
+
+/*----------------------------------------------------------
+ lfs_unlock
+ accept: The name of the device to try to unlock
+ perform: Remove a lock file if there is one using a
+ lock file server.
+ return: 1 on failure 0 on success
+ exceptions: none
+ comments:
+----------------------------------------------------------*/
+int lfs_unlock(const char *filename, int pid) {
+ int s;
+ int ret;
+ int size = 1024;
+ char *buffer = malloc(size);
+ struct sockaddr_in addr;
+
+ if (!(s = socket(AF_INET, SOCK_STREAM, 0)) > 0) {
+ free(buffer);
+ return 1;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(50001);
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (!connect(s, (struct sockaddr *) &addr, sizeof(addr)) == 0) {
+ free(buffer);
+ return 1;
+ }
+
+ sprintf(buffer, "unlock %s %i\n", filename, pid);
+ /* printf( "%s", buffer ); */
+ send(s, buffer, strlen(buffer), 0);
+ ret = recv(s, buffer, size, 0);
+
+ if (ret > 0) {
+ buffer[ret] = '\0';
+ /* printf( "Message recieved: %s", buffer ); */
+ }
+
+ send(s, "quit\n", strlen("quit\n"), 0);
+ close(s);
+
+ if (buffer[0] == '2') {
+ return 0;
+ }
+
+ free(buffer);
+ return 1;
+}
+#endif /* LFS */
+
+/*----------------------------------------------------------
+ lib_lock_dev_unlock
+ accept: The name of the device to try to unlock
+ perform: Remove a lock file if there is one using a
+ lock file server.
+ return: 1 on failure 0 on success
+ exceptions: none
+ comments: This is for use with liblockdev which comes with Linux
+ distros. I suspect it will be problematic with embeded
+ Linux. taj
+----------------------------------------------------------*/
+#ifdef LIBLOCKDEV
+int lib_lock_dev_unlock(const char *filename, int pid) {
+ if (dev_unlock(filename, pid)) {
+ //report("fhs_unlock: Unable to remove LockFile\n");
+ return (1);
+ }
+
+ return (0);
+}
+#endif /* LIBLOCKDEV */
+
+/*----------------------------------------------------------
+ lib_lock_dev_lock
+ accept: The name of the device to try to lock
+ termios struct
+ perform: Create a lock file if there is not one already.
+ return: 1 on failure 0 on success
+ exceptions: none
+ comments: This is for use with liblockdev which comes with Linux
+ distros. I suspect it will be problematic with embeded
+ Linux. taj
+ One could load the library here rather than link it and
+ always try to use this.
+----------------------------------------------------------*/
+#ifdef LIBLOCKDEV
+int lib_lock_dev_lock(const char *filename, int pid) {
+ char message[80];
+ printf("LOCKING %s\n", filename);
+
+ if (dev_testlock(filename)) {
+ //report( "fhs_lock() lockstatus fail\n" );
+ return 1;
+ }
+
+ if (dev_lock(filename)) {
+ sprintf(message,
+ "RXTX fhs_lock() Error: creating lock file for: %s: %s\n",
+ filename, strerror(errno));
+ // report_error( message );
+ return 1;
+ }
+
+ return (0);
+}
+#endif /* LIBLOCKDEV */
+
+/*----------------------------------------------------------
+ fhs_lock
+ accept: The name of the device to try to lock
+ termios struct
+ perform: Create a lock file if there is not one already.
+ return: 1 on failure 0 on success
+ exceptions: none
+ comments: This is for linux and freebsd only currently. I see SVR4 does
+ this differently and there are other proposed changes to the
+ Filesystem Hierachy Standard
+ more reading:
+----------------------------------------------------------*/
+int fhs_lock(const char *filename, int pid) {
+ /*
+ * There is a zoo of lockdir possibilities
+ * Its possible to check for stale processes with most of them.
+ * for now we will just check for the lockfile on most
+ * Problem lockfiles will be dealt with. Some may not even be in use.
+ *
+ */
+ int fd, j;
+ char lockinfo[12];
+ char file[80], *p;
+
+ j = strlen(filename);
+ p = (char *) filename + j;
+
+ /* FIXME need to handle subdirectories /dev/cua/...
+ SCO Unix use lowercase all the time
+ taj
+ */
+ while (*(p - 1) != '/' && j-- != 1) {
+#if defined ( __unixware__ )
+ *p = tolower(*p);
+#endif /* __unixware__ */
+ p--;
+ }
+
+ sprintf(file, "%s/LCK..%s", LOCKDIR, p);
+
+ if (check_lock_status(filename)) {
+ printf("fhs_lock() lockstatus fail\n");
+ return 1;
+ }
+
+ fd = open(file, O_CREAT | O_WRONLY | O_EXCL, 0444);
+
+ if (fd < 0) {
+ printf(
+ "RXTX fhs_lock() Error: creating lock file: %s: %s\n",
+ file, strerror(errno));
+ return 1;
+ }
+
+ sprintf(lockinfo, "%10d\n", (int) getpid());
+ printf("fhs_lock: creating lockfile: %s\n", lockinfo);
+ write(fd, lockinfo, 11);
+ close(fd);
+ return 0;
+}
+
+/*----------------------------------------------------------
+ uucp_lock
+ accept: char * filename. Device to be locked
+ perform: Try to get a uucp_lock
+ return: int 0 on success
+ exceptions: none
+ comments:
+ The File System Hierarchy Standard
+ http://www.pathname.com/fhs/
+ UUCP Lock Files
+ http://docs.freebsd.org/info/uucp/uucp.info.UUCP_Lock_Files.html
+ FSSTND
+ ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/
+ Proposed Changes to the File System Hierarchy Standard
+ ftp://scicom.alphacdc.com/pub/linux/devlock-0.X.tgz
+ "UNIX Network Programming", W. Richard Stevens,
+ Prentice-Hall, 1990, pages 96-101.
+ There is much to do here.
+ 1) UUCP style locks (done)
+ /var/spool/uucp
+ 2) SVR4 locks
+ /var/spool/locks
+ 3) FSSTND locks (done)
+ /var/lock
+ 4) handle stale locks (done except kermit locks)
+ 5) handle minicom lockfile contents (FSSTND?)
+ " 16929 minicom root\n" (done)
+ 6) there are other Lock conventions that use Major and Minor
+ numbers...
+ 7) Stevens recommends LCK..
+ most are caught above. If they turn out to be problematic
+ rather than an exercise, we will handle them.
+----------------------------------------------------------*/
+int uucp_lock(const char *filename, int pid) {
+ char lockfilename[80], lockinfo[12];
+ char name[80];
+ int fd;
+ struct stat buf;
+
+ printf("uucp_lock( %s );\n", filename);
+
+ if (check_lock_status(filename)) {
+ printf("RXTX uucp check_lock_status true\n");
+ return 1;
+ }
+
+ if (stat(LOCKDIR, &buf) != 0) {
+ printf("RXTX uucp_lock() could not find lock directory.\n");
+ return 1;
+ }
+
+ if (stat(filename, &buf) != 0) {
+ printf("RXTX uucp_lock() could not find device.\n");
+ printf("uucp_lock: device was %s\n", name);
+ return 1;
+ }
+
+ sprintf(lockfilename, "%s/LK.%03d.%03d.%03d",
+ LOCKDIR,
+ (int) major(buf.st_dev),
+ (int) major(buf.st_rdev),
+ (int) minor(buf.st_rdev)
+ );
+ sprintf(lockinfo, "%10d\n", (int) getpid());
+
+ if (stat(lockfilename, &buf) == 0) {
+ printf("RXTX uucp_lock() %s is there\n",
+ lockfilename);
+ return 1;
+ }
+
+ fd = open(lockfilename, O_CREAT | O_WRONLY | O_EXCL, 0444);
+
+ if (fd < 0) {
+ printf(
+ "RXTX uucp_lock() Error: creating lock file: %s\n",
+ lockfilename);
+ return 1;
+ }
+
+ write(fd, lockinfo, 11);
+ close(fd);
+ return 0;
+}
+
+/*----------------------------------------------------------
+ check_lock_status
+ accept: the lock name in question
+ perform: Make sure everything is sane
+ return: 0 on success
+ exceptions: none
+ comments:
+----------------------------------------------------------*/
+int check_lock_status(const char *filename) {
+ struct stat buf;
+ /* First, can we find the directory? */
+
+ if (stat(LOCKDIR, &buf) != 0) {
+ printf("check_lock_status: could not find lock directory.\n");
+ return 1;
+ }
+
+ /* OK. Are we able to write to it? If not lets bail */
+
+ if (check_group_uucp()) {
+ printf("check_lock_status: No permission to create lock file.\nplease see: How can I use Lock Files with rxtx? in INSTALL\n");
+ return (1);
+ }
+
+ /* is the device alread locked */
+
+ if (is_device_locked(filename)) {
+ printf("check_lock_status: device is locked by another application\n");
+ return 1;
+ }
+
+ return 0;
+
+}
+
+/*----------------------------------------------------------
+ fhs_unlock
+ accept: The name of the device to unlock
+ perform: delete the lock file
+ return: none
+ exceptions: none
+ comments: This is for linux only currently. I see SVR4 does this
+ differently and there are other proposed changes to the
+ Filesystem Hierachy Standard
+----------------------------------------------------------*/
+void fhs_unlock(const char *filename, int openpid) {
+ char file[80], *p;
+ int i;
+
+ i = strlen(filename);
+ p = (char *) filename + i;
+
+ /* FIXME need to handle subdirectories /dev/cua/... */
+ while (*(p - 1) != '/' && i-- != 1) {
+ p--;
+ }
+
+ sprintf(file, "%s/LCK..%s", LOCKDIR, p);
+
+ if (!check_lock_pid(file, openpid)) {
+ unlink(file);
+ printf("fhs_unlock: Removing LockFile\n");
+ } else {
+ printf("fhs_unlock: Unable to remove LockFile\n");
+ }
+}
+
+/*----------------------------------------------------------
+ uucp_unlock
+ accept: char *filename the device that is locked
+ perform: remove the uucp lockfile if it exists
+ return: none
+ exceptions: none
+ comments: http://docs.freebsd.org/info/uucp/uucp.info.UUCP_Lock_Files.html
+----------------------------------------------------------*/
+void uucp_unlock(const char *filename, int openpid) {
+ struct stat buf;
+ char file[80];
+ /* FIXME */
+
+ printf("uucp_unlock( %s );\n", filename);
+
+ if (stat(filename, &buf) != 0) {
+ /* hmm the file is not there? */
+ printf("uucp_unlock() no such device\n");
+ return;
+ }
+
+ sprintf(file, LOCKDIR"/LK.%03d.%03d.%03d",
+ (int) major(buf.st_dev),
+ (int) major(buf.st_rdev),
+ (int) minor(buf.st_rdev)
+ );
+
+ if (stat(file, &buf) != 0) {
+ /* hmm the file is not there? */
+ printf("uucp_unlock no such lockfile\n");
+ return;
+ }
+
+ if (!check_lock_pid(file, openpid)) {
+ printf("uucp_unlock: unlinking %s\n", file);
+ unlink(file);
+ } else {
+ printf("uucp_unlock: unlinking failed %s\n", file);
+ }
+}
+
+/*----------------------------------------------------------
+ check_lock_pid
+ accept: the name of the lockfile
+ perform: make sure the lock file is ours.
+ return: 0 on success
+ exceptions: none
+ comments:
+----------------------------------------------------------*/
+int check_lock_pid(const char *file, int openpid) {
+ int fd, lockpid;
+ char pid_buffer[12];
+
+ fd = open(file, O_RDONLY);
+
+ if (fd < 0) {
+ return (1);
+ }
+
+ if (read(fd, pid_buffer, 11) < 0) {
+ close(fd);
+ return (1);
+ }
+
+ close(fd);
+ pid_buffer[11] = '\0';
+ lockpid = atol(pid_buffer);
+
+ /* Native threads JVM's have multiple pids */
+ if (lockpid != getpid() && lockpid != getppid() && lockpid != openpid) {
+ printf("check_lock_pid: lock = %s pid = %i gpid=%i openpid=%i\n",
+ pid_buffer, (int) getpid(), (int) getppid(), openpid);
+ return (1);
+ }
+
+ return (0);
+}
+
+/*----------------------------------------------------------
+ check_group_uucp
+ accept: none
+ perform: check if the user is root or in group uucp
+ return: 0 on success
+ exceptions: none
+ comments:
+ This checks if the effective user is in group uucp so we can
+ create lock files. If not we give them a warning and bail.
+ If its root we just skip the test.
+ if someone really wants to override this they can use the USER_LOCK_DIRECTORY --not recommended.
+ In a recent change RedHat 7.2 decided to use group lock.
+ In order to get around this we just check the group id
+ of the lock directory.
+ * Modified to support Debian *
+ The problem was that checking the ownership of the lock file
+ dir is not enough, in the sense that even if the current user
+ is not in the group of the lock directory if the lock
+ directory has 777 permissions the lock file can be anyway
+ created. My solution is simply to try to create a tmp file
+ there and if it works then we can go on. Here is my code that
+ I tried and seems to work.
+ Villa Valerio
+----------------------------------------------------------*/
+int check_group_uucp() {
+
+#ifndef USER_LOCK_DIRECTORY
+ FILE *testLockFile ;
+ char testLockFileDirName[] = LOCKDIR;
+ char testLockFileName[] = "tmpXXXXXX";
+ char *testLockAbsFileName;
+
+ testLockAbsFileName = calloc(strlen(testLockFileDirName)
+ + strlen(testLockFileName) + 2, sizeof(char));
+
+ if (NULL == testLockAbsFileName) {
+ printf("check_group_uucp(): Insufficient memory");
+ return 1;
+ }
+
+ strcat(testLockAbsFileName, testLockFileDirName);
+ strcat(testLockAbsFileName, "/");
+ strcat(testLockAbsFileName, testLockFileName);
+
+ if (-1 == mkstemp(testLockAbsFileName)) {
+ free(testLockAbsFileName);
+ printf("check_group_uucp(): mktemp malformed string - \
+ should not happen");
+
+ return 1;
+ }
+
+ testLockFile = fopen(testLockAbsFileName, "w+");
+
+ if (NULL == testLockFile) {
+ printf("check_group_uucp(): error testing lock file "
+ "creation Error details:");
+ printf("%s\n", strerror(errno));
+ free(testLockAbsFileName);
+ return 1;
+ }
+
+ fclose(testLockFile);
+ unlink(testLockAbsFileName);
+ free(testLockAbsFileName);
+
+#endif /* USER_LOCK_DIRECTORY */
+ return 0;
+}
+
+#ifdef USE_OLD_CHECK_GROUP_UUCP
+int check_group_uucp() {
+#ifndef USER_LOCK_DIRECTORY
+ int group_count;
+ struct passwd *user = getpwuid(geteuid());
+ struct stat buf;
+ char msg[80];
+ gid_t list[ NGROUPS_MAX ];
+
+ if (stat(LOCKDIR, &buf)) {
+ sprintf(msg, "check_group_uucp: Can not find Lock Directory: %s\n", LOCKDIR);
+ printf(msg);
+ return (1);
+ }
+
+ group_count = getgroups(NGROUPS_MAX, list);
+ list[ group_count ] = geteuid();
+
+ /* JJO changes start */
+ if (user == NULL) {
+ printf("Not able to get user groups.\n");
+ return 1;
+ } else
+
+ /* JJO changes stop */
+
+
+ if (user->pw_gid) {
+ while (group_count >= 0 && buf.st_gid != list[ group_count ]) {
+ group_count--;
+ }
+
+ if (buf.st_gid == list[ group_count ]) {
+ return 0;
+ }
+
+ sprintf(msg, "%i %i\n", buf.st_gid, list[ group_count ]);
+ printf(msg);
+ printf(UUCP_ERROR);
+ return 1;
+ }
+
+ return 0;
+ /*
+ if( strcmp( user->pw_name, "root" ) )
+ {
+ while( *g->gr_mem )
+ {
+ if( !strcmp( *g->gr_mem, user->pw_name ) )
+ {
+ break;
+ }
+ (void) *g->gr_mem++;
+ }
+ if( !*g->gr_mem )
+ {
+ printf( UUCP_ERROR );
+ return 1;
+ }
+ }
+ */
+#endif /* USER_LOCK_DIRECTORY */
+ return 0;
+}
+#endif /* USE_OLD_CHECK_GROUP_UUCP */
+
+
+/*----------------------------------------------------------
+ The following should be able to follow symbolic links. I think the stat
+ method used below will work on more systems. This was found while looking
+ for information.
+ * realpath() doesn't exist on all of the systems my code has to run
+ on (HP-UX 9.x, specifically)
+----------------------------------------------------------
+int different_from_LOCKDIR(const char* ld)
+{
+ char real_ld[MAXPATHLEN];
+ char real_LOCKDIR[MAXPATHLEN];
+ if (strncmp(ld, LOCKDIR, strlen(ld)) == 0)
+ return 0;
+ if (realpath(ld, real_ld) == NULL)
+ return 1;
+ if (realpath(LOCKDIR, real_LOCKDIR) == NULL)
+ return 1;
+ if (strncmp(real_ld, real_LOCKDIR, strlen(real_ld)) == 0)
+ return 0;
+ else
+ return 1;
+}
+*/
+
+/*----------------------------------------------------------
+ is_device_locked
+ accept: char * filename. The device in question including the path.
+ perform: see if one of the many possible lock files is aready there
+ if there is a stale lock, remove it.
+ return: 1 if the device is locked or somethings wrong.
+ 0 if its possible to create our own lock file.
+ exceptions: none
+ comments: check if the device is already locked
+----------------------------------------------------------*/
+int is_device_locked(const char *port_filename) {
+ const char *lockdirs[] = { "/etc/locks", "/usr/spool/kermit",
+ "/usr/spool/locks", "/usr/spool/uucp", "/usr/spool/uucp/",
+ "/usr/spool/uucp/LCK", "/var/lock", "/var/lock/modem",
+ "/var/spool/lock", "/var/spool/locks", "/var/spool/uucp",
+ LOCKDIR, NULL
+ };
+ const char *lockprefixes[] = { "LCK..", "lk..", "LK.", NULL };
+ char *p, file[80], pid_buffer[20];
+ int i = 0, j, k, fd, pid;
+ struct stat buf, buf2, lockbuf;
+
+ j = strlen(port_filename);
+ p = (char *) port_filename + j;
+
+ while (*(p - 1) != '/' && j-- != 1) {
+ p--;
+ }
+
+ stat(LOCKDIR, &lockbuf);
+
+ while (lockdirs[i]) {
+ /*
+ Look for lockfiles in all known places other than the
+ defined lock directory for this system
+ report any unexpected lockfiles.
+ Is the suspect lockdir there?
+ if it is there is it not the expected lock dir?
+ */
+ if (!stat(lockdirs[i], &buf2) &&
+ buf2.st_ino != lockbuf.st_ino &&
+ strncmp(lockdirs[i], LOCKDIR, strlen(lockdirs[i]))) {
+ j = strlen(port_filename);
+ p = (char *) port_filename + j;
+
+ /*
+ SCO Unix use lowercase all the time
+ taj
+ */
+ while (*(p - 1) != '/' && j-- != 1) {
+#if defined ( __unixware__ )
+ *p = tolower(*p);
+#endif /* __unixware__ */
+ p--;
+ }
+
+ k = 0;
+
+ while (lockprefixes[k]) {
+ /* FHS style */
+ sprintf(file, "%s/%s%s", lockdirs[i],
+ lockprefixes[k], p);
+
+ if (stat(file, &buf) == 0) {
+// sprintf( message, UNEXPECTED_LOCK_FILE,
+// file );
+// printf( message );
+ return 1;
+ }
+
+ /* UUCP style */
+ stat(port_filename, &buf);
+ sprintf(file, "%s/%s%03d.%03d.%03d",
+ lockdirs[i],
+ lockprefixes[k],
+ (int) major(buf.st_dev),
+ (int) major(buf.st_rdev),
+ (int) minor(buf.st_rdev)
+ );
+
+ if (stat(file, &buf) == 0) {
+// sprintf( message, UNEXPECTED_LOCK_FILE,
+// file );
+// printf( message );
+ return 1;
+ }
+
+ k++;
+ }
+ }
+
+ i++;
+ }
+
+ /*
+ OK. We think there are no unexpect lock files for this device
+ Lets see if there any stale lock files that need to be
+ removed.
+ */
+
+#ifdef FHS
+ /* FHS standard locks */
+ i = strlen(port_filename);
+ p = (char *) port_filename + i;
+
+ while (*(p - 1) != '/' && i-- != 1) {
+#if defined ( __unixware__ )
+ *p = tolower(*p);
+#endif /* __unixware__ */
+ p--;
+ }
+
+ sprintf(file, "%s/%s%s", LOCKDIR, LOCKFILEPREFIX, p);
+#else
+
+ /* UUCP standard locks */
+ if (stat(port_filename, &buf) != 0) {
+ printf("RXTX is_device_locked() could not find device.\n");
+ return 1;
+ }
+
+ sprintf(file, "%s/LK.%03d.%03d.%03d",
+ LOCKDIR,
+ (int) major(buf.st_dev),
+ (int) major(buf.st_rdev),
+ (int) minor(buf.st_rdev)
+ );
+
+#endif /* FHS */
+
+ if (stat(file, &buf) == 0) {
+
+ /* check if its a stale lock */
+ fd = open(file, O_RDONLY);
+ read(fd, pid_buffer, 11);
+ /* FIXME null terminiate pid_buffer? need to check in Solaris */
+ close(fd);
+ sscanf(pid_buffer, "%d", &pid);
+
+ if (kill((pid_t) pid, 0) && errno == ESRCH) {
+ printf(
+ "RXTX Warning: Removing stale lock file. %s\n",
+ file);
+
+ if (unlink(file) != 0) {
+ printf("RXTX Error: Unable to \
+ remove stale lock file: %s\n",
+ file
+ );
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* WIN32 */
+
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/lock.h b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/lock.h
new file mode 100644
index 0000000..e844149
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/lock.h
@@ -0,0 +1,241 @@
+/*
+ * lock.h
+ *
+ * Created on: 28 Mar 2018
+ * Author: Tony
+ * E-Mail: Tony@gmail.com
+ */
+
+#ifndef LOCK_H_
+#define LOCK_H_
+
+
+#ifdef HAVE_SYS_FILE_H
+# include
+#endif /* HAVE_SYS_FILE_H */
+#ifdef LFS /* File Lock Server */
+# include
+# include
+# include
+#endif /* FLS */
+#if defined(__linux__)
+# include /* fix for linux-2.3.4? kernels */
+# include
+# include
+#endif /* __linux__ */
+#if defined(__sun__)
+# include
+# include
+#endif /* __sun__ */
+#if defined(__hpux__)
+# include
+#endif /* __hpux__ */
+/* FIXME -- new file */
+#if defined(__APPLE__)
+# include
+# include
+# include
+# include
+#endif /* __APPLE__ */
+#ifdef __unixware__
+# include
+#endif /* __unixware__ */
+#ifdef HAVE_PWD_H
+#include
+#endif /* HAVE_PWD_H */
+#ifdef HAVE_GRP_H
+#include
+#endif /* HAVE_GRP_H */
+#include
+#ifdef LIBLOCKDEV
+#include
+#endif /* LIBLOCKDEV */
+
+
+
+/* Ports known on the OS */
+#if defined(__linux__)
+# define DEVICEDIR "/dev/"
+# define LOCKDIR "/var/lock"
+# define LOCKFILEPREFIX "LCK.."
+# define FHS
+#endif /* __linux__ */
+#if defined(__QNX__)
+# define DEVICEDIR "/dev/"
+# define LOCKDIR ""
+# define LOCKFILEPREFIX ""
+#endif /* qnx */
+#if defined(__sgi__) || defined(sgi)
+# define DEVICEDIR "/dev/"
+# define LOCKDIR "/usr/spool/uucp"
+# define LOCKFILEPREFIX "LK."
+# define UUCP
+#endif /* __sgi__ || sgi */
+#if defined(__FreeBSD__)
+# define DEVICEDIR "/dev/"
+# define LOCKDIR "/var/spool/lock"
+# define LOCKFILEPREFIX "LK.."
+# define UUCP
+#endif /* __FreeBSD__ */
+#if defined(__APPLE__)
+# define DEVICEDIR "/dev/"
+/*# define LOCKDIR "/var/spool/uucp"*/
+# define LOCKDIR "/var/lock"
+# define LOCKFILEPREFIX "LK."
+# define UUCP
+#endif /* __APPLE__ */
+#if defined(__NetBSD__)
+# define DEVICEDIR "/dev/"
+# define LOCKDIR "/var/lock"
+/*# define LOCKDIR "/usr/spool/uucp"*/
+# define LOCKFILEPREFIX "LK."
+# define UUCP
+#endif /* __NetBSD__ */
+#if defined(__unixware__)
+# define DEVICEDIR "/dev/"
+/* really this only fully works for OpenServer */
+# define LOCKDIR "/var/spool/uucp/"
+# define LOCKFILEPREFIX "LK."
+/*
+this needs work....
+Jonathan Schilling writes:
+This is complicated because as I said in my previous mail, there are
+two kinds of SCO operating systems.
+The one that most people want gnu.io for, including the guy who
+asked the mailing list about SCO support a few days ago, is Open Server
+(a/k/a "SCO UNIX"), which is SVR3-based. This uses old-style uucp locks,
+of the form LCK..tty0a. That's what I implemented in the RXTX port I did,
+and it works correctly.
+The other SCO/Caldera OS, UnixWare/Open UNIX, uses the new-style
+SVR4 locks, of the form LK.123.123.123. These OSes are a lot like
+Solaris (UnixWare/Open UNIX come from AT&T SVR4 which had a joint
+The other SCO/Caldera OS, UnixWare/Open UNIX, uses the new-style
+SVR4 locks, of the form LK.123.123.123. These OSes are a lot like
+Solaris (UnixWare/Open UNIX come from AT&T SVR4 which had a joint
+heritage with Sun way back when). I saw that you added support
+for this form of lock by RXTX 1.4-10 ... but it gets messy because,
+as I said before, we use the same binary gnu.io files for both
+UnixWare/Open UNIX and OpenServer. Thus we can't #ifdef one or the
+other; it would have to be a runtime test. Your code and your macros
+aren't set up for doing this (understandably!). So I didn't implement
+these; the gnu.io locks won't fully work on UnixWare/Open UNIX
+as a result, which I mentioned in the Release Notes.
+What I would suggest is that you merge in the old-style LCK..tty0a lock
+code that I used, since this will satisfy 90% of the SCO users. Then
+I'll work on some way of getting UnixWare/Open UNIX locking to work
+correctly, and give you those changes at a later date.
+Jonathan
+FIXME The lock type could be passed with -DOLDUUCP or -DUUCP based on
+os.name in configure.in or perhaps system defines could determine the lock
+type.
+Trent
+*/
+# define OLDUUCP
+#endif
+#if defined(__hpux__)
+/* modif cath */
+# define DEVICEDIR "/dev/"
+# define LOCKDIR "/var/spool/uucp"
+# define LOCKFILEPREFIX "LCK."
+# define UUCP
+#endif /* __hpux__ */
+#if defined(__osf__) /* Digital Unix */
+# define DEVICEDIR "/dev/"
+# define LOCKDIR ""
+# define LOCKFILEPREFIX "LK."
+# define UUCP
+#endif /* __osf__ */
+#if defined(__sun__) /* Solaris */
+# define DEVICEDIR "/dev/"
+# define LOCKDIR "/var/spool/locks"
+# define LOCKFILEPREFIX "LK."
+/*
+# define UUCP
+*/
+#endif /* __sun__ */
+#if defined(__BEOS__)
+# define DEVICEDIR "/dev/ports/"
+# define LOCKDIR ""
+# define LOCKFILEPREFIX ""
+# define UUCP
+#endif /* __BEOS__ */
+#if defined(WIN32)
+# define DEVICEDIR "//./"
+# define LOCKDIR ""
+# define LOCKFILEPREFIX ""
+#endif /* WIN32 */
+
+/* allow people to override the directories */
+/* #define USER_LOCK_DIRECTORY "/home/tjarvi/1.5/build" */
+#ifdef USER_LOCK_DIRECTORY
+# define LOCKDIR USER_LOCK_DIRECTORY
+#endif /* USER_LOCK_DIRECTORY */
+
+#ifdef DISABLE_LOCKFILES
+#undef UUCP
+#undef FHS
+#undef OLDUUCP
+#endif /* DISABLE_LOCKFILES */
+
+/* That should be all you need to look at in this file for porting */
+#ifdef LFS /* Use a Lock File Server */
+# define LOCK lfs_lock
+# define UNLOCK lfs_unlock
+#elif defined(UUCP)
+# define LOCK uucp_lock
+# define UNLOCK uucp_unlock
+#elif defined(OLDUUCP)
+/*
+ We can handle the old style if needed here see __unixware__ above.
+ defaulting to rxtx-1.4-8 behavior for now.
+ see also __sco__ in SerialImp.c when changing this for a possible
+ bug
+ FIXME
+*/
+# define LOCK fhs_lock
+# define UNLOCK fhs_unlock
+#elif defined(FHS)
+#ifdef LIBLOCKDEV
+# define LOCK lib_lock_dev_lock
+# define UNLOCK lib_lock_dev_unlock
+#else
+# define LOCK fhs_lock
+# define UNLOCK fhs_unlock
+#endif /* LIBLOCKDEV */
+#else
+# define LOCK system_does_not_lock
+# define UNLOCK system_does_not_unlock
+#endif /* UUCP */
+
+
+
+//#ifndef __WIN32__
+//#define UUCP_LOCK_DIR "/var/lock"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+//int uucp_lock( const char *file);
+//int uucp_unlock(void);
+int check_group_uucp();
+int check_lock_pid(const char *file, int openpid);
+int lock_device(const char *);
+void unlock_device(const char *);
+int is_device_locked(const char *);
+int check_lock_status(const char *);
+int lfs_unlock(const char *, int);
+int lfs_lock(const char *, int);
+int lib_lock_dev_unlock(const char *, int);
+int lib_lock_dev_lock(const char *, int);
+void fhs_unlock(const char *, int);
+int fhs_lock(const char *, int);
+void uucp_unlock(const char *, int);
+int uucp_lock(const char *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+//#endif
+
+#endif /* LOCK_H_ */
diff --git a/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/unix.h b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/unix.h
new file mode 100644
index 0000000..e78f84d
--- /dev/null
+++ b/src/spark_driver/lidar/YDLidar-SDK/core/serial/impl/unix/unix.h
@@ -0,0 +1,27 @@
+#pragma once
+// libc dep
+#include
+#include
+#include
+#include
+#include
+#include
+#include