Packet.swift 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. //
  2. // Packet.swift
  3. // OmniKit
  4. //
  5. // Created by Pete Schwamb on 10/14/17.
  6. // Copyright © 2017 Pete Schwamb. All rights reserved.
  7. //
  8. import Foundation
  9. public enum PacketError: Error {
  10. case insufficientData
  11. case crcMismatch
  12. case unknownPacketType(rawType: UInt8)
  13. }
  14. public enum PacketType: UInt8 {
  15. case pod = 0b111
  16. case pdm = 0b101
  17. case con = 0b100
  18. case ack = 0b010
  19. func maxBodyLen() -> Int {
  20. switch self {
  21. case .ack:
  22. return 4
  23. case .con, .pdm, .pod:
  24. return 31
  25. }
  26. }
  27. }
  28. public struct Packet {
  29. let address: UInt32
  30. let packetType: PacketType
  31. let sequenceNum: Int
  32. let data: Data
  33. init(address: UInt32, packetType: PacketType, sequenceNum: Int, data: Data = Data()) {
  34. self.address = address
  35. self.packetType = packetType
  36. self.sequenceNum = sequenceNum
  37. let bodyMaxLen = packetType.maxBodyLen()
  38. if data.count > bodyMaxLen {
  39. self.data = data.subdata(in: 0..<bodyMaxLen)
  40. } else {
  41. self.data = data
  42. }
  43. }
  44. init(encodedData: Data) throws {
  45. guard encodedData.count >= 7 else {
  46. // Not enough data for packet
  47. throw PacketError.insufficientData
  48. }
  49. self.address = encodedData[0...].toBigEndian(UInt32.self)
  50. guard let packetType = PacketType(rawValue: encodedData[4] >> 5) else {
  51. throw PacketError.unknownPacketType(rawType: encodedData[4])
  52. }
  53. self.packetType = packetType
  54. self.sequenceNum = Int(encodedData[4] & 0b11111)
  55. let len = encodedData.count
  56. // Check crc
  57. guard encodedData[0..<len-1].crc8() == encodedData[len-1] else {
  58. // Invalid CRC
  59. throw PacketError.crcMismatch
  60. }
  61. self.data = encodedData.subdata(in: 5..<len-1)
  62. }
  63. func encoded() -> Data {
  64. var output = Data(bigEndian: address)
  65. output.append(UInt8(packetType.rawValue << 5) + UInt8(sequenceNum & 0b11111))
  66. output.append(data)
  67. output.append(output.crc8())
  68. return output
  69. }
  70. }
  71. extension Packet: CustomDebugStringConvertible {
  72. public var debugDescription: String {
  73. let sequenceNumStr = String(format: "%02d", sequenceNum)
  74. return "Packet(\(Data(bigEndian: address).hexadecimalString) packetType:\(packetType) seq:\(sequenceNumStr) data:\(data.hexadecimalString))"
  75. }
  76. }