Created
February 27, 2016 13:59
-
-
Save nathanntg/2ad76f9db61d33f88229 to your computer and use it in GitHub Desktop.
Delimited Serial Packet Descriptor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ORSSerial | |
/// An example of an extension of the ORSSerialPacketDescriptor that enables identifying delimited packets. | |
class DelimitedSerialPacketDescriptor: ORSSerialPacketDescriptor { | |
var delimiter: NSData? | |
convenience init(delimiter: NSData, maximumPacketLength maxPacketLength: UInt, userInfo: AnyObject?, responseEvaluator: ORSSerialPacketEvaluator) { | |
self.init(maximumPacketLength: maxPacketLength, userInfo: userInfo, responseEvaluator: responseEvaluator) | |
// set delimiter | |
self.delimiter = delimiter | |
} | |
convenience init(delimiterString: String, maximumPacketLength maxPacketLength: UInt, userInfo: AnyObject?, responseEvaluator: ORSSerialPacketEvaluator) { | |
self.init(maximumPacketLength: maxPacketLength, userInfo: userInfo, responseEvaluator: responseEvaluator) | |
// set delimiter | |
self.delimiter = delimiterString.dataUsingEncoding(NSUTF8StringEncoding) | |
} | |
private func packetMatchingExcludingFinalDelimiter(buffer: NSData) -> NSData? { | |
// only use log if delimiter is provided (should only be called if delimiter exists) | |
guard let delimiter = delimiter else { | |
return nil | |
} | |
// empty buffer? potentially valid | |
if buffer.length == 0 { | |
if dataIsValidPacket(buffer) { | |
return buffer | |
} | |
return nil | |
} | |
// work back from the end of the buffer | |
for i in 0...buffer.length { | |
// check for delimiter if not reading from the beginning of the buffer | |
if i < buffer.length { | |
// not enough space for the delimiter | |
if i + delimiter.length > buffer.length { | |
continue | |
} | |
// check for proceeding delimiter | |
// (could be more lenient and just check for the end of the delimiter) | |
let windowDel = buffer.subdataWithRange(NSMakeRange(buffer.length - i - delimiter.length, delimiter.length)) | |
// does not match? continue | |
if !windowDel.isEqualToData(delimiter) { | |
continue | |
} | |
} | |
// make window | |
let window = buffer.subdataWithRange(NSMakeRange(buffer.length - i, i)) | |
if dataIsValidPacket(window) { | |
return window | |
} | |
} | |
return nil | |
} | |
override func packetMatchingAtEndOfBuffer(buffer: NSData?) -> NSData? { | |
// only use log if delimiter is provided | |
guard let delimiter = delimiter else { | |
// otherwise inherit normal behavior | |
return super.packetMatchingAtEndOfBuffer(buffer) | |
} | |
// unwrap buffer | |
guard let buffer = buffer else { return nil } | |
// space for delimiter | |
if buffer.length < delimiter.length { | |
return nil | |
} | |
// ensure buffer ends with delimiter | |
let windowFinalDel = buffer.subdataWithRange(NSMakeRange(buffer.length - delimiter.length, delimiter.length)) | |
if !windowFinalDel.isEqualTo(delimiter) { | |
return nil | |
} | |
return packetMatchingExcludingFinalDelimiter(buffer.subdataWithRange(NSMakeRange(0, buffer.length - delimiter.length))) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCTest | |
class DelimitedSerialPacketDescriptorTests: XCTestCase { | |
func testPacketDescriptorNonEmpty() { | |
let desc = DelimitedSerialPacketDescriptor(delimiter: "\r\n".dataUsingEncoding(NSASCIIStringEncoding)!, maximumPacketLength: 32, userInfo: nil, responseEvaluator: { | |
(d: NSData?) -> Bool in | |
guard let data = d else { | |
return false | |
} | |
return data.length > 0 | |
}) | |
let toTest: [(String, String?)] = [ | |
("No\r\nFinal", nil), | |
("\r\nTesting\r\n", "Testing"), | |
("T\r", nil), | |
("\r\nMultiple\r\nStrings\r\nIn\r\nRow\r\n", "Row"), | |
("\r\n", nil), | |
("\r\n\r\n", "\r\n"), | |
("Blah\r\n", "Blah") | |
] | |
for (stringIn, stringOut) in toTest { | |
let dataIn = stringIn.dataUsingEncoding(NSASCIIStringEncoding)! | |
let dataOut: NSData? = stringOut?.dataUsingEncoding(NSASCIIStringEncoding)! ?? nil | |
XCTAssertEqual(dataOut, desc.packetMatchingAtEndOfBuffer(dataIn)) | |
} | |
} | |
func testPacketDescriptorEmpty() { | |
let desc = DelimitedSerialPacketDescriptor(delimiter: "\r\n".dataUsingEncoding(NSASCIIStringEncoding)!, maximumPacketLength: 16, userInfo: nil, responseEvaluator: { | |
(d: NSData?) -> Bool in | |
return d != nil | |
}) | |
let toTest: [(String, String?)] = [ | |
("\r\n\r", nil), | |
("\r\n", ""), | |
("\r\n\r\n", "") | |
] | |
for (stringIn, stringOut) in toTest { | |
let dataIn = stringIn.dataUsingEncoding(NSASCIIStringEncoding)! | |
let dataOut: NSData? = stringOut?.dataUsingEncoding(NSASCIIStringEncoding)! ?? nil | |
XCTAssertEqual(dataOut, desc.packetMatchingAtEndOfBuffer(dataIn)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment