BayEOS-Arduino  1.8.0_0.0.4
BayTCP.cpp
1 #include "BayTCP.h"
2 const char* const BayTCPInterface::_urlencodedChars="$&+,/:;=?@ <>#%{}|~[]`";
3 
4 const uint8_t* BayTCPInterface::parseMAC(const char* str){
5  uint8_t offset=0;
6  uint8_t delim=0;
7  while(str[offset]){
8  if(str[offset]=='-'){
9  delim=1;
10  break;
11  }
12  offset++;
13  }
14  if(! delim){
15  offset=0;
16  while(str[offset]){
17  if(str[offset]==':'){
18  delim=1;
19  break;
20  }
21  offset++;
22  }
23 
24  }
25  offset=0;
26  for(uint8_t i=0;i<6;i++){
27  _mac_ip[i]=(hex2int(str[offset])<<4)+hex2int(str[offset+1]);
28  // res[i]=0;
29  offset+=(2+delim);
30  }
31 
32  return _mac_ip;
33 
34 }
35 
36 uint8_t BayTCPInterface::hex2int(const char c){
37  if((c>='0') & (c<='9')) return c-'0';
38  if((c>='A') & (c<='F')) return c-'A'+10;
39  if((c>='a') & (c<='f')) return c-'a'+10;
40  return 0;
41 }
42 
43 const uint8_t* BayTCPInterface::parseIP(const char* str){
44  uint8_t offset=0;
45  for(uint8_t i=0;i<4;i++){
46  _mac_ip[i]=atoi(str+offset);
47  while(str[offset] && str[offset]!='.') offset++;
48  offset++;
49  }
50  return _mac_ip;
51 }
52 
53 void BayTCPInterface::printPGM(const char *str){
54  char c;
55  while (true) {
56  c=pgm_read_byte(str);
57  if (!c) break;
58 #if BayTCP_DEBUG_INPUT
59  Serial.write(c);
60 #endif
61 
62  write(c);
63  str++;
64  }
65 }
66 void BayTCPInterface::printlnPGM(const char *str){
67  printPGM(str);
68  println();
69 #if BayTCP_DEBUG_INPUT
70  Serial.println();
71 #endif
72 }
73 
74 void BayTCPInterface::skipChars(void){
75  do{
76  while(i_available()){
77  #if BayTCP_DEBUG_OUTPUT
78  Serial.print((char) read());
79 #else
80  read();
81 #endif
82 
83  }
84  delay(1);
85  } while(i_available());
86 
87 }
88 
89 
90 int BayTCPInterface::strlenURLencoded(const char *str){
91  if(! _urlencode) return strlen(str);
92  int count=0;
93  while(*str){
94  if(strchr(_urlencodedChars,*str)){
95  count+=3;
96  }
97  else count++;
98  str++;
99 
100  }
101  return count;
102 }
103 
104 void BayTCPInterface::printURLencoded(const char *str){
105  if(! _urlencode){
106  print(str);
107  return;
108  }
109  while(*str){
110  if(strchr(_urlencodedChars,*str)){
111  print('%');
112  print(*str,HEX);
113  } else
114  print(*str);
115  str++;
116  }
117 }
118 
119 
120 void BayTCPInterface::printPostHeader(uint16_t size){
121  printP("POST /");
122  print(_path);
123  printlnP(" HTTP/1.1");
124  printP("Authorization: Basic ");
125  strcpy(_pgm_buffer,_user);
126  strcat(_pgm_buffer,":");
127  strcat(_pgm_buffer,_password);
128  base64_encode(_base64buffer,(char*) _pgm_buffer,strlen(_pgm_buffer));
129  _base64buffer[base64_enc_len(strlen(_pgm_buffer))]=0;
130  println(_base64buffer); //BASE64
131 #if BayTCP_DEBUG_INPUT
132  Serial.println(_base64buffer);
133  //Serial.println(_pgm_buffer);
134  Serial.println();
135 #endif
136  printP("Host: ");
137 #if BayTCP_DEBUG_INPUT
138  Serial.println(_server);
139 #endif
140  println(_server);
141  printlnP("User-Agent: BayTCP");
142  printlnP("Content-Type: application/x-www-form-urlencoded");
143  printlnP("Connection: close");
144  printP("Content-Length: ");
145  println(size);
146 #if BayTCP_DEBUG_INPUT
147  Serial.println(size);
148 #endif
149  println();
150 }
151 
152 
153 uint8_t BayTCPInterface::sendMultiFromBuffer(uint16_t maxsize){
154  if(! _buffer->available()) return 0;
155  uint8_t res;
156  res=connect();
157  if(res){
158  _tx_error_count++;
159  return (res+2);
160  }
161 
162  uint16_t size;
163  unsigned long readpos=_buffer->readPos();
164 
165  //Guess size for the POST request:
166  //We need the size of the POST request for Content-Length. However ATMEGA cannot build up a
167  //several kb POST request in RAM. So we send a guess content length and fill up with dummy content
168  if(_buffer->available()>((unsigned long) maxsize)){
169  size=maxsize;
170  } else {
171  size=_buffer->available();
172  size*=2;
173  size+=30;//Double size and add 30 - This is just a guess. "bayeosframes[]=base64(frame)"
174  if(size<150) size=150; //To small sizes may cause a problem because "bayeosframe[]=" does not fit in...
175  size+=7+strlenURLencoded(_sender)+1+9+strlenURLencoded(_password);
176  if(size>maxsize) size=maxsize;
177  }
178  printPostHeader(size);
179  flushMTU();
180 
181  //Send Body - first part (sender)
182  printP("sender=");
183  printURLencoded(_sender);
184  printP("&password=");
185  printURLencoded(_password);
186  uint16_t postsize=7+strlenURLencoded(_sender)+1+9+strlenURLencoded(_password);
187  uint16_t mtusize=postsize;
188 
189  //Send Body - second part (frames)
190  uint8_t framesize;
191  while(postsize<(size-25) && readFromBuffer()){
192  if(_mtu && mtusize>_mtu){
193  flushMTU();
194  mtusize=0;
195  }
196  base64_encode(_base64buffer,(char*) _payload,getPacketLength());
197  _base64buffer[base64_enc_len(getPacketLength())]=0;
198  framesize=1+15+strlenURLencoded(_base64buffer);
199  postsize+=framesize;
200  if(postsize<=size){ //Still space in the POST for the frame
201  mtusize+=framesize;
202  printP("&bayeosframes[]=");
203  printURLencoded(_base64buffer);
204  _buffer->next();
205  } else { //Frame does not fitt in the POST
206  postsize-=framesize;
207  break;
208  }
209  }
210 
211  //Fill up with dummy content
212  while(postsize<size){
213  if(_mtu && mtusize>_mtu){
214  flushMTU();
215  mtusize=0;
216  }
217  print("&");
218  postsize++;
219  mtusize++;
220  }
221 
222  println();
223  println();
224  finishTransmissionMode();
225  res=wait_for("HTTP/1.1 200",30000);
226  if(res){
227  _buffer->seekReadPointer(readpos);
228  _tx_error_count++;
229 
230  }
231  else {
232  _tx_error_count=0;
233  delay(10);
234  }
235  skipChars();
236 
237  disconnect();
238  return res;
239 }
240 
241 
242 
244 #if BayTCP_DEBUG_OUTPUT
245  Serial.println("sendPayload");
246 #endif
247  uint8_t res;
248  res=connect();
249  if(res){
250  _tx_error_count++;
251  return (res+2);
252  }
253 
254  base64_encode(_base64buffer,(char*) _payload,getPacketLength());
255  _base64buffer[base64_enc_len(getPacketLength())]=0;
256 
257  uint8_t size=strlenURLencoded(_base64buffer);
258  size+=7+strlenURLencoded(_sender)+1+9+strlenURLencoded(_password)+1+15;
259 
260  printPostHeader(size);
261 
262  //Redo Base64 encoding! buffer is overwritten in printPostHeader!
263  base64_encode(_base64buffer,(char*) _payload,getPacketLength());
264  _base64buffer[base64_enc_len(getPacketLength())]=0;
265 
266  printP("sender=");
267  printURLencoded(_sender);
268  printP("&password=");
269  printURLencoded(_password);
270  printP("&bayeosframes[]=");
271  printURLencoded(_base64buffer); //BASE64
272  println();
273  println(); //was commented out - do we need??
274  finishTransmissionMode();
275  res=wait_for("HTTP/1.1 200",30000);
276  skipChars();
277  if(res) _tx_error_count++;
278  else _tx_error_count=0;
279  disconnect();
280  return res;
281 }
282 
283 
284 
285 
286 uint8_t BayTCPInterface::addToConfigBuffer(uint8_t offset,const char* str){
287  if(strlen(str)>BayTCP_CONFIG_SIZE -offset-1){
288  strncpy(_config_buffer+offset,str,BayTCP_CONFIG_SIZE -offset-1);
289  _config_buffer[BayTCP_CONFIG_SIZE -1]=0;
290  return BayTCP_CONFIG_SIZE -offset;
291  } else {
292  strcpy(_config_buffer+offset,str);
293  return strlen(str)+1;
294  }
295 }
296 
297 void BayTCPInterface::readConfigFromFile(const char *file){
298  SdFile _f;
299  _f.open(file, O_READ);
300  uint8_t i=0;
301  int c;
302  while((i<BayTCP_CONFIG_SIZE) && ((c=_f.read())!=-1)){
303 // Serial.print((char) c);
304  if(c=='|') c=0;
305  _config_buffer[i]=(char) c;
306  i++;
307  }
308  _f.close();
309  setConfigPointers();
310 }
311 
313  uint8_t offset=0;
314  while (offset<BayTCP_CONFIG_SIZE) {
315  _config_buffer[offset]=pgm_read_byte(string);
316  if (!_config_buffer[offset]) break;
317  if (_config_buffer[offset]=='|') _config_buffer[offset]=0;
318 #if BayTCP_DEBUG_INPUT
319  Serial.write(_config_buffer[offset]);
320 #endif
321  offset++;
322  string++;
323  }
324  setConfigPointers();
325 }
326 
328  if(EEPROM.read(eeoffset)==0xff){
329  //No valid config!!
330  return;
331  }
332  for(uint8_t i=0;i<BayTCP_CONFIG_SIZE;i++){
333  _config_buffer[i]=EEPROM.read(eeoffset+i);
334  }
335  setConfigPointers();
336 }
337 
339  for(uint8_t i=0;i<BayTCP_CONFIG_SIZE;i++){
340  EEPROM.write(eeoffset+i,_config_buffer[i]);
341  }
342 }
343 
344 const char* BayTCPInterface::getConfig(void){
345  return _config_buffer;
346 }
347 
348 char** BayTCPInterface::getConfigPointer(uint8_t index){
349  switch(index){
350  case BayTCP_CONFIG_SERVER:
351  return &_server;
352  break;
353  case BayTCP_CONFIG_PORT:
354  return &_port;
355  break;
356  case BayTCP_CONFIG_PATH:
357  return &_path;
358  break;
359  case BayTCP_CONFIG_USER:
360  return &_user;
361  break;
362  case BayTCP_CONFIG_PASSWORD:
363  return &_password;
364  break;
365  case BayTCP_CONFIG_SENDER:
366  return &_sender;
367  break;
368  case BayTCP_CONFIG_APN:
369  return &_apn;
370  break;
371  case BayTCP_CONFIG_PROVPW:
372  return &_prov_pw;
373  break;
374  case BayTCP_CONFIG_PROVUSER:
375  return &_prov_user;
376  break;
377  case BayTCP_CONFIG_PIN:
378  return &_pin;
379  break;
380  }
381  return 0;
382 
383 }
384 
385 void BayTCPInterface::setConfigPointers(void){
386  uint8_t offset=0;
387  _server=_config_buffer;
388  char** p;
389  for(uint8_t i=1;i<10;i++){
390  if(_config_buffer[offset])
391  offset+=strlen(_config_buffer+offset)+1;
392  else offset++;
393  p=getConfigPointer(i);
394  *p=_config_buffer+offset;
395  }
396 }
397 
398 void BayTCPInterface::setConfig(const char *str,uint8_t index){
399  memcpy(_base64buffer,_config_buffer,BayTCP_CONFIG_SIZE );
400  uint8_t offset=0;
401  uint8_t offset_old=0;
402 
403  for(uint8_t i=0;i<8;i++){
404  if(i==index)
405  offset+=addToConfigBuffer(offset,str);
406  else
407  offset+=addToConfigBuffer(offset,_base64buffer+offset_old);
408  offset_old+=strlen(_base64buffer+offset_old)+1;
409  }
410  setConfigPointers();
411 }
412 
413 
414 uint8_t BayTCPInterface::wait_for_available(uint16_t* timeout,int bytes){
415  while(i_available()<bytes){
416  delay(1);
417  (*timeout)--;
418  if(*timeout == 0){
419  return 2;
420  }
421  }
422  return 0;
423 
424 }
425 
426 
427 
428 uint8_t BayTCPInterface::wait_forOK(uint16_t timeout){
429  return wait_forPGM(PSTR("OK"),timeout);
430 }
431 
432 uint8_t BayTCPInterface::wait_forPGM(const char* str,uint16_t timeout,uint8_t bytes, char* buffer){
433  uint8_t length=0;
434  while (true) {
435  _pgm_buffer[length]=pgm_read_byte(str);
436  if (! _pgm_buffer[length]) break;
437  str++;
438  length++;
439  }
440 
441  if(wait_for_available(&timeout,length))
442  return 2;
443  uint8_t offset=0;
444  char c;
445  while(true){
446  if(wait_for_available(&timeout))
447  return 2;
448  c=read();
449 #if BayTCP_DEBUG_OUTPUT
450  Serial.print(c);
451 #endif
452 
453  if(offset<length){
454  if(c==_pgm_buffer[offset])
455  offset++;
456  else offset=0;
457 /* else if(offset>0){
458  skipChars();
459  return 1;
460  }*/
461  }
462 
463  if(offset==length){
464  if(bytes && buffer!=NULL){
465  if(wait_for_available(&timeout,bytes))
466  return 2;
467  offset=0;
468  while(offset<bytes){
469  buffer[offset]=read();
470  offset++;
471  }
472  buffer[offset]=0;
473  }
474  skipChars();
475  return 0;
476  }
477 
478  }
479 }
480 
481 
void seekReadPointer(unsigned long pos)
void readConfigFromStringPGM(const char *string)
Definition: BayTCP.cpp:312
virtual uint8_t connect(void)=0
void setConfig(const char *str, uint8_t index)
Definition: BayTCP.cpp:398
uint8_t getPacketLength(void) const
Definition: BayEOS.cpp:395
virtual void disconnect(void)=0
void readConfigFromEEPROM(int eeoffset=BayTCP_EEPROM_OFFSET)
Definition: BayTCP.cpp:327
void readConfigFromFile(const char *file)
Definition: BayTCP.cpp:297
boolean _urlencode
Definition: BayTCP.h:142
uint8_t sendMultiFromBuffer(uint16_t maxsize=5000)
Definition: BayTCP.cpp:153
void next(void)
char ** getConfigPointer(uint8_t index)
Definition: BayTCP.cpp:348
unsigned long available(void)
uint8_t sendPayload(void)
Definition: BayTCP.cpp:243
const char * getConfig(void)
Definition: BayTCP.cpp:344
uint8_t readFromBuffer(void)
Definition: BayEOS.cpp:308
void writeConfigToEEPROM(int eeoffset=BayTCP_EEPROM_OFFSET)
Definition: BayTCP.cpp:338