Browse code

2017-11-27 update

fractalxaos authored on 11/28/2017 01:35:42
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,995 +0,0 @@
1
-/*
2
- Background Radiation Monitor - Web Server
3
- 
4
- A simple web server that makes available to clients over the Internet
5
- readings from a MightyOhm Geiger counter. The MightyOhm is connected to
6
- an Arduino Uno with attached Ethernet shield.  This software module
7
- runs on the Arduino Uno an embedded HTTP server by which Internet
8
- applications can query the MightyOhm for Geiger counter readings.
9
- Also, this software runs a Network Time Protocol (NTP) client, that
10
- periodically synchronizes the local system clock to network time.
11
- Included is a simple command line interface that may be used to change the
12
- network interface IP address, NTP server address, or configure a
13
- verbose output mode.
14
- 
15
- Copyright 2014 Jeff Owrey
16
-    This program is free software: you can redistribute it and/or modify
17
-    it under the terms of the GNU General Public License as published by
18
-    the Free Software Foundation, either version 3 of the License, or
19
-    (at your option) any later version.
20
-
21
-    This program is distributed in the hope that it will be useful,
22
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
23
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
-    GNU General Public License for more details.
25
-
26
-    You should have received a copy of the GNU General Public License
27
-    along with this program.  If not, see http://www.gnu.org/license.
28
- 
29
- Circuit:
30
- * Main components: Arduino Uno, Ethernet shield, Mighty Ohm Geiger counter
31
- * Ethernet shield attached to pins 10, 11, 12, 13
32
- * In order to allow the MightyOhm to operate on the Uno's 5 volt power
33
-   supply, and thus make the MightyOhm's serial output compatible with the
34
-   Uno, the following has to be done (see MightyOhm schematic):
35
-     1. Change R6 to 1K Ohm.
36
-     2. Change R11 to 330 Ohm.
37
-     3. Connect +5v from the Uno to MightyOhm J6 pin 1.
38
-     4. Connect GND from the Uno to MightyOhm J6 pin 3.
39
-     5. Connect D5 from the Uno to MightyOhm J7 pin 5.
40
-   
41
- Misc Notes:
42
-   As of this release the Uno's SRAM gets entirely maxed out by
43
-   this program.  Any modifications to this program that requires
44
-   additional memory seriously entails the risk that the modifications
45
-   will cause the program to become un-stable.
46
-   
47
- Revision History:  
48
-   * v10 released 25 Feb 2014 by J L Owrey
49
-   * v11 released 24 Jun 2014 by J L Owrey
50
-       - optimization of processRxByte function to conserve SRAM
51
-       - removal of non-used function code
52
-       - defaults to APIPA IP address in the event a DHCP address
53
-         cannot be obtained
54
-   * v12 released 20 Dec 2014 by J L Owrey
55
-       - removed Timestamp global variable to make more dynamic
56
-         memory available for local variables
57
-       - optimized clock network synch algorithm
58
-       - optimized serial update algorithm
59
-   * v13 released 22 Jul 2015 by J L Owrey
60
-       - add use of "F" function to store constant strings in
61
-         program flash memory in order to save SRAM space
62
-   * v14 released 19 Aug 2015 by J L Owrey
63
-       - add ability to respond to web a client request with either
64
-         a JSON compatible string or a standard HTML document
65
-*/
66
-
67
-/***  PREPROCESSOR DEFINES  ***/
68
-
69
-/*
70
- Define the header and version number displayed at startup
71
- and also by the 'view settings' command.
72
-*/
73
-#define STARTUP_HEADER "\n\rRadmon v1.4 (c) 2015"
74
-#define RADMON_VERSION "v1.4"
75
-/*
76
- The following define sets the MAC address of the device.  This
77
- address is a permanent attribute of the device's Ethernet interface,
78
- and never, ever, should be changed.  This address was provided
79
- by the Arduino Ethernet shield manufacturer for use with this
80
- specific instance of the Ethernet shield.  This MAC address should
81
- be shown on a label affixed to the device housing.
82
-*/
83
-#define ETHERNET_MAC_ADDRESS 0x90, 0xA2, 0xDA, 0x0D, 0x84, 0xF6
84
-/*
85
- The following defines an APIPA default address in the event that
86
- DHCP mode is ON and a DHCP address cannot be obtained.
87
-*/
88
-#define DEFAULT_APIPA_IP_ADDRESS "169.254.100.10"
89
-/*
90
- The following defines set the period of a 'heartbeat' string sent
91
- out over the device's USB port.  This heartbeat consists of a serial
92
- data string containing the current radiation reading and GM time.
93
-*/
94
-#define SERIAL_UPDATE_INTERVAL 30000  //milli-seconds
95
-#define VERBOSE_SERIAL_UPDATE_INTERVAL 10000  //milli-seconds
96
-/*
97
- The following define sets the port number the HTTP service will use to
98
- listen for requests from Internet clients.  Normally HTTP requests use
99
- port 80.
100
-*/
101
-#define HTTP_SERVER_PORT 80
102
-/*
103
- The following defines are for configuring a local NTP client
104
- for synchronizing the local system clock to network time.
105
- Note that the default setting is the IP address of the following
106
- time server:
107
-              time-a.timefreq.bldrdoc.gov
108
-*/
109
-#define DEFAULT_NTP_SERVER_IP_ADDR "132.163.4.101"
110
-#define NTP_PORT 8888
111
-#define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message
112
-/*
113
- The following defines how often the system clock gets synchronized
114
- to network time.
115
-*/
116
-#define NET_SYNCH_INTERVAL 43200 //number in seconds
117
-/*
118
- The following defines the size of the buffer space required for the
119
- serial data string from the Mighty Ohm Geiger counter.  The serial
120
- data string is defined as the text from newline character to newline
121
- character.
122
-*/
123
-#define MIGHTYOHM_DATA_STRING_LENGTH 65
124
-/*
125
- The beginning of the MightyOhm data string always begins with the
126
- same three characters.  These three characters determine the 
127
- beginning of a new line of data from the MightyOhm.
128
-*/
129
-#define MIGHTYOHM_DATA_STRING_HEADER "CPS"
130
-
131
-/***  LIBRARY MODULES USED  ***/
132
-
133
-#include <Time.h>
134
-#include <SPI.h>         
135
-#include <Ethernet.h>
136
-#include <EthernetUdp.h>
137
-#include <SoftwareSerial.h>
138
-#include <EEPROM.h>;
139
-
140
-/***  GLOBAL DECLARATIONS ***/
141
-
142
-/*
143
- Create and initialize a mac address object for the Ethernet interface. 
144
-*/
145
-byte mac[] = { ETHERNET_MAC_ADDRESS };
146
-/*
147
- Create and initialize an HTTP server object.  The object is initialized
148
- to the TCP port the HTTP server will use to listen for clients.
149
-*/
150
-EthernetServer httpServer(HTTP_SERVER_PORT);
151
-/*
152
- Create a UDP client object for sending packets to
153
- and receiveing packets from an NTP time server.
154
-*/
155
-EthernetUDP Udp;
156
-/*
157
- Create a software serial port for receiving serial data from
158
- the MightyOhm. Note that the Uno pin 5 receives serial data
159
- FROM the MightyOhm.  The Uno's pin 6 is not used, as there is
160
- no need to send serial data to the MightyOhm. 
161
-*/
162
-SoftwareSerial MightyOhmTxOut(5, 6);
163
-/*
164
- Create global variables to store the MightOhm data, next heartbeat
165
- time, and next synchronization time.
166
-*/
167
-char MightyOhmData[MIGHTYOHM_DATA_STRING_LENGTH + 1];
168
-unsigned long SerialUpdateTime;
169
-time_t NextClockSynchTime;
170
-/*
171
- Create global variables to store the verbose mode state (ON or OFF)
172
- and the IP address mode state (static or DHCP).
173
-*/
174
-boolean bVerbose;
175
-boolean bUseDHCP;
176
-/*
177
- Create and initialize global arrays to hold the current IP address
178
- and the NTP server IP address.
179
-*/
180
-byte ipAddr[4] = {};
181
-byte ntpip[4] = {};
182
-
183
-/*** SYSTEM STARTUP  ***/
184
-
185
-void setup()
186
-{
187
-  /*
188
-   Open serial communications to and from the Uno's USB port.
189
-  */
190
-  Serial.begin(9600);
191
-  /* 
192
-   Print to the USB port a header showing Radmon
193
-   version of this program and the copyright notice.
194
-  */
195
-  Serial.println(F(STARTUP_HEADER));
196
-  /*
197
-    Get the system configuration from EEPROM.
198
-  */
199
-  readSettingsFromEEPROM();
200
-  /*
201
-   Start up the Ethernet interface using either a static or
202
-   DHCP supplied address (depending on stored system configuration).
203
-  */
204
-  Serial.println(F("Configuring network interface..."));
205
-  if(bUseDHCP)
206
-  {
207
-    if ( Ethernet.begin(mac) == 0 )
208
-    {
209
-      /* DHCP not responding so use APIPA address */
210
-      parseIpAddress(ipAddr, DEFAULT_APIPA_IP_ADDRESS);
211
-      Ethernet.begin(mac, ipAddr);
212
-      Serial.println(F("DHCP failed - using APIPA"));
213
-    }
214
-    else
215
-    {
216
-      Serial.print(F("DHCP supplied IP: "));
217
-      Serial.println(Ethernet.localIP());
218
-    }
219
-  }
220
-  else
221
-  {
222
-    Ethernet.begin(mac, ipAddr);
223
-  }
224
-  /*
225
-   Start up NTP client service.
226
-  */
227
-  Udp.begin(NTP_PORT);
228
-  /*
229
-    Synchronize the system clock to network time.
230
-  */
231
-  synchronizeSystemClock();
232
-  /*
233
-   Start up the HTTP server.
234
-  */
235
-  Serial.println(F("Starting HTTP server..."));
236
-  httpServer.begin();
237
-  /*
238
-    Open serial communications to the MightyOhm device.
239
-  */  
240
-  MightyOhmTxOut.begin(9600);
241
-   /*
242
-    Initialize initial time for sending out the hearbeat string. Normally
243
-    the system clock will be at approx 3200 msec at this point. So allow
244
-    some additional time for data to accumulate in MightyOhm data buffer.
245
-  */
246
-  SerialUpdateTime = millis() + 2000;
247
-  /*
248
-   Initialize MightyOhm data string to empty.
249
-  */
250
-  MightyOhmData[0] = 0;
251
-  return;
252
-}
253
-
254
-/*** MAIN LOOP ***/
255
-
256
-void loop()
257
-{
258
-  /*
259
-   Check for user keyboard 'c' pressed.  This character switches
260
-   to command mode.
261
-  */   
262
-  if ( Serial.available() )
263
-  {
264
-    // get incoming byte
265
-    if(Serial.read() == 'c')
266
-    {
267
-      commandMode();
268
-    }
269
-  }  
270
-  /*
271
-    Poll serial input buffer from MightyOhm for new data and 
272
-    process received bytes to form a complete data string.
273
-  */
274
-  while ( MightyOhmTxOut.available() )
275
-  {
276
-    processRxByte( MightyOhmTxOut.read() );
277
-  }
278
-  /*
279
-    Every so often send a 'heartbeat' string to the USB port.
280
-    The heartbeat consists of UTC time stamp and current data
281
-    from the MightyOhm Geiger counter.
282
-  */
283
-  if ( millis() > SerialUpdateTime )
284
-  {
285
-    Serial.println( MightyOhmData );
286
-    /* Set the time for the next heartbeat pulse to go out. */
287
-    SerialUpdateTime = millis() +  \
288
-                       (bVerbose ? VERBOSE_SERIAL_UPDATE_INTERVAL :  \ 
289
-                                    SERIAL_UPDATE_INTERVAL);
290
-  }
291
-  /*
292
-   Listen for and and process requests from HTTP clients.
293
-  */  
294
-  listenForEthernetClients();
295
-  /*
296
-   Periodically synchronize local system clock to time
297
-   provided by NTP time server.
298
-  */
299
-  if ( now() > NextClockSynchTime )
300
-  {
301
-    synchronizeSystemClock();
302
-  }
303
-  return;
304
-}
305
-
306
-/*
307
- Synchronize the local system clock to
308
- network time provided by NTP time server.
309
-*/
310
-void synchronizeSystemClock()
311
-{
312
-  byte count;
313
-  
314
-  Serial.println(F("Synchronizing with network time server..."));
315
-    
316
-  for(count = 0; count < 3; count++)  // Attempt to synchronize 3 times
317
-  {
318
-    if(syncToNetworkTime() == 1)
319
-    {
320
-      //  Synchronization successful
321
-      break;
322
-    }
323
-    delay(1000);
324
-  } /* end for */ 
325
-  if(count == 3) {
326
-    Serial.println(F("synch failed"));
327
-  }
328
-  /* 
329
-   Set the time for the next network NTP
330
-   time synchronization to occur.
331
-  */
332
-  NextClockSynchTime = now() + NET_SYNCH_INTERVAL;
333
-  return;
334
-}
335
-
336
-/*
337
-  Handle HTTP GET requests from an HTTP client.
338
-*/  
339
-void listenForEthernetClients()
340
-{
341
-  char sBuffer[14];
342
-  byte i;
343
-  byte iMode;
344
-  char c, d;
345
-  
346
-  // listen for incoming clients
347
-  EthernetClient client = httpServer.available();
348
-  if (client) {
349
-    if (bVerbose) Serial.print("\n");
350
-    Serial.println(F("client request"));
351
-    i = 0;
352
-    sBuffer[0] = 0;
353
-    iMode = 0;
354
-    d = 0;
355
-  
356
-    while(client.connected() && client.available()) {
357
-      c = client.read();
358
-      /*
359
-       * The end of an HTTP client request is always signaled by a
360
-       * blank line, that is, by two consecutive line feed and carriage 
361
-       * return characters "\r\n\r\n".  The following two lines of code 
362
-       * look for this condition.
363
-       */
364
-      if(c == '\n' && d == '\n') break; //end of HTTP client request
365
-      if (c != '\r') d = c; // ignore carriage return characters
366
-
367
-      if (bVerbose) {
368
-        Serial.write(c);
369
-      }
370
-      // prevent buffer overruns
371
-      if (i < 13) {
372
-        sBuffer[i++] = c;
373
-        sBuffer[i] = 0;
374
-      }
375
-      // request for JSON string response
376
-      if(strcmp(sBuffer, "GET /rdata ") == 0) {
377
-        iMode = 1;
378
-      }
379
-      // request for standard HTML document
380
-      if(strcmp(sBuffer, "GET / ") == 0) {
381
-        iMode = 2;
382
-      }
383
-    }
384
-    /*
385
-     Send a standard HTTP response header to the
386
-     client's GET request.
387
-    */
388
-    client.println(F("HTTP/1.1 200 OK\n"        \
389
-                   "Content-Type: text/html\n"  \
390
-                   "Connnection: close\n"       \
391
-                   "\n"                         \
392
-                   ));
393
-                   
394
-    switch (iMode) {
395
-      case 0:
396
-        // Respond to an invalid URL received from the client
397
-        client.print(F("<!DOCTYPE html>\n" \
398
-                       "<html><head><title>DIY Radmon</title></head>"  \
399
-                       "<body><h2>Invalid URL</h2>" \
400
-                       "<p>You have reached a server at an unknown URL.</p>" \
401
-                       "<p>If you think you made this call in error,<br>" \
402
-                       "please hangup and try your call again.</p>" \
403
-                       "</body></html>"));
404
-        break;
405
-      case 1:
406
-        transmitJson(client);
407
-        break;
408
-      case 2:
409
-        transmitWebPage(client);
410
-        break;
411
-    }
412
-    // give the web browser time to receive the data
413
-    delay(5);
414
-    // close the connection:
415
-    client.stop();
416
-    if (bVerbose) {
417
-      Serial.print(F("client disconnected\r\n\n"));
418
-    }
419
-  }
420
-  return;
421
-}
422
-
423
-/*
424
- Send to the client the MightyOhm Geiger counter's
425
- current readings, embedded in an HTML document.
426
-*/
427
-void transmitWebPage(EthernetClient client)
428
-{
429
-  char strBuffer[MIGHTYOHM_DATA_STRING_LENGTH];
430
-
431
-  strcpy(strBuffer, MightyOhmData);
432
-  /*
433
-   * Send the actual HTML page the user will see in their web
434
-   * browser.
435
-  */
436
-  client.print(F("<!DOCTYPE html>\n" \
437
-                 "<html><head><title>DIY Radmon</title>"  \
438
-                 "<style>pre{font-size:140%;}</style>" \
439
-                 "</head><body><h2>DIY Radiation Monitor</h2>" \
440
-                 "<p><a href=\"http://intravisions.com/radmon/\">" \
441
-                 "<i>intravisions.com</i></a></p><hr>" \
442
-                 "<p><pre>UTC&#9;"));
443
-  /* Data Items */
444
-  client.print(strtok(strBuffer, " "));
445
-  client.print(F(" "));
446
-  client.print(strtok(NULL, ", "));
447
-  client.print(F("<br>"));
448
-  client.print(strtok(NULL, ", "));
449
-  client.print(F("&#9;"));
450
-  client.print(strtok(NULL, ", "));
451
-  client.print(F("<br>"));
452
-  client.print(strtok(NULL, ", "));
453
-  client.print(F("&#9;"));
454
-  client.print(strtok(NULL, ", "));
455
-  client.print(F("<br>"));
456
-  client.print(strtok(NULL, ", "));
457
-  client.print(F("&#9;"));
458
-  client.print(strtok(NULL, ", "));
459
-  client.print(F("<br>"));
460
-  client.print(F("Mode&#9;"));
461
-  client.print(strtok(NULL, ", "));
462
-  client.print(F("<br></pre></p></body></html>"));
463
-  return;
464
-}  
465
-
466
-/*
467
- Send to the client the MightyOhm Geiger counter's
468
- current readings, embedded in a JSON compatible string.
469
-*/
470
-void transmitJson(EthernetClient client) {
471
-  char strBuffer[MIGHTYOHM_DATA_STRING_LENGTH];
472
-
473
-  strcpy(strBuffer, MightyOhmData);
474
-  /*
475
-   * Format and transmit a JSON compatible data string.
476
-   */
477
-  client.print(F("$,UTC="));
478
-  client.print(strtok(strBuffer, " "));
479
-  client.print(F(" "));
480
-  client.print(strtok(NULL, ", "));
481
-  client.print(F(","));
482
-  client.print(strtok(NULL, ", "));
483
-  client.print(F("="));
484
-  client.print(strtok(NULL, ", "));
485
-  client.print(F(","));
486
-  client.print(strtok(NULL, ", "));
487
-  client.print(F("="));
488
-  client.print(strtok(NULL, ", "));
489
-  client.print(F(","));
490
-  client.print(strtok(NULL, ", "));
491
-  client.print(F("="));
492
-  client.print(strtok(NULL, ", "));
493
-  client.print(F(","));
494
-  client.print(F("Mode="));
495
-  client.print(strtok(NULL, ", "));
496
-  client.print(F(",#"));
497
-  return;
498
-}
499
-
500
-/*
501
-   Process bytes received from the MightyOhm Geiger counter,
502
-   one at a time, to create a well formed string.
503
-*/
504
-void processRxByte( char RxByte )
505
-{
506
-  static char readBuffer[MIGHTYOHM_DATA_STRING_LENGTH];
507
-  static byte cIndex = 0;
508
-  
509
-  /*
510
-     Discard carriage return characters.
511
-  */
512
-  if (RxByte == '\r')
513
-  {
514
-    return;
515
-  }
516
-  /*
517
-   A new line character indicates the line of data from
518
-   the MightyOhm is complete and can be written to the
519
-   MightyOhm data buffer.
520
-  */
521
-  else if (RxByte == '\n')
522
-  {
523
-    /*
524
-     First copy the timestamp to the MightyOhm data buffer. The "CPS"
525
-     characters are not preserved in the temporary read buffer, so
526
-     restore them to the MightyOhm data buffer, as well.
527
-    */
528
-    sprintf( MightyOhmData, "%d:%02d:%02d %d/%d/%d, %s",       \
529
-          hour(), minute(), second(), month(), day(), year(),  \
530
-          MIGHTYOHM_DATA_STRING_HEADER );
531
-    /*
532
-     Now copy the rest of the data in the temporary read buffer to the
533
-     MightyOhm data buffer.
534
-    */ 
535
-    strcat(MightyOhmData, readBuffer);
536
-    /*
537
-     Flush the temporary read buffer.
538
-    */
539
-    cIndex = 0;
540
-    readBuffer[0] = 0;
541
-    return;
542
-  }
543
-  /* 
544
-   A new line of data will always have "CPS" as the first
545
-   three characters.  Therefore, when these characters occur in
546
-   sequence, the read buffer should begin collecting characters.
547
-   This is a kluge to deal with an inherent problem in the Software
548
-   Serial library implementation that results in characters dropped
549
-   from the software serial stream buffer.
550
-  */
551
-  if( strstr(readBuffer, MIGHTYOHM_DATA_STRING_HEADER) > 0 ) 
552
-  {
553
-    cIndex = 0;
554
-  }
555
-  /*
556
-   Read characters into a temporary buffer until
557
-   the line of data is complete or the buffer is full.
558
-  */
559
-  if(cIndex < MIGHTYOHM_DATA_STRING_LENGTH)
560
-  {
561
-    readBuffer[cIndex] = RxByte;
562
-    cIndex += 1;
563
-    readBuffer[cIndex] = 0;
564
-  }
565
-  return;
566
-} 
567
-
568
-/* 
569
-  Send a UDP request packet to an NTP time server and listen for a reply.
570
-  When the reply arrives, parse the received UPD packet and compute unix
571
-  epoch time.  Then set the local system clock to the epoch time.
572
-*/
573
-int syncToNetworkTime()
574
-{
575
-  /*
576
-   Send a request to the NTP time server.
577
-  */
578
-  byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold outgoing and incoming packets 
579
-  /*
580
-   Send an NTP packet to the time server and allow for network lag
581
-   before checking if a reply is available.
582
-  */
583
-  sendNTPpacket(packetBuffer);
584
-  delay(2000);  // allow 2000 milli-seconds for network lag
585
-
586
-  /*
587
-   Wait for response from NTP time server.
588
-  */
589
-  if ( Udp.parsePacket() )
590
-  {  
591
-    /*
592
-     A UDP packet has arrived, so read the data from it.
593
-    */
594
-    Udp.read( packetBuffer, NTP_PACKET_SIZE );
595
-    /*
596
-     The timestamp starts at byte 40 of the received packet and is four bytes,
597
-     or two words, long. First, esxtract the two words.
598
-    */
599
-    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
600
-    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
601
-    /*  
602
-     Combine the four bytes (two words) into a long integer
603
-     this is NTP time (seconds since Jan 1 1900).
604
-    */
605
-    unsigned long secsSince1900 = highWord << 16 | lowWord;
606
-    /*  
607
-     Now convert NTP time into UTC time.  Note that
608
-     Unix time starts on Jan 1 1970. In seconds,
609
-     that's 2208988800.  Therfore,
610
-     
611
-         epoch = secsSince1900 - 2208988800UL
612
-         
613
-     Set the local system clock with this value.
614
-    */
615
-    setTime(secsSince1900 - 2208988800UL);
616
-    return 1;
617
-  }
618
-  else
619
-  {
620
-    return 0;
621
-  } /* end if */
622
-}
623
-
624
-/*
625
-  Send an NTP request to the NTP time server.
626
-*/
627
-void sendNTPpacket( byte* packetBuffer )
628
-{
629
-  /*
630
-   Set all bytes in the buffer to 0.
631
-  */
632
-  memset( packetBuffer, 0, NTP_PACKET_SIZE );
633
-  /*
634
-   Initialize values needed to form NTP request.
635
-  */
636
-  packetBuffer[0] = 0b11100011;  // LI, Version, Mode
637
-  packetBuffer[1] = 0;           // Stratum, or type of clock
638
-  packetBuffer[2] = 6;           // Polling Interval
639
-  packetBuffer[3] = 0xEC;        // Peer Clock Precision
640
-  /*
641
-   Set the remaining 8 bytes to zero for Root Delay & Root Dispersion.
642
-  */
643
-  packetBuffer[12]  = 49; 
644
-  packetBuffer[13]  = 0x4E;
645
-  packetBuffer[14]  = 49;
646
-  packetBuffer[15]  = 52;
647
-  /*
648
-   All NTP fields have been given values, so now
649
-   send a packet requesting a timestamp.
650
-  */ 		
651
-  Udp.beginPacket( ntpip, 123 ); //NTP requests are to port 123
652
-  Udp.write( packetBuffer, NTP_PACKET_SIZE );
653
-  Udp.endPacket();
654
-  return;
655
-}
656
-
657
-/***  COMMAND LINE INTERFACE  ***/
658
-
659
-/*
660
- Print a command menu to the USB port.  Then wait for a
661
- response from the user.  When the response has been
662
- received, execute the command.
663
-*/
664
-void commandMode()
665
-{
666
-  char sCmdBuf[2];
667
-  
668
-  getCurrentIP();  //used for display of settings
669
-  
670
-  while(true)
671
-  {
672
-    /*
673
-     Print the menu.
674
-    */
675
-    Serial.print( F("\n"                         \
676
-                  "1 - view settings\r\n"        \
677
-                  "2 - set IP address\r\n"       \
678
-                  "3 - set NTP server\r\n"       \
679
-                  "4 - toggle verbose\r\n"       \
680
-                  "5 - exit without saving\r\n"  \
681
-                  "6 - save & restart\r\n"       \
682
-                  ">"));
683
-    /*
684
-     Get the command from the user.
685
-    */
686
-    getSerialLine(sCmdBuf, 2);
687
-    Serial.print(F("\n\n\r"));
688
-    /* 
689
-     Execute the command.
690
-    */
691
-    switch (sCmdBuf[0])
692
-    {
693
-      case '1':
694
-        displaySettings();
695
-        break;
696
-      case '2':
697
-        setIP();
698
-        break;
699
-      case '3':
700
-        setNTPIP();
701
-        break;
702
-      case '4':
703
-        toggleVerbose();
704
-        break;
705
-      case '5':
706
-        readSettingsFromEEPROM();
707
-        return;
708
-      case '6':
709
-        writeSettingsToEEPROM();
710
-        /*
711
-         A software reboot is necessary to force the 
712
-         Arduino to request an IP address from a DHCP
713
-         server or to initialize the Ethernet interface
714
-         with a static IP address.
715
-        */
716
-        software_Reset();
717
-        return;
718
-      default:
719
-        Serial.println(F("invalid command"));
720
-    } /* end switch */
721
-  } /* end while */
722
-  return;
723
-}
724
-
725
-/*
726
- Displays the current system settings.  Displays
727
- RadMon software version, local IP address, NTP server
728
- address, and verbose mode setting.
729
-*/
730
-void displaySettings()
731
-{
732
-  char sBuf[16];
733
-  
734
-  // Display RadMon version
735
-  Serial.print(F("Firmware "));
736
-  Serial.print(F(RADMON_VERSION));
737
-  Serial.println();
738
-
739
-  // Display local IP address
740
-  sprintf(sBuf, "%d.%d.%d.%d", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]);
741
-  if (bUseDHCP)
742
-  {
743
-    Serial.print(F("DHCP IP: "));
744
-  }
745
-  else
746
-  {
747
-    Serial.print(F("Static IP: "));
748
-  }
749
-  Serial.println(sBuf);
750
-  
751
-  // Display NTP server IP address
752
-  sprintf(sBuf, "%d.%d.%d.%d", ntpip[0], ntpip[1], ntpip[2], ntpip[3]);
753
-  Serial.print(F("NTP server: ")); 
754
-  Serial.println(sBuf);
755
-
756
-  // Display verbose mode setting
757
-  printVerboseMode();
758
-  return;
759
-}
760
-
761
-/*
762
- Sets the local IP address. If the user sends a carriage
763
- return as the first character, then switch to acquiring
764
- IP address via DHCP server.
765
-*/
766
-void setIP()
767
-{
768
-  char sBuf[16];
769
-
770
-  Serial.print(F("enter IP (<CR> for DHCP): "));
771
-  getSerialLine(sBuf, 16);
772
-  
773
-  if(strlen(sBuf) == 0)
774
-  {
775
-    bUseDHCP = true;
776
-    parseIpAddress(ipAddr, "0.0.0.0");
777
-  }
778
-  else
779
-  {
780
-    bUseDHCP = false;
781
-    parseIpAddress(ipAddr, sBuf);
782
-  }
783
-  Serial.println();
784
-  return;
785
-}
786
-
787
-/*
788
- Sets the NTP server IP address.  If the user sends a
789
- carriage return as the first character, then use the
790
- default IP address for the NTP server.
791
-*/
792
-void setNTPIP()
793
-{
794
-  char sBuf[16];
795
-  
796
-  Serial.print(F("enter IP: "));
797
-  getSerialLine(sBuf, 16);
798
-  
799
-  if (strlen(sBuf) == 0)
800
-  {
801
-    parseIpAddress(ntpip, DEFAULT_NTP_SERVER_IP_ADDR);
802
-  }
803
-  else
804
-  {
805
-    parseIpAddress(ntpip, sBuf);
806
-  }
807
-  Serial.println();
808
-  return;
809
-}
810
-
811
-/*
812
- Turns verbose mode ON or OFF.
813
-*/
814
-void toggleVerbose()
815
-{
816
-  bVerbose = !bVerbose;
817
-  printVerboseMode();
818
-  return;
819
-}
820
-
821
-/***  GENERAL HELPER FUNCTIONS  ***/
822
-
823
-/*
824
- Print current verbose mode.
825
-*/
826
-void printVerboseMode()
827
-{
828
-  Serial.print(F("Verbose: "));
829
-  if (bVerbose)
830
-  {
831
-    Serial.println(F("ON"));
832
-  }
833
-  else
834
-  {
835
-    Serial.println(F("OFF"));
836
-  }
837
-  return;
838
-}
839
-
840
-/*
841
- Get the current IP address from the Ethernet interface
842
-*/
843
-void getCurrentIP()
844
-{
845
-  ipAddr[0] = Ethernet.localIP()[0];
846
-  ipAddr[1] = Ethernet.localIP()[1];
847
-  ipAddr[2] = Ethernet.localIP()[2];
848
-  ipAddr[3] = Ethernet.localIP()[3];
849
-  return;
850
-}
851
-
852
-/*
853
- Gets a line of data from the user via USB port.
854
-*/
855
-char* getSerialLine(char* sBuffer, int bufferLength)
856
-{
857
-  byte index;
858
-  char cRx;
859
-
860
-  /* 
861
-   Discard extranious characters that may still be in the
862
-   USB serial stream read buffer.  Most often these characters
863
-   will be unprocessed carriage return or line feed characters.
864
-  */
865
-  delay(10);
866
-  while (Serial.available())
867
-  {
868
-    cRx = Serial.read();
869
-  }
870
-
871
-  /*
872
-   Read and process characters from the user as they arrive in
873
-   the USB serial read buffer.
874
-  */
875
-  index = 0;
876
-  while(true)
877
-  {
878
-    /*
879
-     Wait until the user starts pressing keys and bytes
880
-     arrive in the serial read buffer.
881
-    */
882
-    if (Serial.available())
883
-    {
884
-      cRx = Serial.read();
885
-      if (cRx == '\r' || cRx == '\n')
886
-      {
887
-        /*
888
-         The user has finished typing the command and
889
-         has pressed the Enter key. So, discard the
890
-         carriage return and newline characters and then
891
-         return control to the calling function.
892
-        */
893
-        break;
894
-      }
895
-      else if (cRx == 8 || cRx == 127)
896
-      {
897
-        if (index > 0)
898
-        {
899
-          /*
900
-           The user has hit the delete-backspace key,
901
-           so send out a backspace, followed by a space,
902
-           followed by another backspace character.
903
-           This allows for in-line ediiting.
904
-          */
905
-          Serial.write(8);
906
-          Serial.write(32);
907
-          Serial.write(8); 
908
-          index -= 1;
909
-        }
910
-      }
911
-      else if ( index < (bufferLength - 1) )
912
-      {
913
-        /*
914
-         The received character is valid, so write it
915
-         to the buffer. Once the buffer becomes full
916
-         do not write any more characters to it.  When
917
-         the user pressses the enter key, the string
918
-         will be null terminated and control will pass
919
-         back to the calling function.
920
-        */
921
-        Serial.write(cRx); // echo character to terminal
922
-        sBuffer[index] = cRx;
923
-        index += 1;
924
-      } /* end if */
925
-    } /* end if */
926
-  } /* end while */
927
-  sBuffer[index] = 0; // terminate the string
928
-  return sBuffer;
929
-}
930
-
931
-/*
932
- Writes system configuration settings to non-volitile
933
- EEPROM.  The items written are the local IP address,
934
- the NTP server IP address, the state of verbose mode,
935
- and local IP mode (static or DHCP).
936
-*/
937
-void writeSettingsToEEPROM()
938
-{
939
-  byte ix;
940
-  for (ix = 0; ix < 4; ix++)
941
-  {
942
-    EEPROM.write(ix, ipAddr[ix]);
943
-    EEPROM.write(ix + 4, ntpip[ix]);
944
-  }
945
-  EEPROM.write(8, bVerbose);
946
-  EEPROM.write(9, bUseDHCP);
947
-  return;
948
-}
949
-
950
-/*
951
- Reads system configuration settings from non-volitile
952
- EEPROM.  The items read are the local IP address,
953
- the NTP server IP address, the state of verbose mode,
954
- and local IP mode (static or DHCP).
955
-*/
956
-void readSettingsFromEEPROM()
957
-{
958
-  byte ix;
959
-  for (ix = 0; ix < 4; ix++)
960
-  {
961
-    ipAddr[ix] = EEPROM.read(ix);
962
-    ntpip[ix] = EEPROM.read(ix + 4);
963
-  }
964
-  bVerbose = EEPROM.read(8);
965
-  bUseDHCP = EEPROM.read(9);
966
-  return;
967
-}
968
-
969
-/*
970
- Parses an IP address given in "nnn.nnn.nnn.nnn" string
971
- format into four bytes and stores them in an array. Note
972
- that this function destroys the contents of the sIP
973
- character array.  Therefore this array cannot be
974
- reinitialized after calling this function.
975
-*/
976
-void parseIpAddress(byte* byBuf, char* sIP)
977
-{
978
-  byBuf[0] = atoi(strtok(sIP, "."));
979
-  byBuf[1] = atoi(strtok(NULL, "."));
980
-  byBuf[2] = atoi(strtok(NULL, "."));
981
-  byBuf[3] = atoi(strtok(NULL, "."));
982
-  return;
983
-}
984
-
985
-/*
986
- Restarts the Uno and runs this program from beginning.  This
987
- function gets called after a change made from the user
988
- interface when the user selects "save and restart".
989
-*/
990
-void software_Reset() 
991
-{
992
-  asm volatile ("  jmp 0");
993
-  return; 
994
-}  
995
-