source: rtos_arduino/trunk/arduino_lib/hardware/arduino/samd/libraries/GSM/src/GSM3SoftSerial.cpp@ 175

Last change on this file since 175 was 175, checked in by ertl-honda, 8 years ago

ライブラリを Arduino IDE 1.7.9 にupdate

File size: 9.6 KB
Line 
1/*
2This file is part of the GSM3 communications library for Arduino
3-- Multi-transport communications platform
4-- Fully asynchronous
5-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1
6-- Voice calls
7-- SMS
8-- TCP/IP connections
9-- HTTP basic clients
10
11This library has been developed by Telefónica Digital - PDI -
12- Physical Internet Lab, as part as its collaboration with
13Arduino and the Open Hardware Community.
14
15September-December 2012
16
17This library is free software; you can redistribute it and/or
18modify it under the terms of the GNU Lesser General Public
19License as published by the Free Software Foundation; either
20version 2.1 of the License, or (at your option) any later version.
21
22This library is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25Lesser General Public License for more details.
26
27You should have received a copy of the GNU Lesser General Public
28License along with this library; if not, write to the Free Software
29Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30
31The latest version of this library can always be found at
32https://github.com/BlueVia/Official-Arduino
33*/
34#include "GSM3SoftSerial.h"
35#include <WInterrupts.h>
36#include <HardwareSerial.h>
37#include <Arduino.h>
38
39#define __XON__ 0x11
40#define __XOFF__ 0x13
41
42#define _GSMSOFTSERIALFLAGS_ESCAPED_ 0x01
43#define _GSMSOFTSERIALFLAGS_SENTXOFF_ 0x02
44
45//
46// Lookup table
47//
48#define __PARAGRAPHGUARD__ 50
49typedef struct _DELAY_TABLE
50{
51 long baud;
52 unsigned short rx_delay_centering;
53 unsigned short rx_delay_intrabit;
54 unsigned short rx_delay_stopbit;
55 unsigned short tx_delay;
56} DELAY_TABLE;
57
58
59static const DELAY_TABLE PROGMEM table[] =
60{
61 // baud rxcenter rxintra rxstop tx
62 { 115200, 2, 6, 8, 8, },
63 { 57600, 6, 15, 17, 17, },
64 { 38400, 11, 24, 26, 26, },
65 { 31250, 14, 30, 32, 32, },
66 { 28800, 15, 32, 34, 34, },
67 { 19200, 24, 50, 52, 52, },
68 { 14400, 32, 67, 69, 69, },
69 { 9600, 50, 102, 104, 104, },
70 { 4800, 102, 206, 208, 208, },
71 { 2400, 206, 414, 416, 416, },
72 { 1200, 414, 831, 833, 833, },
73 { 300, 1664, 3331, 3333, 3333, },
74};
75
76//const int XMIT_START_ADJUSTMENT = 5;
77
78
79GSM3SoftSerial* GSM3SoftSerial::_activeObject=0;
80
81GSM3SoftSerial::GSM3SoftSerial():
82 _rx_delay_centering(0),
83 _rx_delay_intrabit(0),
84 _rx_delay_stopbit(0),
85 _tx_delay(0),
86 cb(this)
87{
88
89 //comStatus=0;
90 //waitingAnswer=false;
91}
92
93int GSM3SoftSerial::begin(long speed)
94{
95 _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;
96 setTX();
97 setRX();
98 for (unsigned i=0; i<sizeof(table)/sizeof(table[0]); ++i)
99 {
100 long baud = pgm_read_dword(&table[i].baud);
101 if (baud == speed)
102 {
103 _rx_delay_centering = pgm_read_word(&table[i].rx_delay_centering);
104 _rx_delay_intrabit = pgm_read_word(&table[i].rx_delay_intrabit);
105 _rx_delay_stopbit = pgm_read_word(&table[i].rx_delay_stopbit);
106 _tx_delay = pgm_read_word(&table[i].tx_delay);
107 break;
108 }
109 }
110
111 if (_rx_delay_stopbit)
112 {
113 if (digitalPinToInterrupt(4))
114 {
115 attachInterrupt(4, handle_interrupt, FALLING);
116 }
117 delayMicroseconds(_tx_delay); // if we were low this establishes the end
118 }
119
120 _activeObject=this;
121
122}
123
124void GSM3SoftSerial::close()
125 {
126 _activeObject=0;
127 }
128
129size_t GSM3SoftSerial::write(uint8_t c)
130{
131 if (_tx_delay == 0)
132 return 0;
133
134 // Characters to be escaped under XON/XOFF control with Quectel
135 if(c==0x11)
136 {
137 this->finalWrite(0x77);
138 return this->finalWrite(0xEE);
139 }
140
141 if(c==0x13)
142 {
143 this->finalWrite(0x77);
144 return this->finalWrite(0xEC);
145 }
146
147 if(c==0x77)
148 {
149 this->finalWrite(0x77);
150 return this->finalWrite(0x88);
151 }
152
153 return this->finalWrite(c);
154}
155
156size_t GSM3SoftSerial::finalWrite(uint8_t c)
157{
158
159 // turn off interrupts for a clean txmit
160 EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( 4 ));
161
162
163 // Write the start bit
164 tx_pin_write(LOW);
165 delayMicroseconds(_tx_delay);// + XMIT_START_ADJUSTMENT);
166
167 // Write each of the 8 bits
168 for (byte mask = 0x01; mask; mask <<= 1)
169 {
170 if (c & mask) // choose bit
171 tx_pin_write(HIGH); // send 1
172 else
173 tx_pin_write(LOW); // send 0
174 delayMicroseconds(_tx_delay);
175 }
176
177 tx_pin_write(HIGH); // restore pin to natural state
178
179 // turn interrupts back on
180 EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( 4 ));
181 delayMicroseconds(_tx_delay);
182
183 return 1;
184}
185
186 /*inline*/ void GSM3SoftSerial::tunedDelay(uint16_t delay) {
187 __asm__ __volatile__(
188 "1: \n"
189 " sub %0, #1 \n" // substract 1 from %0 (n)
190 " bne 1b \n" // if result is not 0 jump to 1
191 : "+r" (delay) // '%0' is n variable with RW constraints
192 : // no input
193 : // no clobber
194 );
195 }
196
197void GSM3SoftSerial::tx_pin_write(uint8_t pin_state)
198{
199 // Direct port manipulation is faster than digitalWrite/Read
200 if (pin_state == LOW)
201 _transmitPortRegister->reg &= ~_transmitBitMask;
202 else
203 _transmitPortRegister->reg |= _transmitBitMask;
204}
205
206void GSM3SoftSerial::setTX()
207{
208 pinMode(3, OUTPUT);
209 digitalWrite(3, HIGH);
210 // For digital port direct manipulation
211 _transmitBitMask = digitalPinToBitMask(3);
212 PortGroup * port = digitalPinToPort(3);
213 _transmitPortRegister = portOutputRegister(port);
214}
215
216void GSM3SoftSerial::setRX()
217{
218 pinMode(4, INPUT);
219 digitalWrite(4, HIGH); // pullup for normal logic!
220 // For digital port direct manipulation
221 _receiveBitMask = digitalPinToBitMask(4);
222 PortGroup * port = digitalPinToPort(4);
223 _receivePortRegister = portInputRegister(port);
224}
225
226void GSM3SoftSerial::handle_interrupt()
227{
228 if(_activeObject)
229 _activeObject->recv();
230}
231
232uint32_t GSM3SoftSerial::rx_pin_read()
233{
234 // Digital port manipulation
235 return _receivePortRegister->reg & digitalPinToBitMask(4);
236}
237
238void GSM3SoftSerial::recv()
239{
240
241 bool firstByte=true;
242 byte thisHead;
243
244 uint8_t d = 0;
245 bool morebytes=false;
246 //bool fullbuffer=(cb.availableBytes()<3);
247 bool fullbuffer;
248 bool capturado_fullbuffer = 0;
249 int i;
250 byte oldTail;
251
252 // If RX line is high, then we don't see any start bit
253 // so interrupt is probably not for us
254 if (!rx_pin_read())
255 {
256 do
257 {
258 oldTail=cb.getTail();
259 // Wait approximately 1/2 of a bit width to "center" the sample
260 delayMicroseconds(_rx_delay_centering);
261
262 fullbuffer=(cb.availableBytes()<6);
263
264
265 if(fullbuffer&&(!capturado_fullbuffer))
266 tx_pin_write(LOW);
267
268
269 // Read each of the 8 bits
270 for (uint8_t i=0x1; i; i <<= 1)
271 {
272 delayMicroseconds(_rx_delay_intrabit);
273 uint8_t noti = ~i;
274 if (rx_pin_read())
275 d |= i;
276 else // else clause added to ensure function timing is ~balanced
277 d &= noti;
278 if(fullbuffer&&(!capturado_fullbuffer))
279 {
280 if((uint8_t)__XOFF__ & i)
281 tx_pin_write(HIGH);
282 else
283 tx_pin_write(LOW);
284 }
285 }
286
287 if(fullbuffer&&(!capturado_fullbuffer))
288 {
289 delayMicroseconds(_rx_delay_intrabit);
290 tx_pin_write(HIGH);
291 }
292
293 // So, we know the buffer is full, and we have sent a XOFF
294 if (fullbuffer)
295 {
296 capturado_fullbuffer =1;
297 _flags |=_GSMSOFTSERIALFLAGS_SENTXOFF_;
298 }
299
300
301 // skip the stop bit
302 if (!fullbuffer) delayMicroseconds(_rx_delay_stopbit);
303 if(keepThisChar(&d))
304 {
305 cb.write(d);
306 if(firstByte)
307 {
308 firstByte=false;
309 thisHead=cb.getTail();
310 }
311 }
312
313
314 // This part is new. It is used to detect the end of a "paragraph"
315 // Caveat: the old fashion would let processor a bit of time between bytes,
316 // that here is lost
317 // This active waiting avoids drifting
318 morebytes=false;
319 // TO-DO. This PARAGRAPHGUARD is empyric. We should test it for every speed
320 for(i=0;i<__PARAGRAPHGUARD__;i++)
321 {
322 delayMicroseconds(1);
323 if(!rx_pin_read())
324 {
325 morebytes=true;
326 break;
327 }
328 }
329 }while(morebytes);
330 // If we find a line feed, we are at the end of a paragraph
331 // check!
332
333 if (fullbuffer)
334 {
335 // And... go handle it!
336 if(mgr)
337 mgr->manageMsg(thisHead, cb.getTail());
338 }
339 else if(d==10)
340 {
341 // And... go handle it!
342 if(mgr)
343 mgr->manageMsg(thisHead, cb.getTail());
344 }
345 else if (d==32)
346 {
347 // And... go handle it!
348 if(mgr)
349 mgr->manageMsg(thisHead, cb.getTail());
350 }
351 }
352
353}
354
355bool GSM3SoftSerial::keepThisChar(uint8_t* c)
356{
357 // Horrible things for Quectel XON/XOFF
358 // 255 is the answer to a XOFF
359 // It comes just once
360 if((*c==255)&&(_flags & _GSMSOFTSERIALFLAGS_SENTXOFF_))
361 {
362 _flags ^= _GSMSOFTSERIALFLAGS_SENTXOFF_;
363 return false;
364 }
365
366 // 0x77, w, is the escape character
367 if(*c==0x77)
368 {
369 _flags |= _GSMSOFTSERIALFLAGS_ESCAPED_;
370 return false;
371 }
372
373 // and these are the escaped codes
374 if(_flags & _GSMSOFTSERIALFLAGS_ESCAPED_)
375 {
376 if(*c==0xEE)
377 *c=0x11;
378 else if(*c==0xEC)
379 *c=0x13;
380 else if(*c==0x88)
381 *c=0x77;
382
383 _flags ^= _GSMSOFTSERIALFLAGS_ESCAPED_;
384 return true;
385 }
386
387 return true;
388}
389
390void GSM3SoftSerial::spaceAvailable()
391{
392 // If there is spaceAvailable in the buffer, lets send a XON
393 finalWrite((byte)__XON__);
394}
395
396
397// This is here to avoid problems with Arduino compiler
398void GSM3SoftSerialMgr::manageMsg(byte from, byte to){};
Note: See TracBrowser for help on using the repository browser.