1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
| /*
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Analog inputs attached to pins A0 through A5 (optional)
* Note that A0 and A1 are used by the ethernet shield for the SD card detection + SD card write-protect detection
TELNET SPECIFICS
server.write(thisChar); -> this will write to all the connected clients right away.
client.write(thisChar); -> this will write to only the current client.
use write to write raw data (bytes)
use print for formatted data / strings
server.write(30); -> this will output strange characters
server.print(30); -> this will output 30
in telnet, client.print(CHAR_ESC "[1;0H"); (row 1 column 0) is the top left side of the screen.
client.print(CHAR_ESC "[25;80H"); goes to the right bottom of the screen
To avoid strange shifting, it's better to go only up to row 24
That way any characters entered by the user appear on row 25 without causing a windows shift
*/
#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>
#define CHAR_ESC "\x1B" // \x means "hexadecimal notation" and 1B in hex equals 27 which is the escape character
#define CHAR_NORMAL "\x1B[0m"
#define CHAR_BOLD "\x1B[1m"
#define CHAR_UNDERLINE "\x1B[4m"
#define CHAR_REVERSE "\x1B[7m" //letters turn black and background white
#define CHAR_BLINK "\x1B[5m" //like reverse but background is grey. Also this doesn't work in microsoft telnet and most other clients unless specifically enabled
#define CHAR_80COLUMN "\x1B[?3l" //normal screen, better stay with this for compatability
#define CHAR_132COLUMN "\x1B[?3h" //wide screen :O
#define CHAR_CLS "\x1B[2J" //clear the screen and go to the top left corner
// MAC address is written on the back of the ethernet shield, gateway and subnet are optional.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1,177 };
byte gateway[] = { 192,168,1,1 };
byte subnet[] = { 255, 255, 0, 0 };
//These arrays will keep the last 5 readings on 1-5 and the average temp on position 0
//After each read, 1 is replaced with 2, 2 is replaced with 3, etc, 5 becomes the new reading and after that
//the average of the 5 readings is stored on position 0
float Tbuiten[6] = { 20,20,20,20,20,20};
float Tbinnen[6] = { 20,20,20,20,20,20};
//telnet defaults to port 23
Server server(23);
unsigned long time=0, overflow=0;
void readtemps()
{
// Tbuiten[i]=(5.0 * analogRead(i+8) * 100.0)/1024.0; //the old function with 5v ref for ADC, not so accurate
// Tbuiten[i]= analogRead(i+8) / 9.31; //the new function, with 1.1v ref for ADC, quite accurate.
//We use this analogReference because it makes the range of the ADC go from 0 to 1.1 volts.
//The LM35 will output 10mV per degree Celsius
//so 20 degrees means 200mV, 100 degrees means 1000mV (which is 1V)
//With the normal analogReference of 5v we would use only 0 to 1 volts which is only 20% of the entire range
//By setting the analogReference to 1.1volt we are using roughly 90% of the range
//However: the max reading is now 100 degrees and if you go over it you go over the max input of the ADC, and you will burn it down so pay attention here.
//Also see: http://www.arduino.cc/playground/Main/LM35HigherResolution
//Note that it's INTERNAL1V1 for the mega, but INTERNAL for ATmega168, ATmega328, ATmega8 etc. checkout: http://arduino.cc/en/Reference/AnalogReference
analogReference(INTERNAL);
delay(500); //giving the ADC some time to switch to the new reference voltage
for (int i=1; i <= 4; i++){Tbuiten[i]=Tbuiten[i+1];}
Tbuiten[5]=(analogRead(4) / 9.31);
Tbuiten[0]= (Tbuiten[1]+Tbuiten[2]+Tbuiten[3]+Tbuiten[4]+Tbuiten[5])/5;
for (int i=1; i <= 4; i++){Tbinnen[i]=Tbinnen[i+1];}
Tbinnen[5]=(analogRead(5) / 9.31);
Tbinnen[0]= (Tbinnen[1]+Tbinnen[2]+Tbinnen[3]+Tbinnen[4]+Tbinnen[5])/5;
analogReference(DEFAULT); //setting it back to the 5v ref for the ADC, assuming we're not using a 3.3v arduino
}
void diags (Client client)
{
//one overflow has 49:17:2:47 d:h:m:s
int days=0, hours=0, minutes=0, secs=0;
client.print(CHAR_CLS); //clear the screen
days=(time/86400000)+(overflow*49);
hours=((time%86400000)/3600000)+(overflow*17);
minutes=(((time%86400000)%3600000)/60000)+(overflow*2);
secs=((((time%86400000)%3600000)%60000)/1000)+(overflow*47);
client.print("running time (days:hours:minutes:seconds) : ");client.print(days);client.print(":");client.print(hours);client.print(":");client.print(minutes);client.print(":");client.println(secs);
client.println(" ");
}
//simple function to move around the screen.
//build this cause it seems impossible to just print text along with variables at the same time with print or println
//welcome to the 21st century!
void TNmove( Client client , int row , int col )
{
// example: client.print(CHAR_ESC "[1;0H");
client.print(CHAR_ESC "[");
client.print(row);
client.print(";");
client.print(col);
client.print("H");
}
//this just draws basic things that are always there like lines and stuff
void draw_mainscreen( Client client )
{
client.print(CHAR_CLS); //clear the screen
TNmove(client,1,0);
client.write(201);
for (int i=2; i <= 16; i++){client.write(205);}
client.write(209);
for (int i=18; i <= 79; i++){client.write(205);}
client.write(187);
TNmove(client,2,0);client.write(186);
TNmove(client,2,2);
client.print("iets: ");
client.write(179);
client.print(" nog iets ");
TNmove(client,2,80);client.write(186);
TNmove(client,3,0);client.write(199);
for (int i=2; i <= 16; i++){client.write(196);}
client.write(193);
for (int i=18; i <= 79; i++){client.write(196);}
client.write(182);
for (int i=4; i <= 21; i++){TNmove(client,i,0);client.write(186);TNmove(client,i,80);client.write(186);}
TNmove(client,22,0);client.write(199);
for (int i=2; i <= 14; i++){client.write(196);}
client.write(194);
for (int i=16; i <= 29; i++){client.write(196);}
client.write(194);
for (int i=31; i <= 44; i++){client.write(196);}
client.write(194);
for (int i=46; i <= 59; i++){client.write(196);}
client.write(194);
for (int i=61; i <= 74; i++){client.write(196);}
client.write(194);
for (int i=76; i <= 79; i++){client.write(196);}
client.write(182);
TNmove(client,23,80);client.write(186);
TNmove(client,23,1);client.write(186); TNmove(client,23,15);client.write(179); TNmove(client,23,30);client.write(179);
TNmove(client,23,45);client.write(179); TNmove(client,23,60);client.write(179); TNmove(client,23,75);client.write(179);
TNmove(client,24,0);client.write(200);
for (int i=2; i <= 14; i++){client.write(205);}
client.write(207);
for (int i=16; i <= 29; i++){client.write(205);}
client.write(207);
for (int i=31; i <= 44; i++){client.write(205);}
client.write(207);
for (int i=46; i <= 59; i++){client.write(205);}
client.write(207);
for (int i=61; i <= 74; i++){client.write(205);}
client.write(207);
for (int i=76; i <= 79; i++){client.write(205);}
client.write(188);
TNmove(client,25,0); //park the cursor on the lowest row of the screen
}
//this fills in the basic screen with details about the LBK's
//this is a seperate procedure so that refreshing the data on the screen doesn't need to update the whole screen including all lines and makeup
void draw_tempsscreen( Client client )
{
TNmove(client,4,17); client.print("Meting");
TNmove(client,6,3); client.print("Buiten: ");client.print(Tbuiten[0]);client.write(167);
TNmove(client,7,3); client.print("binnen: ");client.print(Tbinnen[0]);client.write(167);
//printing the menu
TNmove(client,23,2); client.print("R: Refresh");
TNmove(client,23,16); client.print("");
TNmove(client,23,31); client.print("");
TNmove(client,23,46); client.print("");
TNmove(client,23,61); client.print("5: diagnostic");
TNmove(client,25,0); //park the cursor on the lowest row of the screen
}
//simply checks if a client is connected or not
//will return 1 for connected, or 0 for not connected
//client is always 0, 1, 2 or 3 as there are 4 maximum sessions
int client_connected( Client client )
{
return client.connected();
}
void setup() {
// initialize the ethernet device
Ethernet.begin(mac, ip, gateway, subnet);
// start listening for clients
server.begin();
// open the serial port
Serial.begin(9600);
}
void loop()
{
//let's see if there's any data awaiting for us from the ethernet interface
Client client = server.available();
//got work to do... server.available() just gave back a number higher then 0 so we got data from a telnet client
if (client) {
char thisChar = client.read();
client.print(thisChar, DEC);
client.print(" ");
//processing keys received via ethernet
switch (thisChar) {
case 'r':
draw_tempsscreen(client);
break;
case '5':
diags(client);
break;
case 'q':
{ client.print("You pressed the q button, so goodbye....");
client.stop(); }
break;
default:
draw_mainscreen(client);
draw_tempsscreen(client);
break;
}// end of "switch (thisChar)"
}// end of "if (client)" so basically end of receiving data and acting upon it
//here we got an overflow of the millis() function which happens roughly every 50 days
//after the overflow, time will be higher then millis() and thus millis()-time always result in a negative number
//a negative number is never >5000 so we never go in our loop again.
//Therefore we reset time to 0 after an overflow so that we go back into our nice loop below.
if (millis() < time){
overflow=+1;
time=0;
}
//Because our Arduino is so incredibly fast (*cough*) we want to do some things only every once in a while.
//Consider that it takes some time to change the ref voltage for the ADC, to read the pins etc etc and we need some delays for that
//If we do that stuff every cycle then the network access would be superslow
//Therefore we do the slow part (things that do not need direct attention like reading these pins) only every once in while
//By doing that we let the loop go fast the rest of the time to process user input like from the telnet session.
if (millis() - time > 5000){
time=millis();
readtemps();
}
} |