2018.07.26

Dependencies:   FATFileSystem2 mbed-rtos

Fork of USBHost by mbed official

Committer:
sayzyas
Date:
Thu Jul 26 00:29:30 2018 +0000
Revision:
44:e437b1c7c61e
Parent:
43:78f328f311dc
2018.07.26

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sayzyas 43:78f328f311dc 1 /* mbed USBHost Library
sayzyas 43:78f328f311dc 2 * Copyright (c) 2006-2013 ARM Limited
sayzyas 43:78f328f311dc 3 *
sayzyas 43:78f328f311dc 4 * Licensed under the Apache License, Version 2.0 (the "License");
sayzyas 43:78f328f311dc 5 * you may not use this file except in compliance with the License.
sayzyas 43:78f328f311dc 6 * You may obtain a copy of the License at
sayzyas 43:78f328f311dc 7 *
sayzyas 43:78f328f311dc 8 * http://www.apache.org/licenses/LICENSE-2.0
sayzyas 43:78f328f311dc 9 *
sayzyas 43:78f328f311dc 10 * Unless required by applicable law or agreed to in writing, software
sayzyas 43:78f328f311dc 11 * distributed under the License is distributed on an "AS IS" BASIS,
sayzyas 43:78f328f311dc 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sayzyas 43:78f328f311dc 13 * See the License for the specific language governing permissions and
sayzyas 43:78f328f311dc 14 * limitations under the License.
sayzyas 43:78f328f311dc 15 */
sayzyas 43:78f328f311dc 16
sayzyas 43:78f328f311dc 17 #include "USBHostSerial.h"
sayzyas 43:78f328f311dc 18
sayzyas 43:78f328f311dc 19 #if USBHOST_SERIAL
sayzyas 43:78f328f311dc 20
sayzyas 43:78f328f311dc 21 #include "dbg.h"
sayzyas 43:78f328f311dc 22
sayzyas 43:78f328f311dc 23 #define CHECK_INTERFACE(cls,subcls,proto) \
sayzyas 43:78f328f311dc 24 (((cls == 0xFF) && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */ || \
sayzyas 43:78f328f311dc 25 ((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ )
sayzyas 43:78f328f311dc 26
sayzyas 43:78f328f311dc 27 #if (USBHOST_SERIAL <= 1)
sayzyas 43:78f328f311dc 28
sayzyas 43:78f328f311dc 29 USBHostSerial::USBHostSerial()
sayzyas 43:78f328f311dc 30 {
sayzyas 43:78f328f311dc 31 host = USBHost::getHostInst();
sayzyas 43:78f328f311dc 32 ports_found = 0;
sayzyas 43:78f328f311dc 33 dev_connected = false;
sayzyas 43:78f328f311dc 34 }
sayzyas 43:78f328f311dc 35
sayzyas 43:78f328f311dc 36 bool USBHostSerial::connected()
sayzyas 43:78f328f311dc 37 {
sayzyas 43:78f328f311dc 38 return dev_connected;
sayzyas 43:78f328f311dc 39 }
sayzyas 43:78f328f311dc 40
sayzyas 43:78f328f311dc 41 void USBHostSerial::disconnect(void)
sayzyas 43:78f328f311dc 42 {
sayzyas 43:78f328f311dc 43 ports_found = 0;
sayzyas 43:78f328f311dc 44 dev = NULL;
sayzyas 43:78f328f311dc 45 }
sayzyas 43:78f328f311dc 46
sayzyas 43:78f328f311dc 47 bool USBHostSerial::connect() {
sayzyas 43:78f328f311dc 48
sayzyas 43:78f328f311dc 49 if (dev)
sayzyas 43:78f328f311dc 50 {
sayzyas 43:78f328f311dc 51 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
sayzyas 43:78f328f311dc 52 {
sayzyas 43:78f328f311dc 53 USBDeviceConnected* d = host->getDevice(i);
sayzyas 43:78f328f311dc 54 if (dev == d)
sayzyas 43:78f328f311dc 55 return true;
sayzyas 43:78f328f311dc 56 }
sayzyas 43:78f328f311dc 57 disconnect();
sayzyas 43:78f328f311dc 58 }
sayzyas 43:78f328f311dc 59 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
sayzyas 43:78f328f311dc 60 {
sayzyas 43:78f328f311dc 61 USBDeviceConnected* d = host->getDevice(i);
sayzyas 43:78f328f311dc 62 if (d != NULL) {
sayzyas 43:78f328f311dc 63
sayzyas 43:78f328f311dc 64 USB_DBG("Trying to connect serial device \r\n");
sayzyas 43:78f328f311dc 65 if(host->enumerate(d, this))
sayzyas 43:78f328f311dc 66 break;
sayzyas 43:78f328f311dc 67
sayzyas 43:78f328f311dc 68 USBEndpoint* bulk_in = d->getEndpoint(port_intf, BULK_ENDPOINT, IN);
sayzyas 43:78f328f311dc 69 USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT);
sayzyas 43:78f328f311dc 70 if (bulk_in && bulk_out)
sayzyas 43:78f328f311dc 71 {
sayzyas 43:78f328f311dc 72 USBHostSerialPort::connect(host,d,port_intf,bulk_in, bulk_out);
sayzyas 43:78f328f311dc 73 dev = d;
sayzyas 43:78f328f311dc 74 dev_connected = true;
sayzyas 43:78f328f311dc 75 }
sayzyas 43:78f328f311dc 76 }
sayzyas 43:78f328f311dc 77 }
sayzyas 43:78f328f311dc 78 return dev != NULL;
sayzyas 43:78f328f311dc 79 }
sayzyas 43:78f328f311dc 80
sayzyas 43:78f328f311dc 81 /*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
sayzyas 43:78f328f311dc 82 {
sayzyas 43:78f328f311dc 83 // we don't check VID/PID for MSD driver
sayzyas 43:78f328f311dc 84 }
sayzyas 43:78f328f311dc 85
sayzyas 43:78f328f311dc 86 /*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
sayzyas 43:78f328f311dc 87 {
sayzyas 43:78f328f311dc 88 if (!ports_found &&
sayzyas 43:78f328f311dc 89 CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
sayzyas 43:78f328f311dc 90 port_intf = intf_nb;
sayzyas 43:78f328f311dc 91 ports_found = true;
sayzyas 43:78f328f311dc 92 return true;
sayzyas 43:78f328f311dc 93 }
sayzyas 43:78f328f311dc 94 return false;
sayzyas 43:78f328f311dc 95 }
sayzyas 43:78f328f311dc 96
sayzyas 43:78f328f311dc 97 /*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
sayzyas 43:78f328f311dc 98 {
sayzyas 43:78f328f311dc 99 if (ports_found && (intf_nb == port_intf)) {
sayzyas 43:78f328f311dc 100 if (type == BULK_ENDPOINT)
sayzyas 43:78f328f311dc 101 return true;
sayzyas 43:78f328f311dc 102 }
sayzyas 43:78f328f311dc 103 return false;
sayzyas 43:78f328f311dc 104 }
sayzyas 43:78f328f311dc 105
sayzyas 43:78f328f311dc 106 #else // (USBHOST_SERIAL > 1)
sayzyas 43:78f328f311dc 107
sayzyas 43:78f328f311dc 108 //------------------------------------------------------------------------------
sayzyas 43:78f328f311dc 109
sayzyas 43:78f328f311dc 110 USBHostMultiSerial::USBHostMultiSerial()
sayzyas 43:78f328f311dc 111 {
sayzyas 43:78f328f311dc 112 host = USBHost::getHostInst();
sayzyas 43:78f328f311dc 113 dev = NULL;
sayzyas 43:78f328f311dc 114 memset(ports, NULL, sizeof(ports));
sayzyas 43:78f328f311dc 115 ports_found = 0;
sayzyas 43:78f328f311dc 116 dev_connected = false;
sayzyas 43:78f328f311dc 117 }
sayzyas 43:78f328f311dc 118
sayzyas 43:78f328f311dc 119 USBHostMultiSerial::~USBHostMultiSerial()
sayzyas 43:78f328f311dc 120 {
sayzyas 43:78f328f311dc 121 disconnect();
sayzyas 43:78f328f311dc 122 }
sayzyas 43:78f328f311dc 123
sayzyas 43:78f328f311dc 124 bool USBHostMultiSerial::connected()
sayzyas 43:78f328f311dc 125 {
sayzyas 43:78f328f311dc 126 return dev_connected;
sayzyas 43:78f328f311dc 127 }
sayzyas 43:78f328f311dc 128
sayzyas 43:78f328f311dc 129 void USBHostMultiSerial::disconnect(void)
sayzyas 43:78f328f311dc 130 {
sayzyas 43:78f328f311dc 131 for (int port = 0; port < USBHOST_SERIAL; port ++)
sayzyas 43:78f328f311dc 132 {
sayzyas 43:78f328f311dc 133 if (ports[port])
sayzyas 43:78f328f311dc 134 {
sayzyas 43:78f328f311dc 135 delete ports[port];
sayzyas 43:78f328f311dc 136 ports[port] = NULL;
sayzyas 43:78f328f311dc 137 }
sayzyas 43:78f328f311dc 138 }
sayzyas 43:78f328f311dc 139 ports_found = 0;
sayzyas 43:78f328f311dc 140 dev = NULL;
sayzyas 43:78f328f311dc 141 }
sayzyas 43:78f328f311dc 142
sayzyas 43:78f328f311dc 143 bool USBHostMultiSerial::connect() {
sayzyas 43:78f328f311dc 144
sayzyas 43:78f328f311dc 145 if (dev)
sayzyas 43:78f328f311dc 146 {
sayzyas 43:78f328f311dc 147 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
sayzyas 43:78f328f311dc 148 {
sayzyas 43:78f328f311dc 149 USBDeviceConnected* d = host->getDevice(i);
sayzyas 43:78f328f311dc 150 if (dev == d)
sayzyas 43:78f328f311dc 151 return true;
sayzyas 43:78f328f311dc 152 }
sayzyas 43:78f328f311dc 153 disconnect();
sayzyas 43:78f328f311dc 154 }
sayzyas 43:78f328f311dc 155 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
sayzyas 43:78f328f311dc 156 {
sayzyas 43:78f328f311dc 157 USBDeviceConnected* d = host->getDevice(i);
sayzyas 43:78f328f311dc 158 if (d != NULL) {
sayzyas 43:78f328f311dc 159
sayzyas 43:78f328f311dc 160 USB_DBG("Trying to connect serial device \r\n");
sayzyas 43:78f328f311dc 161 if(host->enumerate(d, this))
sayzyas 43:78f328f311dc 162 break;
sayzyas 43:78f328f311dc 163
sayzyas 43:78f328f311dc 164 for (int port = 0; port < ports_found; port ++)
sayzyas 43:78f328f311dc 165 {
sayzyas 43:78f328f311dc 166 USBEndpoint* bulk_in = d->getEndpoint(port_intf[port], BULK_ENDPOINT, IN);
sayzyas 43:78f328f311dc 167 USBEndpoint* bulk_out = d->getEndpoint(port_intf[port], BULK_ENDPOINT, OUT);
sayzyas 43:78f328f311dc 168 if (bulk_in && bulk_out)
sayzyas 43:78f328f311dc 169 {
sayzyas 43:78f328f311dc 170 ports[port] = new USBHostSerialPort();
sayzyas 43:78f328f311dc 171 if (ports[port])
sayzyas 43:78f328f311dc 172 {
sayzyas 43:78f328f311dc 173 ports[port]->connect(host,d,port_intf[port],bulk_in, bulk_out);
sayzyas 43:78f328f311dc 174 dev = d;
sayzyas 43:78f328f311dc 175 dev_connected = true;
sayzyas 43:78f328f311dc 176 }
sayzyas 43:78f328f311dc 177 }
sayzyas 43:78f328f311dc 178 }
sayzyas 43:78f328f311dc 179 }
sayzyas 43:78f328f311dc 180 }
sayzyas 43:78f328f311dc 181 return dev != NULL;
sayzyas 43:78f328f311dc 182 }
sayzyas 43:78f328f311dc 183
sayzyas 43:78f328f311dc 184 /*virtual*/ void USBHostMultiSerial::setVidPid(uint16_t vid, uint16_t pid)
sayzyas 43:78f328f311dc 185 {
sayzyas 43:78f328f311dc 186 // we don't check VID/PID for MSD driver
sayzyas 43:78f328f311dc 187 }
sayzyas 43:78f328f311dc 188
sayzyas 43:78f328f311dc 189 /*virtual*/ bool USBHostMultiSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
sayzyas 43:78f328f311dc 190 {
sayzyas 43:78f328f311dc 191 if ((ports_found < USBHOST_SERIAL) &&
sayzyas 43:78f328f311dc 192 CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
sayzyas 43:78f328f311dc 193 port_intf[ports_found++] = intf_nb;
sayzyas 43:78f328f311dc 194 return true;
sayzyas 43:78f328f311dc 195 }
sayzyas 43:78f328f311dc 196 return false;
sayzyas 43:78f328f311dc 197 }
sayzyas 43:78f328f311dc 198
sayzyas 43:78f328f311dc 199 /*virtual*/ bool USBHostMultiSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
sayzyas 43:78f328f311dc 200 {
sayzyas 43:78f328f311dc 201 if ((ports_found > 0) && (intf_nb == port_intf[ports_found-1])) {
sayzyas 43:78f328f311dc 202 if (type == BULK_ENDPOINT)
sayzyas 43:78f328f311dc 203 return true;
sayzyas 43:78f328f311dc 204 }
sayzyas 43:78f328f311dc 205 return false;
sayzyas 43:78f328f311dc 206 }
sayzyas 43:78f328f311dc 207
sayzyas 43:78f328f311dc 208 #endif
sayzyas 43:78f328f311dc 209
sayzyas 43:78f328f311dc 210 //------------------------------------------------------------------------------
sayzyas 43:78f328f311dc 211
sayzyas 43:78f328f311dc 212 #define SET_LINE_CODING 0x20
sayzyas 43:78f328f311dc 213
sayzyas 43:78f328f311dc 214 USBHostSerialPort::USBHostSerialPort(): circ_buf()
sayzyas 43:78f328f311dc 215 {
sayzyas 43:78f328f311dc 216 init();
sayzyas 43:78f328f311dc 217 }
sayzyas 43:78f328f311dc 218
sayzyas 43:78f328f311dc 219 void USBHostSerialPort::init(void)
sayzyas 43:78f328f311dc 220 {
sayzyas 43:78f328f311dc 221 host = NULL;
sayzyas 43:78f328f311dc 222 dev = NULL;
sayzyas 43:78f328f311dc 223 serial_intf = NULL;
sayzyas 43:78f328f311dc 224 size_bulk_in = 0;
sayzyas 43:78f328f311dc 225 size_bulk_out = 0;
sayzyas 43:78f328f311dc 226 bulk_in = NULL;
sayzyas 43:78f328f311dc 227 bulk_out = NULL;
sayzyas 43:78f328f311dc 228 line_coding.baudrate = 9600;
sayzyas 43:78f328f311dc 229 line_coding.data_bits = 8;
sayzyas 43:78f328f311dc 230 line_coding.parity = None;
sayzyas 43:78f328f311dc 231 line_coding.stop_bits = 1;
sayzyas 43:78f328f311dc 232 circ_buf.flush();
sayzyas 43:78f328f311dc 233 }
sayzyas 43:78f328f311dc 234
sayzyas 43:78f328f311dc 235 void USBHostSerialPort::connect(USBHost* _host, USBDeviceConnected * _dev,
sayzyas 43:78f328f311dc 236 uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out)
sayzyas 43:78f328f311dc 237 {
sayzyas 43:78f328f311dc 238 host = _host;
sayzyas 43:78f328f311dc 239 dev = _dev;
sayzyas 43:78f328f311dc 240 serial_intf = _serial_intf;
sayzyas 43:78f328f311dc 241 bulk_in = _bulk_in;
sayzyas 43:78f328f311dc 242 bulk_out = _bulk_out;
sayzyas 43:78f328f311dc 243
sayzyas 43:78f328f311dc 244 USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
sayzyas 43:78f328f311dc 245 dev->setName("Serial", serial_intf);
sayzyas 43:78f328f311dc 246 host->registerDriver(dev, serial_intf, this, &USBHostSerialPort::init);
sayzyas 43:78f328f311dc 247 baud(9600);
sayzyas 43:78f328f311dc 248 size_bulk_in = bulk_in->getSize();
sayzyas 43:78f328f311dc 249 size_bulk_out = bulk_out->getSize();
sayzyas 43:78f328f311dc 250 bulk_in->attach(this, &USBHostSerialPort::rxHandler);
sayzyas 43:78f328f311dc 251 bulk_out->attach(this, &USBHostSerialPort::txHandler);
sayzyas 43:78f328f311dc 252 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
sayzyas 43:78f328f311dc 253 }
sayzyas 43:78f328f311dc 254
sayzyas 43:78f328f311dc 255 void USBHostSerialPort::rxHandler() {
sayzyas 43:78f328f311dc 256 if (bulk_in) {
sayzyas 43:78f328f311dc 257 int len = bulk_in->getLengthTransferred();
sayzyas 43:78f328f311dc 258 if (bulk_in->getState() == USB_TYPE_IDLE) {
sayzyas 43:78f328f311dc 259 for (int i = 0; i < len; i++) {
sayzyas 43:78f328f311dc 260 circ_buf.queue(buf[i]);
sayzyas 43:78f328f311dc 261 }
sayzyas 43:78f328f311dc 262 rx.call();
sayzyas 43:78f328f311dc 263 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
sayzyas 43:78f328f311dc 264 }
sayzyas 43:78f328f311dc 265 }
sayzyas 43:78f328f311dc 266 }
sayzyas 43:78f328f311dc 267
sayzyas 43:78f328f311dc 268 void USBHostSerialPort::txHandler() {
sayzyas 43:78f328f311dc 269 if (bulk_out) {
sayzyas 43:78f328f311dc 270 if (bulk_out->getState() == USB_TYPE_IDLE) {
sayzyas 43:78f328f311dc 271 tx.call();
sayzyas 43:78f328f311dc 272 }
sayzyas 43:78f328f311dc 273 }
sayzyas 43:78f328f311dc 274 }
sayzyas 43:78f328f311dc 275
sayzyas 43:78f328f311dc 276 int USBHostSerialPort::_putc(int c) {
sayzyas 43:78f328f311dc 277 if (bulk_out) {
sayzyas 43:78f328f311dc 278 if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
sayzyas 43:78f328f311dc 279 return 1;
sayzyas 43:78f328f311dc 280 }
sayzyas 43:78f328f311dc 281 }
sayzyas 43:78f328f311dc 282 return -1;
sayzyas 43:78f328f311dc 283 }
sayzyas 43:78f328f311dc 284
sayzyas 43:78f328f311dc 285 void USBHostSerialPort::baud(int baudrate) {
sayzyas 43:78f328f311dc 286 line_coding.baudrate = baudrate;
sayzyas 43:78f328f311dc 287 format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
sayzyas 43:78f328f311dc 288 }
sayzyas 43:78f328f311dc 289
sayzyas 43:78f328f311dc 290 void USBHostSerialPort::format(int bits, Parity parity, int stop_bits) {
sayzyas 43:78f328f311dc 291 line_coding.data_bits = bits;
sayzyas 43:78f328f311dc 292 line_coding.parity = parity;
sayzyas 43:78f328f311dc 293 line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
sayzyas 43:78f328f311dc 294
sayzyas 43:78f328f311dc 295 // set line coding
sayzyas 43:78f328f311dc 296 host->controlWrite( dev,
sayzyas 43:78f328f311dc 297 USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
sayzyas 43:78f328f311dc 298 SET_LINE_CODING,
sayzyas 43:78f328f311dc 299 0, serial_intf, (uint8_t *)&line_coding, 7);
sayzyas 43:78f328f311dc 300 }
sayzyas 43:78f328f311dc 301
sayzyas 43:78f328f311dc 302 int USBHostSerialPort::_getc() {
sayzyas 43:78f328f311dc 303 uint8_t c = 0;
sayzyas 43:78f328f311dc 304 if (bulk_in == NULL) {
sayzyas 43:78f328f311dc 305 init();
sayzyas 43:78f328f311dc 306 return -1;
sayzyas 43:78f328f311dc 307 }
sayzyas 43:78f328f311dc 308 while (circ_buf.isEmpty());
sayzyas 43:78f328f311dc 309 circ_buf.dequeue(&c);
sayzyas 43:78f328f311dc 310 return c;
sayzyas 43:78f328f311dc 311 }
sayzyas 43:78f328f311dc 312
sayzyas 43:78f328f311dc 313 int USBHostSerialPort::writeBuf(const char* b, int s)
sayzyas 43:78f328f311dc 314 {
sayzyas 43:78f328f311dc 315 int c = 0;
sayzyas 43:78f328f311dc 316 if (bulk_out)
sayzyas 43:78f328f311dc 317 {
sayzyas 43:78f328f311dc 318 while (c < s)
sayzyas 43:78f328f311dc 319 {
sayzyas 43:78f328f311dc 320 int i = (s < size_bulk_out) ? s : size_bulk_out;
sayzyas 43:78f328f311dc 321 if (host->bulkWrite(dev, bulk_out, (uint8_t *)(b+c), i) == USB_TYPE_OK)
sayzyas 43:78f328f311dc 322 c += i;
sayzyas 43:78f328f311dc 323 }
sayzyas 43:78f328f311dc 324 }
sayzyas 43:78f328f311dc 325 return s;
sayzyas 43:78f328f311dc 326 }
sayzyas 43:78f328f311dc 327
sayzyas 43:78f328f311dc 328 int USBHostSerialPort::readBuf(char* b, int s)
sayzyas 43:78f328f311dc 329 {
sayzyas 43:78f328f311dc 330 int i = 0;
sayzyas 43:78f328f311dc 331 if (bulk_in)
sayzyas 43:78f328f311dc 332 {
sayzyas 43:78f328f311dc 333 for (i = 0; i < s; )
sayzyas 43:78f328f311dc 334 b[i++] = getc();
sayzyas 43:78f328f311dc 335 }
sayzyas 43:78f328f311dc 336 return i;
sayzyas 43:78f328f311dc 337 }
sayzyas 43:78f328f311dc 338
sayzyas 43:78f328f311dc 339 uint8_t USBHostSerialPort::available() {
sayzyas 43:78f328f311dc 340 return circ_buf.available();
sayzyas 43:78f328f311dc 341 }
sayzyas 43:78f328f311dc 342
sayzyas 43:78f328f311dc 343
sayzyas 43:78f328f311dc 344
sayzyas 43:78f328f311dc 345 #endif