A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.
Dependents: LPC4088test LPC4088test_ledonly LPC4088test_deleteall LPC4088_RAMtest ... more
XBee.h@12:15597e45eea0, 2014-01-30 (annotated)
- Committer:
- embeddedartists
- Date:
- Thu Jan 30 08:50:47 2014 +0100
- Revision:
- 12:15597e45eea0
- Parent:
- 7:e431d9d47db6
Added license information
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
embeddedartists | 12:15597e45eea0 | 1 | /* |
embeddedartists | 12:15597e45eea0 | 2 | * Copyright 2013 Embedded Artists AB |
embeddedartists | 12:15597e45eea0 | 3 | * |
embeddedartists | 12:15597e45eea0 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
embeddedartists | 12:15597e45eea0 | 5 | * you may not use this file except in compliance with the License. |
embeddedartists | 12:15597e45eea0 | 6 | * You may obtain a copy of the License at |
embeddedartists | 12:15597e45eea0 | 7 | * |
embeddedartists | 12:15597e45eea0 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
embeddedartists | 12:15597e45eea0 | 9 | * |
embeddedartists | 12:15597e45eea0 | 10 | * Unless required by applicable law or agreed to in writing, software |
embeddedartists | 12:15597e45eea0 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
embeddedartists | 12:15597e45eea0 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
embeddedartists | 12:15597e45eea0 | 13 | * See the License for the specific language governing permissions and |
embeddedartists | 12:15597e45eea0 | 14 | * limitations under the License. |
embeddedartists | 12:15597e45eea0 | 15 | */ |
embeddedartists | 7:e431d9d47db6 | 16 | |
embeddedartists | 7:e431d9d47db6 | 17 | #ifndef XBEE_H |
embeddedartists | 7:e431d9d47db6 | 18 | #define XBEE_H |
embeddedartists | 7:e431d9d47db6 | 19 | |
embeddedartists | 7:e431d9d47db6 | 20 | #define RX_BUF_SIZE (512) |
embeddedartists | 7:e431d9d47db6 | 21 | #define XBEE_BUF_SZ (200) |
embeddedartists | 7:e431d9d47db6 | 22 | |
embeddedartists | 7:e431d9d47db6 | 23 | #define XBEE_ADDRLO_BROADCAST (0x0000FFFF) |
embeddedartists | 7:e431d9d47db6 | 24 | #define XBEE_ADDRHI_BROADCAST (0x00000000) |
embeddedartists | 7:e431d9d47db6 | 25 | |
embeddedartists | 7:e431d9d47db6 | 26 | /** |
embeddedartists | 7:e431d9d47db6 | 27 | * Interface to Digi International's XBee module. The XBee S1 module has |
embeddedartists | 7:e431d9d47db6 | 28 | * been used during testing of this interface. |
embeddedartists | 7:e431d9d47db6 | 29 | */ |
embeddedartists | 7:e431d9d47db6 | 30 | class XBee { |
embeddedartists | 7:e431d9d47db6 | 31 | public: |
embeddedartists | 7:e431d9d47db6 | 32 | |
embeddedartists | 7:e431d9d47db6 | 33 | /** Error codes returned from public methods */ |
embeddedartists | 7:e431d9d47db6 | 34 | enum XBeeError { |
embeddedartists | 7:e431d9d47db6 | 35 | Ok = 0, |
embeddedartists | 7:e431d9d47db6 | 36 | ReadError = -1, |
embeddedartists | 7:e431d9d47db6 | 37 | CmdError = -2, |
embeddedartists | 7:e431d9d47db6 | 38 | BufTooSmallError = -3, |
embeddedartists | 7:e431d9d47db6 | 39 | TimeOutError = -4, |
embeddedartists | 7:e431d9d47db6 | 40 | NotInitializedError = -5, |
embeddedartists | 7:e431d9d47db6 | 41 | ArgumentError = -6 |
embeddedartists | 7:e431d9d47db6 | 42 | |
embeddedartists | 7:e431d9d47db6 | 43 | }; |
embeddedartists | 7:e431d9d47db6 | 44 | |
embeddedartists | 7:e431d9d47db6 | 45 | /** Callback function/method types. See registerCallback() */ |
embeddedartists | 7:e431d9d47db6 | 46 | enum CallbackType { |
embeddedartists | 7:e431d9d47db6 | 47 | /** Device is up and ready */ |
embeddedartists | 7:e431d9d47db6 | 48 | CbDeviceUp = 0, |
embeddedartists | 7:e431d9d47db6 | 49 | /** Device is down (disconnected) */ |
embeddedartists | 7:e431d9d47db6 | 50 | CbDeviceDown, |
embeddedartists | 7:e431d9d47db6 | 51 | /** A node has been found */ |
embeddedartists | 7:e431d9d47db6 | 52 | CbNodeFound, |
embeddedartists | 7:e431d9d47db6 | 53 | /** Transmit status */ |
embeddedartists | 7:e431d9d47db6 | 54 | CbTxStat, |
embeddedartists | 7:e431d9d47db6 | 55 | /** Data is available */ |
embeddedartists | 7:e431d9d47db6 | 56 | CbDataAvailable, |
embeddedartists | 7:e431d9d47db6 | 57 | CbNum // must be last |
embeddedartists | 7:e431d9d47db6 | 58 | |
embeddedartists | 7:e431d9d47db6 | 59 | }; |
embeddedartists | 7:e431d9d47db6 | 60 | |
embeddedartists | 7:e431d9d47db6 | 61 | /** Xbee types */ |
embeddedartists | 7:e431d9d47db6 | 62 | enum XBeeType { |
embeddedartists | 7:e431d9d47db6 | 63 | EndDevice = 0, |
embeddedartists | 7:e431d9d47db6 | 64 | Coordinator |
embeddedartists | 7:e431d9d47db6 | 65 | }; |
embeddedartists | 7:e431d9d47db6 | 66 | |
embeddedartists | 7:e431d9d47db6 | 67 | /** Transmit status */ |
embeddedartists | 7:e431d9d47db6 | 68 | enum XBeeTxStatus { |
embeddedartists | 7:e431d9d47db6 | 69 | TxStatusOk = 0, |
embeddedartists | 7:e431d9d47db6 | 70 | TxStatusNoAck, |
embeddedartists | 7:e431d9d47db6 | 71 | TxStatusCCA, |
embeddedartists | 7:e431d9d47db6 | 72 | TxStatusPurged |
embeddedartists | 7:e431d9d47db6 | 73 | }; |
embeddedartists | 7:e431d9d47db6 | 74 | |
embeddedartists | 7:e431d9d47db6 | 75 | /** |
embeddedartists | 7:e431d9d47db6 | 76 | * Create an interface to an XBee module. |
embeddedartists | 7:e431d9d47db6 | 77 | * |
embeddedartists | 7:e431d9d47db6 | 78 | * @param tx UART TX line |
embeddedartists | 7:e431d9d47db6 | 79 | * @param tx UART rx line |
embeddedartists | 7:e431d9d47db6 | 80 | * @param reset reset pin |
embeddedartists | 7:e431d9d47db6 | 81 | * @param sleep sleep request pin |
embeddedartists | 7:e431d9d47db6 | 82 | */ |
embeddedartists | 7:e431d9d47db6 | 83 | XBee(PinName tx, PinName rx, PinName reset, PinName sleep); |
embeddedartists | 7:e431d9d47db6 | 84 | |
embeddedartists | 7:e431d9d47db6 | 85 | /** |
embeddedartists | 7:e431d9d47db6 | 86 | * Initialize the XBee module and configure it to be of a |
embeddedartists | 7:e431d9d47db6 | 87 | * specific type. |
embeddedartists | 7:e431d9d47db6 | 88 | * |
embeddedartists | 7:e431d9d47db6 | 89 | * Note: This implementation will always configure the XBee module to |
embeddedartists | 7:e431d9d47db6 | 90 | * work in API mode. |
embeddedartists | 7:e431d9d47db6 | 91 | * |
embeddedartists | 7:e431d9d47db6 | 92 | * @param type the type of this XBee node |
embeddedartists | 7:e431d9d47db6 | 93 | * @param panId the PAN ID to use for the XBee network. This argument |
embeddedartists | 7:e431d9d47db6 | 94 | * must contain 4 characters representing hexadecimal values |
embeddedartists | 7:e431d9d47db6 | 95 | * (e.g. "A1E0" means the hexadecimal value 0xA1E0); |
embeddedartists | 7:e431d9d47db6 | 96 | */ |
embeddedartists | 7:e431d9d47db6 | 97 | XBeeError init(XBeeType type, const char* panId); |
embeddedartists | 7:e431d9d47db6 | 98 | |
embeddedartists | 7:e431d9d47db6 | 99 | /** |
embeddedartists | 7:e431d9d47db6 | 100 | * Register a callback function |
embeddedartists | 7:e431d9d47db6 | 101 | * |
embeddedartists | 7:e431d9d47db6 | 102 | * @param fptr Callback function to register |
embeddedartists | 7:e431d9d47db6 | 103 | * @param type The type of event that will trigger a call to the function. |
embeddedartists | 7:e431d9d47db6 | 104 | */ |
embeddedartists | 7:e431d9d47db6 | 105 | void registerCallback(void (*fptr)(void), CallbackType type) { |
embeddedartists | 7:e431d9d47db6 | 106 | if (fptr) { |
embeddedartists | 7:e431d9d47db6 | 107 | _callbacks[type].attach(fptr); |
embeddedartists | 7:e431d9d47db6 | 108 | } |
embeddedartists | 7:e431d9d47db6 | 109 | } |
embeddedartists | 7:e431d9d47db6 | 110 | |
embeddedartists | 7:e431d9d47db6 | 111 | /** |
embeddedartists | 7:e431d9d47db6 | 112 | * Register a callback method |
embeddedartists | 7:e431d9d47db6 | 113 | * |
embeddedartists | 7:e431d9d47db6 | 114 | * @param tptr pointer to the object to call the member function on |
embeddedartists | 7:e431d9d47db6 | 115 | * @param mptr pointer to the member function to be called |
embeddedartists | 7:e431d9d47db6 | 116 | * @param type The type of event that will trigger a call to the method. |
embeddedartists | 7:e431d9d47db6 | 117 | */ |
embeddedartists | 7:e431d9d47db6 | 118 | template<typename T> |
embeddedartists | 7:e431d9d47db6 | 119 | void registerCallback(T* tptr, void (T::*mptr)(void), CallbackType type) { |
embeddedartists | 7:e431d9d47db6 | 120 | if((mptr != NULL) && (tptr != NULL)) { |
embeddedartists | 7:e431d9d47db6 | 121 | _callbacks[type].attach(tptr, mptr); |
embeddedartists | 7:e431d9d47db6 | 122 | } |
embeddedartists | 7:e431d9d47db6 | 123 | } |
embeddedartists | 7:e431d9d47db6 | 124 | |
embeddedartists | 7:e431d9d47db6 | 125 | /** |
embeddedartists | 7:e431d9d47db6 | 126 | * Call this method repeatedly to process incoming data. |
embeddedartists | 7:e431d9d47db6 | 127 | */ |
embeddedartists | 7:e431d9d47db6 | 128 | void process(); |
embeddedartists | 7:e431d9d47db6 | 129 | |
embeddedartists | 7:e431d9d47db6 | 130 | /** |
embeddedartists | 7:e431d9d47db6 | 131 | * Get address of remote node. This method will only return valid data |
embeddedartists | 7:e431d9d47db6 | 132 | * when called in the context of the CbDataAvailable and CbNodeFound |
embeddedartists | 7:e431d9d47db6 | 133 | * callbacks |
embeddedartists | 7:e431d9d47db6 | 134 | * |
embeddedartists | 7:e431d9d47db6 | 135 | * @param addrHi Top 32 bits of address will be written to this argument |
embeddedartists | 7:e431d9d47db6 | 136 | * @param addrLo Bottom 32 bits of address will be written to this argument |
embeddedartists | 7:e431d9d47db6 | 137 | */ |
embeddedartists | 7:e431d9d47db6 | 138 | XBeeError getRemoteAddress(uint32_t* addrHi, uint32_t* addrLo); |
embeddedartists | 7:e431d9d47db6 | 139 | |
embeddedartists | 7:e431d9d47db6 | 140 | /** |
embeddedartists | 7:e431d9d47db6 | 141 | * Get signal strength indicator value (RSSI). This method will only |
embeddedartists | 7:e431d9d47db6 | 142 | * return valid data when called in the context of the |
embeddedartists | 7:e431d9d47db6 | 143 | * CbDataAvailable and CbNodeFound callbacks |
embeddedartists | 7:e431d9d47db6 | 144 | * |
embeddedartists | 7:e431d9d47db6 | 145 | * @param rssi RSSI value will be written to this argument |
embeddedartists | 7:e431d9d47db6 | 146 | */ |
embeddedartists | 7:e431d9d47db6 | 147 | XBeeError getRssi(uint8_t* rssi ); |
embeddedartists | 7:e431d9d47db6 | 148 | |
embeddedartists | 7:e431d9d47db6 | 149 | /** |
embeddedartists | 7:e431d9d47db6 | 150 | * Get the transmit status. This method will only return valid data when |
embeddedartists | 7:e431d9d47db6 | 151 | * called in the context of the CbTxStat callback. |
embeddedartists | 7:e431d9d47db6 | 152 | * |
embeddedartists | 7:e431d9d47db6 | 153 | * @param frameId the frame ID will be written to this argument |
embeddedartists | 7:e431d9d47db6 | 154 | * @param status the status will be written to this argument |
embeddedartists | 7:e431d9d47db6 | 155 | */ |
embeddedartists | 7:e431d9d47db6 | 156 | XBeeError getTxStatus(uint8_t* frameId, XBeeTxStatus* status); |
embeddedartists | 7:e431d9d47db6 | 157 | |
embeddedartists | 7:e431d9d47db6 | 158 | /** |
embeddedartists | 7:e431d9d47db6 | 159 | * Get received data. This method will only return valid data when called |
embeddedartists | 7:e431d9d47db6 | 160 | * in the context of the CbDataAvailable callback |
embeddedartists | 7:e431d9d47db6 | 161 | * |
embeddedartists | 7:e431d9d47db6 | 162 | * @param data will point to a buffer with received data |
embeddedartists | 7:e431d9d47db6 | 163 | * @param len will contain the length of the received data |
embeddedartists | 7:e431d9d47db6 | 164 | */ |
embeddedartists | 7:e431d9d47db6 | 165 | XBeeError getData(char** data, uint8_t* len); |
embeddedartists | 7:e431d9d47db6 | 166 | |
embeddedartists | 7:e431d9d47db6 | 167 | /** |
embeddedartists | 7:e431d9d47db6 | 168 | * Send data to a node with specified address. It is also possible to |
embeddedartists | 7:e431d9d47db6 | 169 | * broadcast a message using broadcast address (XBEE_ADDRHI_BROADCAST, |
embeddedartists | 7:e431d9d47db6 | 170 | * XBEE_ADDRLO_BROADCAST). |
embeddedartists | 7:e431d9d47db6 | 171 | * |
embeddedartists | 7:e431d9d47db6 | 172 | * @param addrHi Top 32 bits of address |
embeddedartists | 7:e431d9d47db6 | 173 | * @param addrLo Bottom 32 bits of address |
embeddedartists | 7:e431d9d47db6 | 174 | * @param data buffer containing data to send |
embeddedartists | 7:e431d9d47db6 | 175 | * @param len number of bytes to send |
embeddedartists | 7:e431d9d47db6 | 176 | * @param frameId the ID of the frame will be written to this argument. |
embeddedartists | 7:e431d9d47db6 | 177 | * The ID can then be used to match this request with the status returned |
embeddedartists | 7:e431d9d47db6 | 178 | * in the CbTxStat callback. |
embeddedartists | 7:e431d9d47db6 | 179 | */ |
embeddedartists | 7:e431d9d47db6 | 180 | XBeeError send(uint32_t addrHi, uint32_t addrLo, char* data, |
embeddedartists | 7:e431d9d47db6 | 181 | uint8_t len, uint8_t* frameId); |
embeddedartists | 7:e431d9d47db6 | 182 | |
embeddedartists | 7:e431d9d47db6 | 183 | /** |
embeddedartists | 7:e431d9d47db6 | 184 | * Send a Node Discover request. All modules on the operating channel and |
embeddedartists | 7:e431d9d47db6 | 185 | * PAN ID should respond. The responses will be reported in the CbNodeFound |
embeddedartists | 7:e431d9d47db6 | 186 | * callback. |
embeddedartists | 7:e431d9d47db6 | 187 | */ |
embeddedartists | 7:e431d9d47db6 | 188 | XBeeError discoverNodes(); |
embeddedartists | 7:e431d9d47db6 | 189 | |
embeddedartists | 7:e431d9d47db6 | 190 | /** |
embeddedartists | 7:e431d9d47db6 | 191 | * Request the module to enter sleep mode. |
embeddedartists | 7:e431d9d47db6 | 192 | */ |
embeddedartists | 7:e431d9d47db6 | 193 | XBeeError enterSleep(); |
embeddedartists | 7:e431d9d47db6 | 194 | |
embeddedartists | 7:e431d9d47db6 | 195 | /** |
embeddedartists | 7:e431d9d47db6 | 196 | * Request the module to exit sleep mode. |
embeddedartists | 7:e431d9d47db6 | 197 | */ |
embeddedartists | 7:e431d9d47db6 | 198 | XBeeError exitSleep(); |
embeddedartists | 7:e431d9d47db6 | 199 | |
embeddedartists | 7:e431d9d47db6 | 200 | |
embeddedartists | 7:e431d9d47db6 | 201 | protected: |
embeddedartists | 7:e431d9d47db6 | 202 | |
embeddedartists | 7:e431d9d47db6 | 203 | |
embeddedartists | 7:e431d9d47db6 | 204 | private: |
embeddedartists | 7:e431d9d47db6 | 205 | |
embeddedartists | 7:e431d9d47db6 | 206 | enum RfState { |
embeddedartists | 7:e431d9d47db6 | 207 | RfStateFrame = 0, |
embeddedartists | 7:e431d9d47db6 | 208 | RfStateLength, |
embeddedartists | 7:e431d9d47db6 | 209 | RfStateData |
embeddedartists | 7:e431d9d47db6 | 210 | }; |
embeddedartists | 7:e431d9d47db6 | 211 | |
embeddedartists | 7:e431d9d47db6 | 212 | |
embeddedartists | 7:e431d9d47db6 | 213 | bool _initialized; |
embeddedartists | 7:e431d9d47db6 | 214 | Serial _serial; |
embeddedartists | 7:e431d9d47db6 | 215 | XBeeType _type; |
embeddedartists | 7:e431d9d47db6 | 216 | DigitalOut _reset; |
embeddedartists | 7:e431d9d47db6 | 217 | DigitalOut _sleep; |
embeddedartists | 7:e431d9d47db6 | 218 | |
embeddedartists | 7:e431d9d47db6 | 219 | uint8_t rxqIn; |
embeddedartists | 7:e431d9d47db6 | 220 | uint8_t rxqOut; |
embeddedartists | 7:e431d9d47db6 | 221 | uint8_t rxq[RX_BUF_SIZE]; |
embeddedartists | 7:e431d9d47db6 | 222 | |
embeddedartists | 7:e431d9d47db6 | 223 | uint32_t _rfFrameTimeout; |
embeddedartists | 7:e431d9d47db6 | 224 | Timer _rfFrameTimer; |
embeddedartists | 7:e431d9d47db6 | 225 | |
embeddedartists | 7:e431d9d47db6 | 226 | RfState _rfState; |
embeddedartists | 7:e431d9d47db6 | 227 | uint32_t _rfPos; |
embeddedartists | 7:e431d9d47db6 | 228 | uint32_t _rfFrameLen; |
embeddedartists | 7:e431d9d47db6 | 229 | char _rfBuf[XBEE_BUF_SZ]; |
embeddedartists | 7:e431d9d47db6 | 230 | uint8_t _rfFrameId; |
embeddedartists | 7:e431d9d47db6 | 231 | |
embeddedartists | 7:e431d9d47db6 | 232 | uint32_t _addrHi; |
embeddedartists | 7:e431d9d47db6 | 233 | uint32_t _addrLo; |
embeddedartists | 7:e431d9d47db6 | 234 | uint8_t _rssi; |
embeddedartists | 7:e431d9d47db6 | 235 | uint8_t _frameId; |
embeddedartists | 7:e431d9d47db6 | 236 | XBeeTxStatus _txStatus; |
embeddedartists | 7:e431d9d47db6 | 237 | char* _recvData; |
embeddedartists | 7:e431d9d47db6 | 238 | uint8_t _recvLen; |
embeddedartists | 7:e431d9d47db6 | 239 | |
embeddedartists | 7:e431d9d47db6 | 240 | |
embeddedartists | 7:e431d9d47db6 | 241 | FunctionPointer _callbacks[CbNum]; |
embeddedartists | 7:e431d9d47db6 | 242 | |
embeddedartists | 7:e431d9d47db6 | 243 | |
embeddedartists | 7:e431d9d47db6 | 244 | void uartRxIrq(); |
embeddedartists | 7:e431d9d47db6 | 245 | void uartRxQPut(uint8_t data); |
embeddedartists | 7:e431d9d47db6 | 246 | uint8_t uartRxQGet(); |
embeddedartists | 7:e431d9d47db6 | 247 | bool uartRxQIsEmpty(); |
embeddedartists | 7:e431d9d47db6 | 248 | uint32_t uartReceive(char *buf, uint32_t buflen); |
embeddedartists | 7:e431d9d47db6 | 249 | int32_t uartReadLine(char* buf, uint32_t bufLen, uint32_t timeout); |
embeddedartists | 7:e431d9d47db6 | 250 | |
embeddedartists | 7:e431d9d47db6 | 251 | void resetModule(); |
embeddedartists | 7:e431d9d47db6 | 252 | XBeeError commandMode(); |
embeddedartists | 7:e431d9d47db6 | 253 | XBeeError atGet(const char* atCmd, char* resp, uint32_t respLen); |
embeddedartists | 7:e431d9d47db6 | 254 | XBeeError atSet(const char* atCmd); |
embeddedartists | 7:e431d9d47db6 | 255 | |
embeddedartists | 7:e431d9d47db6 | 256 | void processByte(char data); |
embeddedartists | 7:e431d9d47db6 | 257 | void processFrame(char* buf, uint32_t len); |
embeddedartists | 7:e431d9d47db6 | 258 | |
embeddedartists | 7:e431d9d47db6 | 259 | void handleAtResponse(uint8_t frameId, char* atBuf, uint8_t status, |
embeddedartists | 7:e431d9d47db6 | 260 | char* valueBuf, uint32_t valueLen); |
embeddedartists | 7:e431d9d47db6 | 261 | |
embeddedartists | 7:e431d9d47db6 | 262 | void handleDiscovery(uint8_t status, char* buf, uint32_t len); |
embeddedartists | 7:e431d9d47db6 | 263 | void handleTxStatus(uint8_t frameId, uint8_t status); |
embeddedartists | 7:e431d9d47db6 | 264 | void processData(uint32_t addrHi, uint32_t addrLo, uint8_t rssi, |
embeddedartists | 7:e431d9d47db6 | 265 | uint8_t opt, char* buf, uint32_t len); |
embeddedartists | 7:e431d9d47db6 | 266 | void handleModemStatus(uint8_t status); |
embeddedartists | 7:e431d9d47db6 | 267 | |
embeddedartists | 7:e431d9d47db6 | 268 | char checksum(char* buf, uint32_t len); |
embeddedartists | 7:e431d9d47db6 | 269 | uint32_t bufTo32bitInt(const char* buf); |
embeddedartists | 7:e431d9d47db6 | 270 | void int32bitToBuf(uint32_t v, char* buf); |
embeddedartists | 7:e431d9d47db6 | 271 | |
embeddedartists | 7:e431d9d47db6 | 272 | XBeeError apiTx64(uint32_t addrHi, uint32_t addrLo, char* data, |
embeddedartists | 7:e431d9d47db6 | 273 | uint32_t len, uint8_t* frameId); |
embeddedartists | 7:e431d9d47db6 | 274 | XBeeError apiAtCmd(const char* atCmd, uint32_t param, bool useParameter); |
embeddedartists | 7:e431d9d47db6 | 275 | |
embeddedartists | 7:e431d9d47db6 | 276 | uint8_t getFrameId(); |
embeddedartists | 7:e431d9d47db6 | 277 | |
embeddedartists | 7:e431d9d47db6 | 278 | |
embeddedartists | 7:e431d9d47db6 | 279 | }; |
embeddedartists | 7:e431d9d47db6 | 280 | |
embeddedartists | 7:e431d9d47db6 | 281 | #endif |