]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxUSBCDMAModem.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / net / cellular / UbloxUSBModem / UbloxUSBCDMAModem.cpp
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
20 #define __DEBUG__ 4
21 #ifndef __MODULE__
22 #define __MODULE__ "UbloxUSBCDMAModem.cpp"
23 #endif
24
25 #include "core/fwk.h"
26
27 #include "UbloxUSBCDMAModem.h"
28 #include "UbloxCDMAModemInitializer.h"
29 #include "USBHost.h"
30
31 #define USE_ONE_PORT 1
32
33 UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
34 m_stream(m_dongle.getSerial(serial)), 
35 m_at(&m_stream),
36 m_sms(&m_at), m_ppp(&m_stream),
37 m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
38 m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
39 {
40   USBHost* host = USBHost::getHostInst();
41   m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
42   if( m_powerGatingPin != NC )
43   {
44     power(false); //Dongle will have to be powered on manually
45   }
46 }
47
48 class CSSProcessor : public IATCommandsProcessor
49 {
50 public:
51   CSSProcessor() : status(STATUS_REGISTERING)
52   {
53
54   }
55   enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
56   REGISTERING_STATUS getStatus()
57   {
58     return status;
59   }
60 private:
61   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
62   {
63     char b;
64                 char bc[3] = "";
65                 int sid = 99999; 
66                 
67     //if( sscanf(line, "%*d, %c", &r) == 1 )
68     if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
69                 {
70                                 if(strcmp("Z", bc) == 0)
71                                         status = STATUS_REGISTERING;
72                                 else
73                                         status = STATUS_OK;
74     }
75     return OK;
76   }
77   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
78   {
79     return OK;
80   }
81   volatile REGISTERING_STATUS status;
82 };
83
84 int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* password)
85 {
86   if( !m_ipInit )
87   {
88     m_ipInit = true;
89     m_ppp.init();
90   }
91   m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
92
93   int ret = init();
94   if(ret)
95   {
96     return ret;
97   }
98
99   #if USE_ONE_PORT
100   m_smsInit = false; //SMS status reset
101   //m_ussdInit = false; //USSD status reset
102   //m_linkMonitorInit = false; //Link monitor status reset
103   #endif
104
105   ATCommandsInterface::ATResult result;
106
107   if(apn != NULL)
108   {
109     char cmd[48];
110     sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
111     ret = m_at.executeSimple(cmd, &result);
112     DBG("Result of command: Err code=%d", ret);
113     DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
114     DBG("APN set to %s", apn);
115   }
116
117
118   //Connect
119   DBG("Connecting");
120   #if USE_ONE_PORT
121   m_at.close(); // Closing AT parser
122   m_atOpen = false; //Will need to be reinitialized afterwards
123   #endif
124
125   DBG("Connecting PPP");
126
127   ret = m_ppp.connect();
128   DBG("Result of connect: Err code=%d", ret);
129   return ret;
130 }
131
132
133 int UbloxUSBCDMAModem::disconnect()
134 {
135   DBG("Disconnecting from PPP");
136   int ret = m_ppp.disconnect();
137   if(ret)
138   {
139     ERR("Disconnect returned %d, still trying to disconnect", ret);
140   }
141
142   //Ugly but leave dongle time to recover
143   Thread::wait(500);
144
145   #if USE_ONE_PORT
146   ATCommandsInterface::ATResult result;
147   DBG("Starting AT thread");
148   ret = m_at.open();
149   if(ret)
150   {
151     return ret;
152   }
153   #endif
154
155   DBG("Trying to hangup");
156
157   #if 0 //Does not appear to work
158   int tries = 10;
159   do
160   {
161     ret = m_at.executeSimple("+++", &result, 1000);
162     DBG("Result of command: Err code=%d\n", ret);
163     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
164   } while(tries-- && ret);
165   if(!ret)
166   {
167     ret = m_at.executeSimple("ATH", &result);
168     DBG("Result of command: Err code=%d\n", ret);
169     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
170   }
171   #endif
172
173   #if USE_ONE_PORT
174   //Reinit AT parser
175   ret = m_at.init();
176   DBG("Result of command: Err code=%d\n", ret);
177   if(ret)
178   {
179     m_at.close(); // Closing AT parser
180     DBG("AT Parser closed, could not complete disconnection");
181     return NET_TIMEOUT;
182   }
183
184   #if 0
185   m_at.close(); // Closing AT parser
186   DBG("AT Parser closed");
187   #endif
188   #endif
189   return OK;
190 }
191
192 int UbloxUSBCDMAModem::sendSM(const char* number, const char* message)
193 {
194   int ret = init();
195   if(ret)
196   {
197     return ret;
198   }
199
200   if(!m_smsInit)
201   {
202     ret = m_sms.init();
203     if(ret)
204     {
205       return ret;
206     }
207     m_smsInit = true;
208   }
209
210   ret = m_sms.send(number, message);
211   if(ret)
212   {
213     return ret;
214   }
215
216   return OK;
217 }
218
219 int UbloxUSBCDMAModem::getSM(char* number, char* message, size_t maxLength)
220 {
221   int ret = init();
222   if(ret)
223   {
224     return ret;
225   }
226
227   if(!m_smsInit)
228   {
229     ret = m_sms.init();
230     if(ret)
231     {
232       return ret;
233     }
234     m_smsInit = true;
235   }
236
237   ret = m_sms.get(number, message, maxLength);
238   if(ret)
239   {
240     return ret;
241   }
242
243   return OK;
244 }
245
246 int UbloxUSBCDMAModem::getSMCount(size_t* pCount)
247 {
248   int ret = init();
249   if(ret)
250   {
251     return ret;
252   }
253
254   if(!m_smsInit)
255   {
256     ret = m_sms.init();
257     if(ret)
258     {
259       return ret;
260     }
261     m_smsInit = true;
262   }
263
264   ret = m_sms.getCount(pCount);
265   if(ret)
266   {
267     return ret;
268   }
269
270   return OK;
271 }
272
273 ATCommandsInterface* UbloxUSBCDMAModem::getATCommandsInterface()
274 {
275   return &m_at;
276 }
277
278 int UbloxUSBCDMAModem::power(bool enable)
279 {
280   if( m_powerGatingPin == NC )
281   {
282     return NET_INVALID; //A pin name has not been provided in the constructor
283   }
284
285   if(!enable) //Will force components to re-init
286   {
287     cleanup();
288   }
289   
290   DigitalOut powerGatingOut(m_powerGatingPin);
291   powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
292
293   return OK;
294 }
295
296 bool UbloxUSBCDMAModem::power()
297 {
298   if( m_powerGatingPin == NC )
299   {
300     return true; //Assume power is always on 
301   }
302   
303   DigitalOut powerGatingOut(m_powerGatingPin);
304   return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
305 }
306
307 int UbloxUSBCDMAModem::init()
308 {
309   if( !m_dongleConnected )
310   {
311     if(!power())
312     {
313       //Obviously cannot initialize the dongle if it is disconnected...
314       ERR("Power is off");
315       return NET_INVALID;
316     }
317     m_dongleConnected = true;
318     while( !m_dongle.connected() )
319     {
320       m_dongle.tryConnect();
321       Thread::wait(100);
322     }
323   }
324
325   if(m_atOpen)
326   {
327     return OK;
328   }
329
330   DBG("Starting AT thread if needed");
331   int ret = m_at.open();
332   if(ret)
333   {
334     return ret;
335   }
336
337   DBG("Sending initialisation commands");
338   ret = m_at.init();
339   if(ret)
340   {
341     return ret;
342   }
343
344  if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
345   {
346     INFO("Using a UBLOX C200 Dongle");
347   }
348   else
349   {
350     WARN("Using an Unknown Dongle");
351   }
352
353   ATCommandsInterface::ATResult result;
354
355   //Wait for network registration
356   CSSProcessor cssProcessor;
357   do
358   {
359     DBG("Waiting for network registration");
360     ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
361     DBG("Result of command: Err code=%d\n", ret);
362     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
363     if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
364     {
365       Thread::wait(3000);
366     }
367   } while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
368
369   m_atOpen = true;
370
371   return OK;
372 }
373
374 int UbloxUSBCDMAModem::cleanup()
375 {
376   if(m_ppp.isConnected())
377   {
378     WARN("Data connection is still open"); //Try to encourage good behaviour from the user
379     m_ppp.disconnect(); 
380   }
381   
382   m_smsInit = false;
383 //  m_linkMonitorInit = false;
384   //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
385   
386   if(m_atOpen)
387   {
388     m_at.close();
389     m_atOpen = false;
390   }
391   
392   m_dongle.disconnect();
393   m_dongleConnected = false;
394   
395   return OK;
396 }
397
398