PHS module SMA-01 library. see: https://developer.mbed.org/users/phsfan/notebook/abitusbmodem/
Dependencies: Socket lwip-sys lwip
Dependents: AbitUSBModem_HTTPTest AbitUSBModem_MQTTTest AbitUSBModem_WebsocketTest AbitUSBModem_SMSTest
Fork of VodafoneUSBModem by
USBHostPhs/USBHostPhs.cpp
- Committer:
- phsfan
- Date:
- 2015-02-25
- Revision:
- 99:514e67a69ad6
- Parent:
- 97:7d9cc95e2ea7
File content as of revision 99:514e67a69ad6:
/* USBHostPhs.cpp */ /* Modified by 2015 phsfan * for ABIT SMA-01 */ /* mbed USBHost Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* WANDongle.cpp, WANDongleSerialPort.cpp */ /* Copyright (c) 2010-2012 mbed.org, MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define __DEBUG__ 0 #ifndef __MODULE__ #define __MODULE__ "USBHostPhs.cpp" #endif #include "core/dbg.h" #include <cstdint> #include "rtos.h" #include "USBHostPhs.h" #define CHECK_INTERFACE(cls,subcls,proto) \ (((cls == 0xFF) && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */ || \ ((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ ) USBHostPhs::USBHostPhs() { host = USBHost::getHostInst(); ports_found = 0; dev_connected = false; } bool USBHostPhs::connected() { return dev_connected; } void USBHostPhs::disconnect(void) { USBHostPhsPort::reset(); ports_found = 0; dev = NULL; } bool USBHostPhs::connect() { if (dev) { for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { USBDeviceConnected* d = host->getDevice(i); if (dev == d) return true; } disconnect(); } for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { USBDeviceConnected* d = host->getDevice(i); if (d != NULL) { USB_DBG("Trying to connect serial device \r\n"); if(host->enumerate(d, this)) break; DBG("Device has VID:%04x PID:%04x", d->getVid(), d->getPid()); if ((d->getVid() != PHS_VID) || (d->getPid() != PHS_PID)) break; USBEndpoint* bulk_in = d->getEndpoint(port_intf, BULK_ENDPOINT, IN); USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT); if (bulk_in && bulk_out) { USBHostPhsPort::connect(host,d,port_intf,bulk_in, bulk_out); dev = d; dev_connected = true; DBG("Device connected"); } } } return dev != NULL; } /*virtual*/ void USBHostPhs::setVidPid(uint16_t vid, uint16_t pid) { // we don't check VID/PID for MSD driver } /*virtual*/ bool USBHostPhs::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 { if (!ports_found && CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) { port_intf = intf_nb; ports_found = true; return true; } return false; } /*virtual*/ bool USBHostPhs::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used { if (ports_found && (intf_nb == port_intf)) { if (type == BULK_ENDPOINT) return true; } return false; } //------------------------------------------------------------------------------ #define SET_LINE_CODING 0x20 USBHostPhsPort::USBHostPhsPort() : cb_tx_en(false), cb_rx_en(false), listener(NULL) { init(); reset(); } void USBHostPhsPort::init(void) { host = NULL; dev = NULL; serial_intf = NULL; size_bulk_in = 0; size_bulk_out = 0; bulk_in = NULL; bulk_out = NULL; line_coding.baudrate = 921600; line_coding.data_bits = 8; line_coding.parity = None; line_coding.stop_bits = 1; } void USBHostPhsPort::connect(USBHost* _host, USBDeviceConnected * _dev, uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out) { host = _host; dev = _dev; serial_intf = _serial_intf; bulk_in = _bulk_in; bulk_out = _bulk_out; max_out_size = bulk_out->getSize(); if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE ) { max_out_size = WANDONGLE_MAX_OUTEP_SIZE; } USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf); dev->setName("Serial", serial_intf); host->registerDriver(dev, serial_intf, this, &USBHostPhsPort::init); baud(921600); size_bulk_in = bulk_in->getSize(); size_bulk_out = bulk_out->getSize(); bulk_in->attach(this, &USBHostPhsPort::rxHandler); bulk_out->attach(this, &USBHostPhsPort::txHandler); readPacket(); //Start receiving data } void USBHostPhsPort::rxHandler() { if (((USBEndpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success { buf_in_read_pos = 0; buf_in_len = ((USBEndpoint *) bulk_in)->getLengthTransferred(); //Update length //lock_rx.unlock(); rx_mtx.lock(); lock_rx = false; //Transmission complete if(cb_rx_en) { rx_mtx.unlock(); listener->readable(); //Call handler from the IRQ context //readPacket() should be called by the handler subsequently once the buffer has been emptied } else { cb_rx_pending = true; //Queue the callback rx_mtx.unlock(); } } else //Error, try reading again { //lock_rx.unlock(); DBG("Trying again"); readPacket(); } } void USBHostPhsPort::txHandler() { if (((USBEndpoint *) bulk_out)->getState() == USB_TYPE_IDLE) //Success { tx_mtx.lock(); buf_out_len = 0; //Reset length lock_tx = false; //Transmission complete //lock_tx.unlock(); if(cb_tx_en) { tx_mtx.unlock(); listener->writeable(); //Call handler from the IRQ context //writePacket() should be called by the handler subsequently once the buffer has been filled } else { cb_tx_pending = true; //Queue the callback tx_mtx.unlock(); } } else //Error, try reading again { //lock_tx.unlock(); writePacket(); } } void USBHostPhsPort::baud(int baudrate) { line_coding.baudrate = baudrate; format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits); } void USBHostPhsPort::format(int bits, Parity parity, int stop_bits) { line_coding.data_bits = bits; line_coding.parity = parity; line_coding.stop_bits = (stop_bits == 1) ? 0 : 2; // set line coding host->controlWrite( dev, USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, SET_LINE_CODING, 0, serial_intf, (uint8_t *)&line_coding, 7); } void USBHostPhsPort::reset() { tx_mtx.lock(); rx_mtx.lock(); buf_out_len = 0; max_out_size = 0; lock_tx = false; cb_tx_pending = false; buf_in_len = 0; buf_in_read_pos = 0; lock_rx = false; cb_rx_pending = false; tx_mtx.unlock(); rx_mtx.unlock(); } int USBHostPhsPort::readPacket() { DBG("Read packet on %p", this); rx_mtx.lock(); if(lock_rx) { ERR("Fail"); rx_mtx.unlock(); return -1; } if( bulk_in == NULL ) { WARN("Port is disconnected"); rx_mtx.unlock(); return -1; } lock_rx = true; //Receiving rx_mtx.unlock(); // DBG("readPacket"); //lock_rx.lock(); USB_TYPE res = host->bulkRead(dev, (USBEndpoint *)bulk_in, buf_in, ((USBEndpoint *)bulk_in)->getSize(), false); //Queue transfer #if __DEBUG__ >= 5 printf(" - bulkRead:"); for (int i = 0; i < buf_in_len; i ++) { if (buf_in[i] >= 0x20 && buf_in[i] < 0x7f) { printf(" %c", buf_in[i]); } else { printf(" %02x", buf_in[i]); } } printf("\r\n"); #endif if(res != USB_TYPE_PROCESSING) { //lock_rx.unlock(); ERR("host->bulkRead() returned %d", res); Thread::wait(100); return -1; } return 0; } int USBHostPhsPort::writePacket() { tx_mtx.lock(); if(lock_tx) { ERR("Fail"); tx_mtx.unlock(); return -1; } if( bulk_out == NULL ) { WARN("Port is disconnected"); tx_mtx.unlock(); return -1; } lock_tx = true; //Transmitting tx_mtx.unlock(); // DBG("writePacket"); //lock_tx.lock(); USB_TYPE res = host->bulkWrite(dev, (USBEndpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer #if __DEBUG__ >= 5 printf(" - bulkWrite:"); for (int i = 0; i < buf_out_len; i ++) { if (buf_out[i] >= 0x20 && buf_out[i] < 0x7f) { printf(" %c", buf_out[i]); } else { printf(" %02x", buf_out[i]); } } printf("\r\n"); #endif if(res != USB_TYPE_PROCESSING) { //lock_tx.unlock(); ERR("host->bulkWrite() returned %d", res); Thread::wait(100); return -1; } return 0; } int USBHostPhsPort::putc(int c) { tx_mtx.lock(); if(!lock_tx) { if(buf_out_len < max_out_size) { buf_out[buf_out_len] = (uint8_t)c; buf_out_len++; } } else { ERR("CAN'T WRITE!"); } tx_mtx.unlock(); return c; } int USBHostPhsPort::getc() { rx_mtx.lock(); int c = 0; if(!lock_rx) { if(buf_in_read_pos < buf_in_len) { c = (int)buf_in[buf_in_read_pos]; buf_in_read_pos++; } } else { ERR("CAN'T READ!"); } rx_mtx.unlock(); return c; } int USBHostPhsPort::readable() { rx_mtx.lock(); if (lock_rx) { rx_mtx.unlock(); return 0; } /* if( !lock_rx.trylock() ) { return 0; }*/ int res = buf_in_len - buf_in_read_pos; //lock_rx.unlock(); rx_mtx.unlock(); return res; } int USBHostPhsPort::writeable() { tx_mtx.lock(); if (lock_tx) { tx_mtx.unlock(); return 0; } /*if( !lock_tx.trylock() ) { return 0; }*/ int res = max_out_size - buf_out_len; tx_mtx.unlock(); //lock_tx.unlock(); return res; } void USBHostPhsPort::attach(IUSBHostSerialListener* pListener) { if(pListener == NULL) { setupIrq(false, IUSBHostSerial::RxIrq); setupIrq(false, IUSBHostSerial::TxIrq); } listener = pListener; if(pListener != NULL) { setupIrq(true, IUSBHostSerial::RxIrq); setupIrq(true, IUSBHostSerial::TxIrq); } } void USBHostPhsPort::setupIrq(bool en, IUSBHostSerial::IrqType irq /*= RxIrq*/) { switch(irq) { case IUSBHostSerial::RxIrq: rx_mtx.lock(); cb_rx_en = en; if(en && cb_rx_pending) { cb_rx_pending = false; rx_mtx.unlock(); listener->readable(); //Process the interrupt that was raised } else { rx_mtx.unlock(); } break; case IUSBHostSerial::TxIrq: tx_mtx.lock(); cb_tx_en = en; if(en && cb_tx_pending) { cb_tx_pending = false; tx_mtx.unlock(); listener->writeable(); //Process the interrupt that was raised } else { tx_mtx.unlock(); } break; } }