-
Notifications
You must be signed in to change notification settings - Fork 8
/
udp.c
362 lines (345 loc) · 14.4 KB
/
udp.c
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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
//********************************************************************************************
//
// File : udp.c implement for User Datagram Protocol
//
//********************************************************************************************
//
// Copyright (C) 2007
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
// This program is distributed in the hope that it will be useful, but
//
// WITHOUT ANY WARRANTY;
//
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin St, Fifth Floor, Boston, MA 02110, USA
//
// http://www.gnu.de/gpl-ger.html
//
//********************************************************************************************
#include "includes.h"
//
//********************************************************************************************
// The User Datagram Protocol offers only a minimal transport service
// -- non-guaranteed datagram delivery
// -- and gives applications direct access to the datagram service of the IP layer.
// UDP is used by applications that do not require the level of service of TCP or
// that wish to use communications services (e.g., multicast or broadcast delivery)
// not available from TCP.
//
// +------------+-----------+-------------+----------+
// + MAC header + IP header + UDP header + Data ::: +
// +------------+-----------+-------------+----------+
//
// UDP header
//
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +00+01+02+03+04+05+06+07+08+09+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Source port + Destination port +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Length + Checksum +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Data ::: +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
//
//********************************************************************************************
//
// Function : udp_generate_header
// Argument : BYTE *rxtx_buffer is a pointer point to UDP tx buffer
// WORD_BYTES dest_port is a destiantion port
// WORD_BYTES length is a UDP header and data length
// Return value : None
//
// Description : generate udp header
//
//********************************************************************************************
void udp_generate_header ( BYTE *rxtx_buffer, WORD_BYTES dest_port, WORD_BYTES length )
{
WORD_BYTES ck;
// setup source port, default value is 3000
rxtx_buffer[UDP_SRC_PORT_H_P] = UDP_AVR_PORT_H_V;
rxtx_buffer[UDP_SRC_PORT_L_P] = UDP_AVR_PORT_L_V;
// setup destination port
rxtx_buffer[UDP_DST_PORT_H_P] = dest_port.byte.high;
rxtx_buffer[UDP_DST_PORT_L_P] = dest_port.byte.low;
// setup udp length
rxtx_buffer[UDP_LENGTH_H_P] = length.byte.high;
rxtx_buffer[UDP_LENGTH_L_P] = length.byte.low;
// setup udp checksum
rxtx_buffer[UDP_CHECKSUM_H_P] = 0;
rxtx_buffer[UDP_CHECKSUM_L_P] = 0;
// length+8 for source/destination IP address length (8-bytes)
ck.word = software_checksum ( (BYTE*)&rxtx_buffer[IP_SRC_IP_P], length.word+8, length.word+IP_PROTO_UDP_V);
rxtx_buffer[UDP_CHECKSUM_H_P] = ck.byte.high;
rxtx_buffer[UDP_CHECKSUM_L_P] = ck.byte.low;
}
//********************************************************************************************
//
// Function : udp_puts_data
// Description : puts data from RAM to UDP tx buffer
//
//********************************************************************************************
WORD udp_puts_data ( BYTE *rxtx_buffer, BYTE *data, WORD offset )
{
while( *data )
{
rxtx_buffer[ UDP_DATA_P + offset ] = *data++;
offset++;
}
return offset;
}
//********************************************************************************************
//
// Function : udp_puts_data_p
// Description : puts data from program memory to tx buffer
//
//********************************************************************************************
WORD udp_puts_data_p ( BYTE *rxtx_buffer, PGM_P data, WORD offset )
{
BYTE ch;
while( (ch = pgm_read_byte(data++)) )
{
rxtx_buffer[ UDP_DATA_P + offset ] = ch;
offset++;
}
return offset;
}
//********************************************************************************************
//
// Function : udp_receive
// Argument : BYTE *rxtx_buffer is a pointer, point to UDP tx buffer
// BYTE *dest_mac is a pointer, point to destiantion MAC address
// BYTE *dest_ip is a pointer, point to destiantion IP address
// Return value : if received packet is UDP and destination port matching with AVR port, return true
// other return false
//
// Description : check received packet and process UDP command.
//
//********************************************************************************************
BYTE udp_receive ( BYTE *rxtx_buffer, BYTE *dest_mac, BYTE *dest_ip )
{
WORD_BYTES dlength, adc0;
BYTE generic_buf[64], temp, count_time_temp[3], tmp;
// check UDP packet and check destination port
if ( rxtx_buffer[IP_PROTO_P] != IP_PROTO_UDP_V || rxtx_buffer[UDP_DST_PORT_H_P] != UDP_AVR_PORT_H_V || rxtx_buffer[ UDP_DST_PORT_L_P ] != UDP_AVR_PORT_L_V )
return 0;
// check UDP command, UDP command are first and second byte
// "GA" command is Get All command, AVR will be send all data to AVRnet CPannel
// Response format is OKLLADC0TTEHHMMAAA.AAA.AAA.AAA;SSS.SSS.SSS.SSS;\r\n
// LL is LED1 and LED2
// ADC0 is ADC0 value
// TT is temperature
// E is send temp enable/disable
// HH is hours for send temp
// MM is minutes for send temp
// AAA.AAA.AAA.AAA is an AVR IP address
// SSS.SSS.SSS.SSS is a Server IP address
// ';' is end of IP address
// \r\n is end of command
// for example : GA100512250010010.1.1.1;10.1.1.76\r\n = LED1 on, LED2 off, ADC0 0512, Temp 25, Disable send temp, Hour 01, Min 00
if ( rxtx_buffer[UDP_DATA_P] == 'G' && rxtx_buffer[UDP_DATA_P+1] == 'A' && rxtx_buffer[UDP_DATA_P+2] == '\r' && rxtx_buffer[UDP_DATA_P+3] == '\n')
{
// command response
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("GAOK"), 0 );
// LED1
if ((LED_PORT&_BV(LED_PIN1))==0)
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("1"), dlength.word );
else
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("0"), dlength.word );
// LED2
if ((LED_PORT&_BV(LED_PIN2))==0)
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("1"), dlength.word );
else
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("0"), dlength.word );
// ADC0
adc0.word = adc_read ( 0 );
print_decimal ( generic_buf, 4, adc0.word );
generic_buf[ 4 ] = '\0';
dlength.word = udp_puts_data ( rxtx_buffer, (BYTE *)generic_buf, dlength.word );
// temperature
temp = adc_read_temp();
print_decimal ( generic_buf, 2, temp );
generic_buf[ 2 ] = '\0';
dlength.word = udp_puts_data ( rxtx_buffer, (BYTE *)generic_buf, dlength.word );
// send temp config
eeprom_read_block ( count_time_temp, ee_count_time, 3 );
if (count_time_temp[0])
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("1"), dlength.word );
else
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("0"), dlength.word );
print_decimal ( generic_buf, 2, count_time_temp[1] );
generic_buf[ 2 ] = '\0';
dlength.word = udp_puts_data ( rxtx_buffer, (BYTE *)generic_buf, dlength.word );
print_decimal ( generic_buf, 2, count_time_temp[2] );
generic_buf[ 2 ] = '\0';
dlength.word = udp_puts_data ( rxtx_buffer, (BYTE *)generic_buf, dlength.word );
// AVR IP address
print_ip ( generic_buf, (BYTE*)&avr_ip, 0 );
dlength.word = udp_puts_data ( rxtx_buffer, (BYTE *)generic_buf, dlength.word );
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR(";"), dlength.word );
// Server IP address
print_ip ( generic_buf, (BYTE*)&server_ip, 0 );
dlength.word = udp_puts_data ( rxtx_buffer, (BYTE *)generic_buf, dlength.word );
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR(";\r\n"), dlength.word );
}
// "ST" command is set send temperature configuration command
// "ST" command format is STEHHMM\r\n
// E is send temp enable/disable
// HH is hours for send temp
// MM is minutes for send temp
// \r\n is end of command
// for example : ST10115\r\n = Enable send temp, 1-Hour, 15-Minutes
else if ( rxtx_buffer[UDP_DATA_P] == 'S' && rxtx_buffer[UDP_DATA_P+1] == 'T' && rxtx_buffer[UDP_DATA_P+7] == '\r' && rxtx_buffer[UDP_DATA_P+8] == '\n')
{
// get enable/disable
count_time_temp[0] = rxtx_buffer[UDP_DATA_P+2] - '0';
// get hour
count_time_temp[1] = (rxtx_buffer[UDP_DATA_P+3] - '0') * 10;
count_time_temp[1] = count_time_temp[1] + (rxtx_buffer[UDP_DATA_P+4] - '0');
// get minute
count_time_temp[2] = (rxtx_buffer[UDP_DATA_P+5] - '0') * 10;
count_time_temp[2] = count_time_temp[2] + (rxtx_buffer[UDP_DATA_P+6] - '0');
// write config to eeprom
eeprom_write_block ( count_time_temp, ee_count_time, 3 );
eeprom_read_block ( count_time, ee_count_time, 3 );
count_time[3] = 0;
// command response
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("STOK\r\n"), 0 );
}
// "SI" command is set AVR IP address command
// "SI" command format is SIAAA.AAA.AAA.AAA;SSS.SSS.SSS.SSS;\r\n
// AAA.AAA.AAA.AAA is an AVR IP address (variable length)
// SSS.SSS.SSS.SSS is a Server IP address (variable length)
// ';' end of ip address
// \r\n is end of command
// for example : SI10.1.1.1;10.1.1.76;\r\n
else if ( rxtx_buffer[UDP_DATA_P] == 'S' && rxtx_buffer[UDP_DATA_P+1] == 'I' )
{
// find \r\n
for(tmp=UDP_DATA_P; tmp<UDP_DATA_P+128; tmp++)
{
if(rxtx_buffer[UDP_DATA_P+tmp]=='\r' && rxtx_buffer[UDP_DATA_P+tmp+1]=='\n')
{
temp = 0;
break;
}
}
if(temp==0)
{
tmp = 0;
// find ';' end of IP address and replace it with zero
while ( rxtx_buffer[UDP_DATA_P+tmp] != ';') tmp++;
rxtx_buffer[UDP_DATA_P+tmp] = 0;
// use http_get_ip to convert ascii to hex
if ( http_get_ip ( (BYTE*)&rxtx_buffer[UDP_DATA_P+2], (BYTE*)&avr_ip ) == 4 )
eeprom_write_block ( &avr_ip, ee_avr_ip, 4 );
eeprom_read_block ( &avr_ip, ee_avr_ip, 4 );
// Get server IP
temp = tmp+1;
while ( rxtx_buffer[UDP_DATA_P+tmp] != ';') tmp++;
rxtx_buffer[UDP_DATA_P+tmp] = '\0';
// use http_get_ip to convert ascii to hex
if ( http_get_ip ( (BYTE*)&rxtx_buffer[UDP_DATA_P+temp], (BYTE*)&server_ip ) == 4 )
eeprom_write_block ( &avr_ip, ee_server_ip, 4 );
eeprom_read_block ( &avr_ip, ee_server_ip, 4 );
// send command response to client
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("SIOK\r\n"), 0 );
}
else
{
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("ERROR\r\n"), 0 );
}
}
// "WL" command is Write LCD command
// "WL" command format is WL1111111111111111;2222222222222222;\r\n
// 1111111111111111 is 1'st line character (variable length, max is 16)
// 2222222222222222 is 2'nd line character (variable length, max is 16)
// ';' end of character
// \r\n is end of command
// for example : WLHello World!;I'm AVRnet;\r\n
else if ( rxtx_buffer[UDP_DATA_P] == 'W' && rxtx_buffer[UDP_DATA_P+1] == 'L')
{
// find \r\n
for(tmp=UDP_DATA_P; tmp<UDP_DATA_P+128; tmp++)
{
if(rxtx_buffer[UDP_DATA_P+tmp]=='\r' && rxtx_buffer[UDP_DATA_P+tmp+1]=='\n')
{
temp = 0;
break;
}
}
if(temp==0)
{
tmp=0;
// find end of 1'st line and replace it with '\n'
while( rxtx_buffer[UDP_DATA_P+tmp] != ';' ) tmp++;
rxtx_buffer[UDP_DATA_P+tmp] = '\n';
// find end of 1'st line and replace it with '\0'
while( rxtx_buffer[UDP_DATA_P+tmp] != ';' ) tmp++;
rxtx_buffer[UDP_DATA_P+tmp] = '\0';
// print string to LCD
lcd_putc ( '\f' );
lcd_print ( (BYTE*)&rxtx_buffer[UDP_DATA_P+2] );
flag1.bits.lcd_busy = 1;
// send command response to client
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("WLOK\r\n"), 0 );
}
else
{
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("ERROR\r\n"), 0 );
}
}
// "SL" command, is set LED1, LED2 command
// "SL" command format is SL12\r\n
// 1 is on/off command for LED1 '1' = ON, '0' = OFF
// 2 is on/off command for LED2 '1' = ON, '0' = OFF
// \r\n is end of command
else if(rxtx_buffer[UDP_DATA_P]=='S' && rxtx_buffer[UDP_DATA_P+1]=='L' && rxtx_buffer[UDP_DATA_P+4]=='\r' && rxtx_buffer[UDP_DATA_P+5]=='\n')
{
// on/off LED1
if(rxtx_buffer[UDP_DATA_P+2]=='0')
LED_PORT |= _BV ( LED_PIN1 );
else
LED_PORT &= ~_BV ( LED_PIN1 );
// on/off LED2
if(rxtx_buffer[UDP_DATA_P+3]=='0')
LED_PORT |= _BV ( LED_PIN2 );
else
LED_PORT &= ~_BV ( LED_PIN2 );
// send command response
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("SLOK\r\n"), 0 );
}
// added in V1.1 ==============================================================================
// "RS" is software reset command
#ifndef REMOVE_BOOTLOADER_SUPPORT
else if(rxtx_buffer[UDP_DATA_P]=='R' && rxtx_buffer[UDP_DATA_P+1]=='S' && rxtx_buffer[UDP_DATA_P+2]=='\r' && rxtx_buffer[UDP_DATA_P+3]=='\n')
{
// send command response
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("Y"), 0 );
flag2.bits.software_reset = 1;
}
#endif
// end added in V1.1 ==========================================================================
else
{
// unknown command, send "ERROR" to client
dlength.word = udp_puts_data_p ( rxtx_buffer, PSTR("ERROR\r\n"), 0 );
}
// set ethernet header
eth_generate_header (rxtx_buffer, (WORD_BYTES){ETH_TYPE_IP_V}, dest_mac );
// generate ip header and checksum
ip_generate_header (rxtx_buffer, (WORD_BYTES){sizeof(IP_HEADER)+sizeof(UDP_HEADER)+dlength.word}, IP_PROTO_UDP_V, dest_ip );
// generate UDP header
udp_generate_header (rxtx_buffer, (WORD_BYTES){(rxtx_buffer[UDP_SRC_PORT_H_P]<<8)|rxtx_buffer[UDP_SRC_PORT_L_P]}, (WORD_BYTES){sizeof(UDP_HEADER)+dlength.word});
// send packet to ethernet media
enc28j60_packet_send ( rxtx_buffer, sizeof(ETH_HEADER)+sizeof(IP_HEADER)+sizeof(UDP_HEADER)+dlength.word );
return 1;
}