UbloxUSBCDMAModem.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /* UbloxUSBCDMAModem.cpp */
  2. /* Copyright (C) 2012 mbed.org, MIT License
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  5. * and associated documentation files (the "Software"), to deal in the Software without restriction,
  6. * including without limitation the rights to use, copy, modify, merge, publish, distribute,
  7. * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in all copies or
  11. * substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
  14. * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  16. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. */
  19. #define __DEBUG__ 4
  20. #ifndef __MODULE__
  21. #define __MODULE__ "UbloxUSBCDMAModem.cpp"
  22. #endif
  23. #include "core/fwk.h"
  24. #include "UbloxUSBCDMAModem.h"
  25. #include "UbloxCDMAModemInitializer.h"
  26. #include "USBHost.h"
  27. #define USE_ONE_PORT 1
  28. UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
  29. m_stream(m_dongle.getSerial(serial)),
  30. m_at(&m_stream),
  31. m_sms(&m_at), m_ppp(&m_stream),
  32. m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
  33. m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
  34. {
  35. USBHost* host = USBHost::getHostInst();
  36. m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
  37. if( m_powerGatingPin != NC )
  38. {
  39. power(false); //Dongle will have to be powered on manually
  40. }
  41. }
  42. class CSSProcessor : public IATCommandsProcessor
  43. {
  44. public:
  45. CSSProcessor() : status(STATUS_REGISTERING)
  46. {
  47. }
  48. enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
  49. REGISTERING_STATUS getStatus()
  50. {
  51. return status;
  52. }
  53. private:
  54. virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
  55. {
  56. char b;
  57. char bc[3] = "";
  58. int sid = 99999;
  59. //if( sscanf(line, "%*d, %c", &r) == 1 )
  60. if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
  61. {
  62. if(strcmp("Z", bc) == 0)
  63. status = STATUS_REGISTERING;
  64. else
  65. status = STATUS_OK;
  66. }
  67. return OK;
  68. }
  69. virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
  70. {
  71. return OK;
  72. }
  73. volatile REGISTERING_STATUS status;
  74. };
  75. int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* password)
  76. {
  77. if( !m_ipInit )
  78. {
  79. m_ipInit = true;
  80. m_ppp.init();
  81. }
  82. m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
  83. int ret = init();
  84. if(ret)
  85. {
  86. return ret;
  87. }
  88. #if USE_ONE_PORT
  89. m_smsInit = false; //SMS status reset
  90. //m_ussdInit = false; //USSD status reset
  91. //m_linkMonitorInit = false; //Link monitor status reset
  92. #endif
  93. ATCommandsInterface::ATResult result;
  94. if(apn != NULL)
  95. {
  96. char cmd[48];
  97. sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
  98. ret = m_at.executeSimple(cmd, &result);
  99. DBG("Result of command: Err code=%d", ret);
  100. DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
  101. DBG("APN set to %s", apn);
  102. }
  103. //Connect
  104. DBG("Connecting");
  105. #if USE_ONE_PORT
  106. m_at.close(); // Closing AT parser
  107. m_atOpen = false; //Will need to be reinitialized afterwards
  108. #endif
  109. DBG("Connecting PPP");
  110. ret = m_ppp.connect();
  111. DBG("Result of connect: Err code=%d", ret);
  112. return ret;
  113. }
  114. int UbloxUSBCDMAModem::disconnect()
  115. {
  116. DBG("Disconnecting from PPP");
  117. int ret = m_ppp.disconnect();
  118. if(ret)
  119. {
  120. ERR("Disconnect returned %d, still trying to disconnect", ret);
  121. }
  122. //Ugly but leave dongle time to recover
  123. Thread::wait(500);
  124. #if USE_ONE_PORT
  125. ATCommandsInterface::ATResult result;
  126. DBG("Starting AT thread");
  127. ret = m_at.open();
  128. if(ret)
  129. {
  130. return ret;
  131. }
  132. #endif
  133. DBG("Trying to hangup");
  134. #if 0 //Does not appear to work
  135. int tries = 10;
  136. do
  137. {
  138. ret = m_at.executeSimple("+++", &result, 1000);
  139. DBG("Result of command: Err code=%d\n", ret);
  140. DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
  141. } while(tries-- && ret);
  142. if(!ret)
  143. {
  144. ret = m_at.executeSimple("ATH", &result);
  145. DBG("Result of command: Err code=%d\n", ret);
  146. DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
  147. }
  148. #endif
  149. #if USE_ONE_PORT
  150. //Reinit AT parser
  151. ret = m_at.init();
  152. DBG("Result of command: Err code=%d\n", ret);
  153. if(ret)
  154. {
  155. m_at.close(); // Closing AT parser
  156. DBG("AT Parser closed, could not complete disconnection");
  157. return NET_TIMEOUT;
  158. }
  159. #if 0
  160. m_at.close(); // Closing AT parser
  161. DBG("AT Parser closed");
  162. #endif
  163. #endif
  164. return OK;
  165. }
  166. int UbloxUSBCDMAModem::sendSM(const char* number, const char* message)
  167. {
  168. int ret = init();
  169. if(ret)
  170. {
  171. return ret;
  172. }
  173. if(!m_smsInit)
  174. {
  175. ret = m_sms.init();
  176. if(ret)
  177. {
  178. return ret;
  179. }
  180. m_smsInit = true;
  181. }
  182. ret = m_sms.send(number, message);
  183. if(ret)
  184. {
  185. return ret;
  186. }
  187. return OK;
  188. }
  189. int UbloxUSBCDMAModem::getSM(char* number, char* message, size_t maxLength)
  190. {
  191. int ret = init();
  192. if(ret)
  193. {
  194. return ret;
  195. }
  196. if(!m_smsInit)
  197. {
  198. ret = m_sms.init();
  199. if(ret)
  200. {
  201. return ret;
  202. }
  203. m_smsInit = true;
  204. }
  205. ret = m_sms.get(number, message, maxLength);
  206. if(ret)
  207. {
  208. return ret;
  209. }
  210. return OK;
  211. }
  212. int UbloxUSBCDMAModem::getSMCount(size_t* pCount)
  213. {
  214. int ret = init();
  215. if(ret)
  216. {
  217. return ret;
  218. }
  219. if(!m_smsInit)
  220. {
  221. ret = m_sms.init();
  222. if(ret)
  223. {
  224. return ret;
  225. }
  226. m_smsInit = true;
  227. }
  228. ret = m_sms.getCount(pCount);
  229. if(ret)
  230. {
  231. return ret;
  232. }
  233. return OK;
  234. }
  235. ATCommandsInterface* UbloxUSBCDMAModem::getATCommandsInterface()
  236. {
  237. return &m_at;
  238. }
  239. int UbloxUSBCDMAModem::power(bool enable)
  240. {
  241. if( m_powerGatingPin == NC )
  242. {
  243. return NET_INVALID; //A pin name has not been provided in the constructor
  244. }
  245. if(!enable) //Will force components to re-init
  246. {
  247. cleanup();
  248. }
  249. DigitalOut powerGatingOut(m_powerGatingPin);
  250. powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
  251. return OK;
  252. }
  253. bool UbloxUSBCDMAModem::power()
  254. {
  255. if( m_powerGatingPin == NC )
  256. {
  257. return true; //Assume power is always on
  258. }
  259. DigitalOut powerGatingOut(m_powerGatingPin);
  260. return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
  261. }
  262. int UbloxUSBCDMAModem::init()
  263. {
  264. if( !m_dongleConnected )
  265. {
  266. if(!power())
  267. {
  268. //Obviously cannot initialize the dongle if it is disconnected...
  269. ERR("Power is off");
  270. return NET_INVALID;
  271. }
  272. m_dongleConnected = true;
  273. while( !m_dongle.connected() )
  274. {
  275. m_dongle.tryConnect();
  276. Thread::wait(100);
  277. }
  278. }
  279. if(m_atOpen)
  280. {
  281. return OK;
  282. }
  283. DBG("Starting AT thread if needed");
  284. int ret = m_at.open();
  285. if(ret)
  286. {
  287. return ret;
  288. }
  289. DBG("Sending initialisation commands");
  290. ret = m_at.init();
  291. if(ret)
  292. {
  293. return ret;
  294. }
  295. if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
  296. {
  297. INFO("Using a UBLOX C200 Dongle");
  298. }
  299. else
  300. {
  301. WARN("Using an Unknown Dongle");
  302. }
  303. ATCommandsInterface::ATResult result;
  304. //Wait for network registration
  305. CSSProcessor cssProcessor;
  306. do
  307. {
  308. DBG("Waiting for network registration");
  309. ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
  310. DBG("Result of command: Err code=%d\n", ret);
  311. DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
  312. if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
  313. {
  314. Thread::wait(3000);
  315. }
  316. } while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
  317. m_atOpen = true;
  318. return OK;
  319. }
  320. int UbloxUSBCDMAModem::cleanup()
  321. {
  322. if(m_ppp.isConnected())
  323. {
  324. WARN("Data connection is still open"); //Try to encourage good behaviour from the user
  325. m_ppp.disconnect();
  326. }
  327. m_smsInit = false;
  328. // m_linkMonitorInit = false;
  329. //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
  330. if(m_atOpen)
  331. {
  332. m_at.close();
  333. m_atOpen = false;
  334. }
  335. m_dongle.disconnect();
  336. m_dongleConnected = false;
  337. return OK;
  338. }