Skip to content

Instantly share code, notes, and snippets.

@nathanntg
Created February 27, 2016 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nathanntg/2ad76f9db61d33f88229 to your computer and use it in GitHub Desktop.
Save nathanntg/2ad76f9db61d33f88229 to your computer and use it in GitHub Desktop.
Delimited Serial Packet Descriptor
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)))
}
}
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