Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aaa921d

Browse files
committedJul 23, 2019
Merge branch 'develop'
2 parents 081861b + 5934cbb commit aaa921d

20 files changed

+953
-6
lines changed
 

‎Example/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ let package = Package(
77
name: "SwiftyXBeeExample",
88
dependencies: [
99
// Dependencies declare other packages that this package depends on.
10-
.package(path: "../"),
10+
.package(url: "https://github.com/samco182/SwiftyXBee", from: "1.0.0"),
1111

1212
],
1313
targets: [

‎Example/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
# SwiftyXBeeExample
22

33
A simple example of how to communicate with XBee (ZigBee Series 2) radios in API mode.
4+
5+
⚠️ If you want to run the example code, make sure to use an actual XBee serial number when defining:
6+
```swift
7+
let deviceAddress = DeviceAddress(address: 0x0013A20012345678)
8+
```
9+
You can find the XBee's serial number on the back of the device, or by copying it directly from the [XCTU tool](https://www.digi.com/resources/documentation/digidocs/90001526/tasks/t_download_and_install_xctu.htm).
+35-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,35 @@
1-
print("Hello, world!")
1+
import SwiftyXBee
2+
3+
// Initialize xbee instance
4+
let serialConnection = SerialConnection(speed: .S9600, bitsPerChar: .Eight, stopBits: .One, parity: .None)
5+
let xbee = SwiftyXBee(for: .RaspberryPi3, serialConnection: serialConnection)
6+
7+
8+
// Reading a Receive Packet API Frame
9+
10+
print("Receiving packet...")
11+
12+
do {
13+
let readingPacket = try xbee.readRFDataPacket()
14+
print("Packet received: \(readingPacket.frameData.receivedData)")
15+
} catch let error {
16+
print("Error receiving packet: \(error)")
17+
}
18+
19+
20+
// Sending a Transmit Request API Frame
21+
22+
print("Sending packet...")
23+
let deviceAddress = DeviceAddress(address: 0x0013A20012345678) // For the example to work, replace this for an actual XBee Serial number
24+
let networkAddress = NetworkAddress(address: 0xFFFE) // You can use this address if you don't know the destination's network address
25+
xbee.sendTransmitRequest(to: deviceAddress, network: networkAddress, message: "This is my message to send!")
26+
27+
28+
// Reading a Transmit Status API Frame
29+
30+
do {
31+
let readingPacket = try xbee.readTransmitStatus()
32+
print("Packet sent. Status: \(readingPacket.frameData.deliveryStatus!)")
33+
} catch let error {
34+
print("Error reading status: \(error)")
35+
}

‎README.md

+125-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,125 @@
1-
# SwiftXBee
2-
⚡️ A Swift library for communicating with XBee radios in API mode
1+
# SwiftyXBee
2+
3+
⚡️A Swift library for communicating with XBee (ZigBee Series 2) radios in API mode.
4+
<p>
5+
<img src="https://img.shields.io/badge/Architecture%20-ARMv6%20%7C%20%20ARMv7%2F8-red.svg"/>
6+
<img src="https://img.shields.io/badge/OS-Raspbian%20%7C%20Debian%20%7C%20Ubuntu-yellow.svg"/>
7+
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift-4x-brightgreen.svg"/></a>
8+
<a href="https://raw.githubusercontent.com/samco182/SwiftySHT20/master/LICENSE"><img src="https://img.shields.io/badge/Licence-MIT-blue.svg" /></a>
9+
</p>
10+
<img src="https://www.digi.com/products/embedded-systems/rf-modules/2-4-ghz-modules/xbee-zigbee/product-images/xbee-s2c-zigbee" height="300" width="450">
11+
12+
## Summary
13+
This is a [SwiftyGPIO](https://github.com/uraimo/SwiftyGPIO) based library for communicating with XBee radios in **API mode**, with support for Series 2 **only**.
14+
15+
This is a **work in progress**. I started coding the library for a project I am currently working on, so, as of now, it only supports RX/TX and Transmit Status API Frames. If you want to contribute to this noble cause, please submit a PR and I will be more than happy to review it and merge it :smile:.
16+
17+
For more information regarding the RF module, you can consult its [datasheet](https://www.digi.com/resources/documentation/digidocs/pdfs/90002002.pdf).
18+
19+
## API Mode
20+
XBees support two operation modes: API and AT. API mode requires that the device communicate through a structured interface (that is, data is communicated in frames in a defined order). The API specifies how the device sends and receives commands, command responses, and module status messages using a serial port Data Frame. On the other hand, in AT (transparent) mode, the XBee radio simply relays serial data to the receiving XBee, as identified by the DH+DL address.
21+
22+
According to the documentation:
23+
> The XBee firmware supports two API operating modes: without escaped characters and with escaped characters. Use the AP command to enable either mode. To configure a device to one of these modes, set the following AP parameter values:
24+
> - AP = 1: API operation.
25+
> - AP = 2: API operation (with escaped characters—only possible on UART).
26+
27+
⚠️ This library is designed to work only in API mode, it **requires** the **AP mode set to 2 (escape bytes)**, as this setting offers the best reliability.
28+
29+
## Hardware Details
30+
- The XBee should be powered using **3.3 V**.
31+
- This library requires the XBee's **UART** to be configured with compatible settings for the baud rate, parity, start bits, stop bits, and data bits.
32+
33+
This is the pin assignment to manually connect (no XBee shield) the device to any of the compatible boards:
34+
35+
| XBee Pin | Board UART |
36+
| ------------------------ | --------------- |
37+
| VCC = **1** | VCC 3.3V |
38+
| DOUT = **2** | RX / Receive |
39+
| DIN / CONFIG = **3** | TX / Transmit |
40+
| GND = **10** | GND |
41+
42+
The UART pins on the RaspberryPi (pin 14 TXD, pin 15 RXD) need to be enabled via `raspi-config` before you can use them (restart required). By enabling the UART pins, you will lose the ability to access the login shell over serial.
43+
44+
## Supported Boards
45+
Every board supported by [SwiftyGPIO](https://github.com/uraimo/SwiftyGPIO): RaspberryPis, BeagleBones, C.H.I.P., etc...
46+
47+
To use this library, you'll need a Linux ARM board running [Swift 4.x](https://github.com/uraimo/buildSwiftOnARM) 🚗.
48+
49+
The example below will use a Raspberry Pi 3B+ board, but you can easily modify the example to use one of the other supported boards. A full working demo project for the RaspberryPi3B+ is available in the **Example** directory.
50+
51+
## Installation
52+
First of all, makes sure your board is running **Swift 4.x** ⚠️!
53+
54+
Since Swift 4.x supports Swift Package Manager, you only need to add SwiftXBee as a dependency in your project's `Package.swift` file:
55+
56+
```swift
57+
let package = Package(
58+
name: "MyProject",
59+
dependencies: [
60+
.package(url: "https://github.com/samco182/SwiftyXBee", from: "1.0.0"),
61+
]
62+
targets: [
63+
.target(
64+
name: "MyProject",
65+
dependencies: ["SwiftyXBee"]),
66+
]
67+
)
68+
```
69+
Then run `swift package update` to install the dependency.
70+
71+
## Usage
72+
### Initialization
73+
The first thing is to initialize an instance of `SwiftyXBee` with the same UART configuration as the one you used to setup the XBee devices on the XCTU tool or through the AT command mode. Once you have your `xbee` object initialized, you can send and receive data packets between XBees:
74+
75+
```swift
76+
import SwiftyXBee
77+
78+
let serial = SerialConnection(speed: .S9600, bitsPerChar: .Eight, stopBits: .One, parity: .None)
79+
let xbee = SwiftyXBee(for: .RaspberryPi3, serialConnection: serial)
80+
```
81+
You can also initialize the `XBee` object with the following method:
82+
```swift
83+
import SwiftyXBee
84+
85+
let xbee = SwiftyXBee()
86+
```
87+
This initializer defaults to `.RaspberryPi3` as the selected board and serial connection with `speed: .S9600`, `bitsPerChar: .Eight`, `stopBits: .One`, and `parity: .None)`.
88+
89+
### Transmit Packets
90+
There a several different types of transmit (TX) packets available. But as mentioned above, as of now, the library only allows **Transmit Request** packets to be sent. A list of all TX packets can be found in the API [documentation](https://www.digi.com/resources/documentation/digidocs/pdfs/90002002.pdf). All classes that end in "Request" are TX packets.
91+
```swift
92+
// The destination XBee 64-bit serial number
93+
let deviceAddress = DeviceAddress(address: 0x0013A20012345678)
94+
95+
// The destination XBee 16-bit network address
96+
let networkAddress = NetworkAddress(address: 0xFFFE)
97+
98+
// The actual message to be sent
99+
let message = "This is my message to send!"
100+
101+
xbee.sendTransmitRequest(to: deviceAddress, network: networkAddress, message: message)
102+
```
103+
When a Transmit Request completes, the device sends a **Transmit Status** packet out of the serial interface. This message indicates if the Transmit Request was successful or if it failed. If you want to make sure your packet was correctly delivered, call the following code:
104+
```swift
105+
do {
106+
let transmitStatus = try xbee.readTransmitStatus()
107+
print("Status received: \(readingPacket.frameData.deliveryStatus)")
108+
} catch let error {
109+
print("Error: \(error)")
110+
}
111+
```
112+
113+
### Receive Packet
114+
As with transmit (TX) packets, there are also several different types of receive (RX) packets available. But as of now, the library only allows **Receive Packet** API frame to be read.
115+
```swift
116+
do {
117+
let readingPacket = try xbee.readRFDataPacket()
118+
print("Packet received: \(readingPacket.frameData.receivedData)")
119+
} catch let error {
120+
print("Error: \(error)")
121+
}
122+
```
123+
124+
## Note 🔎
125+
If you want to better understand how ZigBee communication protocol works, or the details (in a more comprehensive way) of the most common API frames XBee counts with, you could try reading [this book](https://www.amazon.com/gp/product/0596807732?ie=UTF8&tag=xbapra-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0596807732Building).
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// Constants.swift
3+
// SwiftyXBee
4+
//
5+
// Created by Samuel Cornejo on 7/13/19.
6+
//
7+
8+
import Foundation
9+
10+
public enum Constant {
11+
public static let minimumRawDataLength = 4
12+
public static let startDelimiter: UInt8 = 0x7E
13+
public static let escapeByteXOR: UInt8 = 0x20
14+
public static let hexConversionByte: UInt64 = 0xFF
15+
public static let checksumExcludedBytesCount = 3
16+
}
17+
18+
public enum LengthConstant {
19+
public static let msbIndex = 1
20+
public static let lsbIndex = 2
21+
public static let totalExcludedBytes: UInt8 = 4
22+
}
23+
24+
public enum EscapedBytes: UInt8, CaseIterable {
25+
case frameDelimiter = 0x7E
26+
case escape = 0x7D
27+
case xon = 0x11
28+
case xoff = 0x13
29+
}
30+
31+
public enum FrameType: UInt8 {
32+
case transmitRequest = 0x10
33+
case transmitStatus = 0x8B
34+
case receivePacket = 0x90
35+
}
36+
37+
// ZigBee Receive Packet Frame
38+
public enum ReceiveOptions: UInt8 {
39+
case acknowledgedPacket = 0x01
40+
case broadcastPacket = 0x02
41+
case encryptedPacket = 0x20
42+
case endDevicePacket = 0x40
43+
}
44+
45+
// ZigBee Transmit Request Frame
46+
public enum FrameId: UInt8 {
47+
case sendNoACK = 0x00
48+
case sendACK = 0x01
49+
}
50+
51+
public enum TransmissionOption: UInt8 {
52+
case unusedBits = 0x00
53+
case disableACK = 0x01
54+
case enableAPSEncryption = 0x20
55+
case extendedTransmissionTimeout = 0x40
56+
}
57+
58+
// ZigBee Transmit Status
59+
public enum DeliveryStatus: UInt8 {
60+
case success = 0x00
61+
case macACKFailure = 0x01
62+
case ccaFailure = 0x02
63+
case invalidDestinationEndpoint = 0x15
64+
case networkACKFailure = 0x21
65+
case notJoinedToNetwork = 0x22
66+
case selfAddressed = 0x23
67+
case addressNotFound = 0x24
68+
case routeNotFound = 0x25
69+
case broadcastFailedToHear = 0x26
70+
case invalidBindingTableIndex = 0x2B
71+
case resourceError = 0x2C
72+
case attemptedBroadcastWithAPS = 0x2D
73+
case attemptedUnicastWithAPS = 0x2E
74+
case lackOfFreeBuffer = 0x32
75+
case dataPayloadTooLarge = 0x74
76+
case indirectMessageUnrequested = 0x75
77+
}
78+
79+
public enum DiscoveryStatus: UInt8 {
80+
case noDiscoveryOverhead = 0x00
81+
case addressDiscovery = 0x01
82+
case routeDiscovery = 0x02
83+
case addressAndRoute = 0x03
84+
case extendedTimeoutDiscovery = 0x40
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// Array+Extensions.swift
3+
// SwiftyXBee
4+
//
5+
// Created by Samuel Cornejo on 7/14/19.
6+
//
7+
8+
import Foundation
9+
10+
extension Array where Element == UInt8 {
11+
/// Adds up all the elements in an array of UInt8.
12+
///
13+
/// - Returns: The sum of all the elements
14+
/// - Note: This is a workaround method. For some reason, using Array's Reduce inside a while loop,
15+
/// in a armv7 board causes the follwing error: **illegal hardware instruction swift run**.
16+
func addAll() -> UInt64 {
17+
var total = UInt64(0)
18+
forEach({ total += UInt64($0)})
19+
return total
20+
}
21+
22+
/// Adds escape bytes if needed.
23+
///
24+
/// - Returns: Data with possible escape bytes included
25+
/// - Note: According to XBee documentation, API Mode 2 needs to escape a specific set of bytes.
26+
func escapeDataIfNeeded() -> [CChar] {
27+
var data: [UInt8] = []
28+
29+
for byte in self {
30+
if EscapedBytes.allCases.contains(where: { $0.rawValue == byte }) {
31+
data.append(EscapedBytes.escape.rawValue)
32+
data.append(byte ^ Constant.escapeByteXOR)
33+
} else {
34+
data.append(byte)
35+
}
36+
}
37+
38+
return data.map({ CChar(bitPattern: $0) })
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// Int+Extensions.swift
3+
// SwiftyXBee
4+
//
5+
// Created by Samuel Cornejo on 7/18/19.
6+
//
7+
8+
import Foundation
9+
10+
extension UInt64 {
11+
var uint8: UInt8 {
12+
return UInt8(self)
13+
}
14+
15+
var uint16: UInt16 {
16+
return UInt16(self)
17+
}
18+
}
19+
20+
extension UInt16 {
21+
var uint8: UInt8 {
22+
return UInt8(self)
23+
}
24+
}
25+
26+
extension Int {
27+
var uint8: UInt8 {
28+
return UInt8(self)
29+
}
30+
}
31+
32+
extension CChar {
33+
var uint8: UInt8 {
34+
return UInt8(self)
35+
}
36+
}
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.