Files
swiftrplidar/Sources/SwiftRPLidar/SwiftRPLidar.swift
2020-07-06 12:25:12 +09:30

224 lines
5.4 KiB
Swift

import Foundation
import SwiftSerial
struct Constants{
static let SYNC: UInt8 = 0xA5
static let SYNC2: UInt8 = 0x5A
static let GET_INFO: UInt8 = 0x50
static let GET_HEALTH: UInt8 = 0x52
static let STOP: UInt8 = 0x25
static let RESET: UInt8 = 0x40
static let SCAN: UInt8 = 0x20
static let FORCE_SCAN: UInt8 = 0x21
static let DESCRIPTOR_LEN = 7
static let INFO_LEN = 20
static let HEALTH_LEN = 3
static let INFO_TYPE: UInt8 = 4
static let HEALTH_TYPE: UInt8 = 6
static let SCAN_TYPE: UInt8 = 129
static let SET_PWM_BYTE: UInt8 = 0xF0
static let MAX_MOTOR_PWM = 1023
static let DEFAULT_MOTOR_PWM = 660
}
enum HEALTH_STATUSES {
case GOOD, WARNING, ERROR
}
struct SwiftRPLidar {
var text = "Hello, World!"
}
func processScan(raw: Data) throws -> LidarScan {
let newScan = raw[0] & 0b1
let inversedNewScan = (raw[0] >> 1) & 0b1
let quality = raw[0] >> 2
if (newScan == inversedNewScan){
}
if ((raw[1] & 0b1) != 1) {
}
let angle = (raw[1] >> 1) + (raw[2] << 7) / 64
let distance = raw[3] + (raw[4] << 8) / 4
return LidarScan(newScan: newScan, quality: quality, angle: angle, distance: distance)
}
struct LidarScan{
var newScan: Bool
var quality: Float
var angle: Float
var distance: Float
}
typealias MeasurementHandler = (_ scan: LidarScan) -> Void
typealias ScanHandler = (_ scans: [LidarScan]) -> Void
class RPLidar{
private var motor: Bool = false
private var serialPort: SerialPort? = nil
private var motorRunning = false
init(serialPort: SerialPort) throws {
self.serialPort = serialPort
}
deinit {
if(serialPort != nil){
serialPort?.closePort()
}
}
public func connect() throws {
disconnect()
try serialPort!.openPort()
}
public func disconnect(){
if(serialPort != nil){
// Need to close, SwiftSerial is blocking.
serialPort!.closePort()
}
}
public func startMotor() throws{
// A1
serialPort?.dtr = true
// A2
try self.setPwm(Constants.DEFAULT_MOTOR_PWM)
self.motorRunning = true
}
public func stopMotor() throws{
try setPwm(0)
serialPort?.dtr = false
motorRunning = false
}
public func setPwm(_ pwm: Int) throws{
assert(0 <= pwm && pwm <= Constants.MAX_MOTOR_PWM)
try self.sendPayloadCommand(Constants.SET_PWM_BYTE, payload: pwm.asData())
}
public func getInfo() throws -> (UInt8, UInt8, UInt8, String){
try sendCommand(Data([Constants.GET_HEALTH]))
let (dataSize, isSingle, dataType) = try readDescriptor()!
if (dataSize != Constants.INFO_LEN){
}
if(!isSingle){
}
if(dataType != Constants.INFO_TYPE){
}
let raw = try readResponse(dataSize)
let serialNumber = String(bytes: raw[4...], encoding: .ascii)!
return (raw[0], raw[2], raw[3], serialNumber)
}
public func getHealth(){
}
public func clearInput(){
}
public func stop(){
}
public func reset(){
}
public func iterMeasurements(maxBufferMeasurements: Int = 500, _ onMeasure: MeasurementHandler) {
}
public func iterScans(maxBufferMeasurements: Int = 500, minLength: Int = 5, _ onScan: ScanHandler){
}
private func sendPayloadCommand(_ cmd: Int, payload: Data) throws{
let size = UInt8(payload.count)
var req = Constants.SYNC.asData() + cmd.asData() + size.asData() + payload
let checksum = calcChecksum(req)
req += checksum.asData()
try serialPort?.writeData(req)
}
private func sendPayloadCommand(_ cmd: UInt8, payload: Data) throws {
return try sendPayloadCommand(Int(cmd), payload: payload)
}
private func calcChecksum(_ data: Data) -> Int{
var checksum = 0;
data.forEach{ body in
checksum ^= Int(body)
}
return checksum
}
private func sendCommand(_ command: Data) throws{
var req = Constants.SYNC.asData()
req.append(command)
try serialPort?.writeData(req)
}
private func readDescriptor() throws -> (UInt8, Bool, UInt8)?{
guard let descriptor = try serialPort?.readData(ofLength: Constants.DESCRIPTOR_LEN) else {
return nil
}
if (descriptor.count != Constants.DESCRIPTOR_LEN){
}
else if (descriptor[0...1] != Data([Constants.SYNC, Constants.SYNC2])){
}
let isSingle = descriptor[descriptor.count - 2] == 0
return (descriptor[2], isSingle, descriptor[descriptor.count - 1])
}
private func readResponse(_ dataSize: Int) throws -> Data {
guard let data = try serialPort?.readData(ofLength: dataSize) else{
return Data()
}
if(data.count != dataSize){
}
return data
}
private func readResponse(_ dataSize: UInt8) throws -> Data {
return try readResponse(Int(dataSize))
}
}
extension Int{
func asData() -> Data {
var int = self
return Data(bytes: &int, count: int / Int(UINT8_MAX))
}
}
extension UInt8 {
func asData() -> Data {
return Data([self])
}
}