Em cũng đang tự viết dựa vào datasheet enc28j60 để viết mấy hàm cơ bản.Thầy có thể giải thích giÙm em cách điều khiển enc28j60 để truyền và nhận gói tin.Sử dụng các thanh ghi để điều khiển,chú thích các thanh ghi và bit của nó.Em đọc datasheet nhưng chưa hiểu.Em cảm ơn thầy.
Thông báo
Collapse
No announcement yet.
Giao thức TCP/IP và Web server với AVR
Collapse
This is a sticky topic.
X
X
-
Bây giờ là phần code cho TCP :
Ta lại tạo 2 file source và header :
“tcp.c” :
Code://---------------------------------------------------------------------------- // Writen by NTTam - PTITHCM //---------------------------------------------------------------------------- #include "packet.h" #include "ethernet.h" #include "ip.h" #include "uart.h" #include "tcp.h"
Code://---------------------------------------------------------------------------- // Writen by NTTam - PTITHCM //---------------------------------------------------------------------------- #ifndef TCP_H #define TCP_H #endif //TCP_H
Code://-------------------------------------------------------------------------------------- //Cau truc TCP header struct ntTCPHeader { unsigned int srcPort; unsigned int desPort; unsigned long seqNumber; unsigned long ackNumber; unsigned char Offset; unsigned char Flags; unsigned int Window; unsigned int Checksum; unsigned int UrgentPtr; unsigned char optdata[8]; }; #define TCP_HEADER_LEN 20
Code:#define TCP_NON_FLAG (0) #define TCP_FIN_FLAG (1<<0) #define TCP_SYN_FLAG (1<<1) #define TCP_RST_FLAG (1<<2) #define TCP_PSH_FLAG (1<<3) #define TCP_ACK_FLAG (1<<4) #define TCP_URG_FLAG (1<<5) #define TCP_ECE_FLAG (1<<6) #define TCP_CWR_FLAG (1<<7)
Đầu tiên là giá trị MSS (Max Segment Size – Kích thước đoạn dữ liệu tối đa mà ta có thể nhận). Chỗ này các bạn xem lại minh họa chỗ 2 cô thư ký là hiểu ý nghĩa giá trị này liền.
Code:#define MAX_SEGMENT_SIZE (ETHERNET_BUFFER_SIZE - ETH_HEADER_LEN - IP_HEADER_LEN - TCP_HEADER_LEN)
Code://List the TCP session state #define TCP_STATE_CLOSED 0 #define TCP_STATE_SYN_SENT 1 #define TCP_STATE_LISTEN 2 #define TCP_STATE_SYN_RECEIVED 3 #define TCP_STATE_ESTABLISHED 4 #define TCP_STATE_FIN_WAIT1 5 #define TCP_STATE_FIN_WAIT2 6 #define TCP_STATE_CLOSING 7 #define TCP_STATE_TIMED_WAIT 8 #define TCP_STATE_CLOSE_WAIT 9 #define TCP_STATE_LAST_ACK 10
Code://60 seconds timeout: #define TCP_TIMEOUT 60
Code://maximum connection count #define TCP_MAX_SESSION 8
Code://-------------------------------------------------------------------------------------- struct tcpSession{ unsigned int desPort; //Port on the remote host unsigned int srcPort; //Port on the local host unsigned long desIP; //IP address of the remote host unsigned long seqNumber; //Sequence number unsigned long ackNumber; //Acknowlegement number unsigned char sesState; //Current state of TCP session unsigned int srcWin; unsigned int desWin; unsigned long lastRxAck; //Last Received Ack unsigned char nextAck; unsigned char timeOut; //Session time out void(*appDataIn)(unsigned char* dataBuffer,unsigned int dataLen,struct tcpSession *pSession); unsigned char appID; //Upper layer application ID unsigned char appState; //Upper layer application state };
Khai báo 1 bảng TCP session, trong đó mỗi dòng là 1 struct tcpSession lưu thông tin về 1 kết nối:
Code://-------------------------------------------------------------------------------------- struct tcpSession tcpSessionTable[TCP_MAX_SESSION];
Code://-------------------------------------------------------------------------------------- //Ham khoi tao so tuan tu cho mot phien TCP // Hien tai su dung gia tri 1234 (may tinh thuong dung gia tri thoi gian hien tai) unsigned long TCPInitSequenceNumber() { return(1234); }
Code://-------------------------------------------------------------------------------------- //Ham dong mot phien TCP void TCPCloseSession(unsigned char socketnum) { tcpSessionTable[socketnum].sesState = TCP_STATE_CLOSED; #ifdef TCP_DEBUG printf("Close TCP session %d\r\n",socketnum); #endif }
Code://-------------------------------------------------------------------------------------- //Khoi dong cac gia tri trong bang TCP session void TCPInit() { unsigned char i = 0; for(i=0; i<TCP_MAX_SESSION; i++){ TCPCloseSession(i); } }
Code:Hàm tìm kiếm 1 phiên TCP đang rỗi trong bảng TCP session table (để mở kết nối mới) //-------------------------------------------------------------------------------------- //Tim mot session TCP dang roi unsigned char TCPGetFreeSession(){ unsigned char i; for(i=0; i<TCP_MAX_SESSION; i++){ if (tcpSessionTable[i].sesState == TCP_STATE_CLOSED) return i; } //no free closed socket fount! -> kick an TIMED_WAIT socket for(i=0; i<TCP_MAX_SESSION; i++){ if (tcpSessionTable[i].sesState == TCP_STATE_TIMED_WAIT){ TCPCloseSession(i); return i; } } //no more free sockets ... return invalid val return(TCP_MAX_SESSION); }
Code://-------------------------------------------------------------------------------------- //Ham khoi tao mot session TCP o che do server de cho ket noi void TCPCreateSession(unsigned int sourcePort, prog_void* appService) { unsigned char i; i = TCPGetFreeSession(); if(i >= TCP_MAX_SESSION) i = 0; //force session 0 tcpSessionTable[i].srcPort = sourcePort; tcpSessionTable[i].sesState = TCP_STATE_LISTEN; //Current state of TCP session tcpSessionTable[i].srcWin = 8192;//NETSTACK_BUFFERSIZE - ETH_HEADER_LEN - IP_HEADER_LEN - TCP_HEADER_LEN - 16; tcpSessionTable[i].desWin = tcpSessionTable[i].srcWin; tcpSessionTable[i].timeOut = TCP_TIMEOUT; //Session time out tcpSessionTable[i].appDataIn = appService; #ifdef TCP_DEBUG printf("TCP session created: %d\r\n", i); #endif }
Code://-------------------------------------------------------------------------------------- //Duoc goi moi giay de kiem tra Time out cho cac phien TCP, // giai phong cac phine TCP bi treo void TCPCheckTimeOut(){ unsigned char i; for(i=0; i<TCP_MAX_SESSION; i++){ //decrement ttl: if ((tcpSessionTable[i].sesState != TCP_STATE_CLOSED) && (tcpSessionTable[i].sesState != TCP_STATE_LISTEN)){ if(tcpSessionTable[i].timeOut) tcpSessionTable[i].timeOut--; //if socket TTL count is zero, close this socket! if (tcpSessionTable[i].timeOut == 0){ TCPCloseSession(i); } } } }
Code://-------------------------------------------------------------------------------------- //Tinh checksum cho goi TCP unsigned int checksum(unsigned char *buffer, unsigned int len, unsigned long csum32) { unsigned int res16 = 0x0000; unsigned char data_hi; unsigned char data_lo; while(len > 1){ data_hi = *buffer++; data_lo = *buffer++; res16 = (((unsigned int)data_hi << 8) + data_lo); csum32 = csum32 + res16; len -=2; } if(len > 0){ data_hi = *buffer; res16 = (unsigned int)data_hi<<8; csum32 = csum32 + res16; } while(csum32>>16) csum32 = (csum32 & 0xFFFF)+ (csum32 >> 16); //csum32 = ((csum32 & 0x0000FFFF)+ ((csum32 & 0xFFFF0000) >> 16)); res16 =~(csum32 & 0x0000FFFF); return (res16); }
Hàm gửi 1 đoạn dữ liệu đi bằng giao thức TCP:
Code://-------------------------------------------------------------------------------------- //Gui di mot goi TCP void TCPPackedSend(struct tcpSession *pSession, unsigned char Flags, unsigned int len, unsigned char *dataBuffer) { unsigned int tmp; unsigned long checksum32; //Make pointer to TCP header struct ntTCPHeader* tcpHeader; struct ntIPHeader* ipHeader; //Neu dang syn thi them option ve MSS if(Flags & TCP_SYN_FLAG){ //Option data dataBuffer[0] = 0x02; dataBuffer[1] = 0x04; dataBuffer[2] = (MAX_SEGMENT_SIZE >> 8) & 0xff; dataBuffer[3] = MAX_SEGMENT_SIZE & 0xff; dataBuffer[4] = 0x01; dataBuffer[5] = 0x03; dataBuffer[6] = 0x03; dataBuffer[7] = 0x00; //Move data pointer to make room for TCP header } dataBuffer -= TCP_HEADER_LEN; tcpHeader = (struct ntTCPHeader*)dataBuffer; //Fill UDP header tcpHeader->srcPort = HTONS(pSession->srcPort); tcpHeader->desPort = HTONS(pSession->desPort); tcpHeader->seqNumber = HTONL(pSession->seqNumber); pSession->seqNumber = pSession->seqNumber + len; if(Flags & (TCP_FIN_FLAG|TCP_SYN_FLAG)) (pSession->seqNumber)++; tcpHeader->ackNumber = HTONL(pSession->ackNumber); if(Flags & TCP_SYN_FLAG){ tcpHeader->Offset = (0x07<<4); len += (TCP_HEADER_LEN + 8); }else{ tcpHeader->Offset = (0x05<<4); len += TCP_HEADER_LEN; } tcpHeader->Flags = Flags; tcpHeader->Window = HTONS(pSession->srcWin);//((NETSTACK_BUFFERSIZE-20-14)); tcpHeader->Checksum = 0; tcpHeader->UrgentPtr = 0x0000; //Generate checksum ipHeader = (struct ntIPHeader*)(dataBuffer-IP_HEADER_LEN); ipHeader->srcIPAddr = HTONL(ipGetConfig()->ip); ipHeader->desIPAddr = HTONL(pSession->desIP); ipHeader->Checksum = HTONS(len); ipHeader->TTL = 0x00; ipHeader->Protocol = IP_PROTO_TCP; checksum32 = 0; tmp = len + 12; tmp = checksum (((unsigned char *)ipHeader+8), tmp, checksum32); tcpHeader->Checksum = HTONS(tmp); ipSend(pSession->desIP, IP_PROTO_TCP, len, (unsigned char *)tcpHeader); }
Code://-------------------------------------------------------------------------------------- //Ham xu ly goi TCP nhan duoc, duoc goi boi giao thuc IP (IPProcess) void TCPProcess(unsigned char *buffer, unsigned int len) //Ham xu ly cho giao thuc TCP // Duoc thuc thi khi nhan duoc mot goi TCP (goi boi netstackIPProcess) // buffer: co tro den dau goi IP (bat dau IP Header) // len : chieu dai buffer { unsigned char i,ipHeaderLen,tcpHeaderLen; unsigned int dataLen; unsigned long tmp; struct ntIPHeader* ipHeader; struct ntTCPHeader* tcpHeader; unsigned char *tcpData; //Khoi tao cac co tro den Header IP va TCP ipHeader = (struct ntIPHeader*)(buffer); ipHeaderLen = ((ipHeader->verHdrLen) & 0x0F) << 2; // tcpHeader = (struct ntTCPHeader*)(buffer+ipHeaderLen); tcpHeaderLen = ((tcpHeader->Offset) & 0xF0) >> 2; // tcpData = (buffer+ipHeaderLen+tcpHeaderLen); dataLen = HTONS(ipHeader->Len) - (ipHeaderLen + tcpHeaderLen); //Tim kiem mot phien TCP co san cho goi nay for(i = 0; i < TCP_MAX_SESSION; i++){ //Check session table if(tcpSessionTable[i].sesState != TCP_STATE_CLOSED){ //If not closed session if(tcpSessionTable[i].srcPort == HTONS((tcpHeader->desPort))){ //If matched local port if(tcpSessionTable[i].desPort == HTONS((tcpHeader->srcPort))&&(tcpSessionTable[i].desIP == HTONL((ipHeader->srcIPAddr)))){ break; //Thoat khoi vong lap for, luc nay gia tri cua i chinh la chi so cua phien TCP tuong ung } } } } if(i == TCP_MAX_SESSION){ //Neu khong co 1 phien TCP dang ton tai cho goi nay //Tim 1 phien dang o trang thai LISTEN (doi ket noi) cho local port nay for(i=0; i < TCP_MAX_SESSION; i++){ if(tcpSessionTable[i].sesState == TCP_STATE_LISTEN){ if(tcpSessionTable[i].srcPort == HTONS((tcpHeader->desPort))){ //If matched local port //Cap nhat remote port va remote IP tcpSessionTable[i].desPort = HTONS((tcpHeader->srcPort)); tcpSessionTable[i].desIP = HTONL((ipHeader->srcIPAddr)); //Dong thoi tao ra 1 session moi de cho ket noi khac den local port nay TCPCreateSession(tcpSessionTable[i].srcPort,tcpSessionTable[i].appDataIn); break; } } } } if(i == TCP_MAX_SESSION){ #ifdef TCP_DEBUG printf("No TCP session found\r\n"); #endif return; //Neu khong co phien TCP nao danh cho goi nay thi thoat ra } #ifdef TCP_DEBUG printf("TCP session found: %d\r\n",i); #endif //Bat dau xu ly giao thuc tcpSessionTable[i].timeOut = TCP_TIMEOUT; //Reset lai gia tri Time out //Truong hop nhan duoc yeu cau reset lai ket noi if ((tcpHeader->Flags) & TCP_RST_FLAG){ //Chap nhan dong ket noi TCPCloseSession(i); return; } //Kiem tra trang thai hien tai cua phien TCP switch (tcpSessionTable[i].sesState){ //Neu la trang thai doi ket noi: TCP_STATE_LISTEN case(TCP_STATE_LISTEN): //Chi xu ly neu co SYN duoc set (yeu cau thiet lap ket noi) if ((tcpHeader->Flags) == TCP_SYN_FLAG){ //Chuyen sang trang thai ke tiep la TCP_STATE_SYN_RECEIVED tcpSessionTable[i].sesState = TCP_STATE_SYN_RECEIVED; //Khoi tao gia tri sequence tcpSessionTable[i].seqNumber = HTONL(TCPInitSequenceNumber()); //Ack chinh la so tuan tu nhan duoc cong 1 tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1; tcpSessionTable[i].desWin = HTONS((tcpHeader->Window)); //Goi tra xac nhan va co SYN (SYN & ACK) TCPPackedSend(&tcpSessionTable[i],(TCP_SYN_FLAG|TCP_ACK_FLAG),0,tcpData); //Tang so tuan tu len 1 //tcpSessionTable[i].seqNumber++; #ifdef TCP_DEBUG printf("SYN received\r\n"); #endif } break; //Neu la trang thai TCP_STATE_SYN_RECEIVED case(TCP_STATE_SYN_RECEIVED): //Neu co co ACK (cho ban tin SYN & ACK truoc do) if ((tcpHeader->Flags) == TCP_ACK_FLAG){ //Kiem tra ack trong goi tin den, neu dung thi thiet lap ket noi hoan tat if((tcpSessionTable[i].seqNumber) == HTONL((tcpHeader->ackNumber))){ tcpSessionTable[i].sesState = TCP_STATE_ESTABLISHED; //Goi tiep theo gui di se co co ACK tcpSessionTable[i].nextAck = 1; #ifdef TCP_DEBUG printf("Connection established\r\n"); #endif } }else{ //Neu khong dung ACK //Khong lam gi ca, goi tin do khong hop le //TCPCloseSession(i); } break; //Truong hop ket noi da duoc thiet lap case(TCP_STATE_ESTABLISHED): //Neu nhan duoc yeu cau ket thuc ket noi tu client if ((tcpHeader->Flags) & TCP_FIN_FLAG){ //Chuyen sang trang thai ke tiep la trang thai cho ACK cuoi //Dung ra o day phai chuyen sang trang thai TCP_STATE_CLOSE_WAIT nhung khong can thiet // vi o day ta co the dong ket noi ngay ma khong can cho gui xong du lieu tcpSessionTable[i].sesState = TCP_STATE_LAST_ACK; //Cap nhat ack tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber)) + dataLen; tcpSessionTable[i].ackNumber++; //Tang 1 cho co FIN //Gui xac nhan ACK cho yeu cau dong ket noi dong thoi thong bao san sang dong ket noi TCPPackedSend(&tcpSessionTable[i],TCP_ACK_FLAG,0,tcpData); TCPPackedSend(&tcpSessionTable[i],(TCP_FIN_FLAG|TCP_ACK_FLAG),0,tcpData); //Dang le truyen o trang thai CLOSE_WAIT nhung ta thuc hien o day luon TCPCloseSession(i); //Neu khong (dang truyen du lieu) }else{ //Kiem tra ACK tu remote host if((tcpHeader->Flags) & TCP_ACK_FLAG){ //Neu co co ACK thi kiem tra gia tri ACK tcpSessionTable[i].lastRxAck = HTONL((tcpHeader->ackNumber)); if ((tcpSessionTable[i].seqNumber) == HTONL((tcpHeader->ackNumber))){ //Dung ACK #ifdef TCP_DEBUG printf("Got ACK\r\n"); #endif }else{ //Phia ben kia khong nhan duoc du thong tin //Sua loi o day //Process error correction here //Not finish yet, temporary just ignore it and continue with next data //Chua thuc hien tcpSessionTable[i].seqNumber = HTONL((tcpHeader->ackNumber)); #ifdef TCP_DEBUG printf("Miss ACK:got %d\r\nExpected:%d\n\r",HTONL((tcpHeader->ackNumber)),tcpSessionTable[i].seqNumber+1); #endif } } //--Ket thuc kiem tra ACK //Kiem tra sequence number tmp = HTONL((tcpHeader->seqNumber)); //Neu khong dung goi dang cho nhan if (tmp != tcpSessionTable[i].ackNumber){ //there was an error, check what to do next: #ifdef TCP_DEBUG printf("Incorrect seq, got:%d,expexted:%d\r\n",tmp,tcpSessionTable[i].ackNumber); #endif if (tmp < tcpSessionTable[i].ackNumber){ //Neu dang doi du lieu bat dau tu byte thu n nhung ta nhan duoc doan du lieu bat dau tu (n-k) //Tinh phan du lieu thua (k = n - (n-k)) tmp = (tcpSessionTable[i].ackNumber - tmp); //Neu doan du lieu thua it hon du lieu nhan duoc if(tmp < dataLen){ //Bo di phan du lieu thua, nhan phan con lai tcpData += tmp; dataLen = dataLen - tmp; }else{ //Neu tat ca du lieu nhan duoc deu thua //Gui lai ACK, bo goi vua nhan duoc dataLen = 0; TCPPackedSend(&tcpSessionTable[i],(TCP_ACK_FLAG),0,tcpData); return; } //Neu seq > ack (tuc la co 1 doan du lieu bi mat) }else{ //tmp > tcp.... //Yeu cau gui lai TCPPackedSend(&tcpSessionTable[i],(TCP_ACK_FLAG),0,tcpData); return; } } //Neu thuc thi den day nghia la sequence number == ack number (chinh xac) //--Ket thuc kiem tra so tuan tu //Kiem tra chieu dai buffer de chac chan la chieu dai du lieu nhan duoc khong qua buffer // if (tcpData > (buffer + ETHERNET_BUFFER_SIZE)) tcpData = (buffer + ETHERNET_BUFFER_SIZE); if ((tcpData + dataLen) > buffer + ETHERNET_BUFFER_SIZE){ dataLen = (buffer + ETHERNET_BUFFER_SIZE) - tcpData; } // //Cap nhat ack cho lan nhan ke tiep tcpSessionTable[i].ackNumber = tcpSessionTable[i].ackNumber + dataLen; #ifdef TCP_DEBUG printf("Data length (%d), buffer size(%d)\n\r",dataLen,(buffer + ETHERNET_BUFFER_SIZE - tcpData)); printf("Ack Number (%d)\n\r",tcpSessionTable[i].ackNumber); #endif //Goi tiep theo gui di se co co ACK tcpSessionTable[i].nextAck = 1; //Goi ham xu ly lop ung dung if(dataLen != 0){ (tcpSessionTable[i].appDataIn)(tcpData, dataLen,&tcpSessionTable[i]); } } //--Ket thuc xu ly truong hop dang truyen du lieu break; //Neu la trang thai doi LAST_ACK (2 phia deu san sang dong ket noi, dang doi xac nhan ack cuoi cung) case(TCP_STATE_LAST_ACK): //socket is closed tmp = HTONL((tcpHeader->seqNumber)); //Kiem tra ACK, neu dung ACK if (tmp == tcpSessionTable[i].seqNumber + 1){ TCPCloseSession(i); }else{ //Gui lai co FIN & ACK TCPPackedSend(&tcpSessionTable[i], (TCP_FIN_FLAG|TCP_ACK_FLAG), 0, tcpData); } break; //Truong hop ngat ket noi thu dong, da nhan co FIN tu remote host va xac nhan case(TCP_STATE_CLOSE_WAIT): //Truong hop nay se khong xay ra vi o tren ta chuyen truc tiep // sang LAST_ACK khi nhan duoc yeu cau dong ket noi tcpSessionTable[i].sesState = TCP_STATE_LAST_ACK; if(dataLen){ tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber)) + dataLen; }else{ //Neu dataLen == 0 thi cung tang so tuan tu len 1 tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1; } //tcpSessionTable[i].seqNumber = HTONL((tcpHeader->ackNumber)); TCPPackedSend(&tcpSessionTable[i], (TCP_FIN_FLAG|TCP_ACK_FLAG), 0, tcpData); break; //Truong hop dang o trang thai FIN WAIT 1 (da truyen du lieu xong, // san sang dong ket noi va da gui di co FIN va dang cho ACK) case(TCP_STATE_FIN_WAIT1): //if we receive FIN tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1; if (tcpHeader->Flags == TCP_FIN_FLAG){ //Neu chi nhan duoc co FIN //Chuyen sang trang thai CLOSING va gui ACK tcpSessionTable[i].sesState = TCP_STATE_CLOSING; TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData); //tcpSessionTable[i].seqNumber++; #ifdef TCP_DEBUG printf("Closing\n\r"); #endif }else if(tcpHeader->Flags == (TCP_FIN_FLAG | TCP_ACK_FLAG)){ //Neu nhan dong thoi FIN va ACK //Chuyen sang trang thai TIME_WAIT va gui ACK // nhung o day do chua co timer nen ta chuyen luon sang dong ket noi if (HTONL((tcpHeader->ackNumber)) == tcpSessionTable[i].seqNumber){ //TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData); TCPCloseSession(i); #ifdef TCP_DEBUG printf("End\n\r"); #endif }else{ //Neu khong dung ack cho thong bao FIN //Chuyen sang cho co ACK cuoi cung tcpSessionTable[i].sesState = TCP_STATE_LAST_ACK; #ifdef TCP_DEBUG printf("Last ack\n\r"); #endif } //Gui xac nhan cho co FIN TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData); //tcpSessionTable[i].seqNumber++; }else if(tcpHeader->Flags == TCP_ACK_FLAG){ //Neu chi nhan duoc ACK //Chuyen sang trang thai FIN WAIT2 tcpSessionTable[i].sesState = TCP_STATE_FIN_WAIT2; #ifdef TCP_DEBUG printf("Fin wait 2\n\r"); #endif } break; //Neu dang o trang thai FIN WAIT 2 (san sang dong ket noi va gui co FIN, // phia ben kia da xac nhan nhung van chua san sang dong ket noi case(TCP_STATE_FIN_WAIT2): //Neu nhan duoc co FIN if (tcpHeader->Flags & TCP_FIN_FLAG){ if(dataLen){ tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+dataLen; }else{ tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1; } //FIN -> goto TIMED WAIT tcpSessionTable[i].sesState = TCP_STATE_TIMED_WAIT; TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData); //Chua co timer thi dong ket noi o day luon TCPCloseSession(i); #ifdef TCP_DEBUG printf("End\n\r"); #endif } break; case(TCP_STATE_TIMED_WAIT): break; case(TCP_STATE_CLOSING): tcpSessionTable[i].sesState = TCP_STATE_TIMED_WAIT; break; default: TCPCloseSession(i); } //we must set timed wait TTL here because timed wait is not packet triggered if (tcpSessionTable[i].sesState == TCP_STATE_TIMED_WAIT){ tcpSessionTable[i].timeOut = 5; //5 seconds timeout } return; } //--------------------------------------------------------------------------------------
Hay là mọi người cứ từ từ nghiên cứu, chỗ nào không hiểu thì cứ hỏi . Giờ nghĩ tới viết giải thích cho code thấy nản quá. Viết giải thích cho code có khi còn khó hơn viết code .Last edited by nttam79; 10-11-2011, 11:55.
Comment
-
Giao thức UDP:
Tiếp theo, ta chuyển sang giao thức UDP, trong 3 giao thức ở lớp này (TCP, UDP và ICMP) thì UDP là giao thức đơn giản nhất, dễ viết nhất.
Trong chồng giao thức IP, nhiệm vụ của UDP là khi nhận 1 segment dữ liệu từ ứng dụng gửi xuống, nó sẽ gửi đi ngay đến địa chỉ IP và port được yêu cầu mà không cần đánh số thứ tự, bắt tay thiết lập kết nối hay thậm chí không quan tâm đến việc dữ liệu đó có đến được đích hay không.
Header của giao thức UDP rất đon giản: chỉ gồm có 4 trường: port nguồn, port đích, chiều dài gói tin và checksum.
Trong thực tế, UDP được sử dụng để gửi đi các dữ liệu mà yêu cầu về độ trễ nhỏ quan trọng hơn yêu cầu về độ tin cậy. Ví dụ như dữ liệu của các video stream, audio stream, các báo hiệu nhanh, hay đơn giản là tương tác trong các game online.
Vậy ta mở file “packet.h” thêm khai báo header UDP vào:
Code://-------------------------------------------------------------------------------------- //Cau truc UDP header struct ntUDPHeader { unsigned int srcPort; unsigned int desPort; unsigned int Len; unsigned int Checksum; }; #define UDP_HEADER_LEN 8
“udp.c”
Code://---------------------------------------------------------------------------- // Writen by NTTam - PTITHCM //---------------------------------------------------------------------------- #include "packet.h" #include "ip.h" #include "uart.h"
Code://---------------------------------------------------------------------------- // Writen by NTTam - PTITHCM //---------------------------------------------------------------------------- #ifndef UDP_H #define UDP_H //---------------------------------------------------------------------------- #endif //UDP_H
Hàm gửi gói tin bằng UDP:
Code://---------------------------------------------------------------------------- //Ham gui di mot goi UDP void udpSend(unsigned long dstIp, unsigned int dstPort, unsigned int len, unsigned char* udpData) { struct ntUDPHeader* udpHeader; udpHeader = (struct ntUDPHeader*)(udpData - UDP_HEADER_LEN); len += UDP_HEADER_LEN; udpHeader->desPort = HTONS(dstPort); udpHeader->srcPort = HTONS(dstPort); udpHeader->Len = HTONS(len); udpHeader->Checksum = 0; ipSend(dstIp, IP_PROTO_UDP, len, (unsigned char*)udpHeader); }
Code://-------------------------------------------------------------------------------------- //Ham xu ly goi UDP nhan duoc, duoc goi boi ham xu ly goi IP (IPProcess) // Hien chua co ung dung chay UDP nen ham nay trong void UDPProcess(unsigned int len, struct ntIPHeader* packet) { dhcpIn((len - IP_HEADER_LEN - UDP_HEADER_LEN), (struct netDhcpHeader*)((char*)packet - IP_HEADER_LEN - UDP_HEADER_LEN)); #ifdef NET_DEBUG printf("NetStack UDP/IP Rx Dummy Handler\r\n"); #endif }
Tiếp theo sẽ là DHCP và HTTP, xong cái này là các bạn có thể truy cập web trên mạch được rồi (nếu có mạch ).
Comment
-
Đã built xong code đến phần Ping được. Trong quá trình làm theo anh Tâm có vài điểm anh Tâm nói chưa rõ lắm nên hôm nay Huy port lên phần code mới làm xong và biên dịch OK.
Anh Tâm có nhầm một chỗ như sau :
Trong hàm này ta có sử dụng định nghĩa vector ngắt (ISR), do đó ta cần include file tương ứng vào. Thêm dòng này vào đầu file "ehternet.c"
Code:
#include <avr/interrupt.h>
Trong hàm này, ta sử dụng 2 biến toàn cục là eth_got_frame và time_watchdog, hai biến này cần được khai báo trong file “enc28j60.c” (nên để ở dầu file) thay bằng ethernet.c
Code:
unsigned char eth_got_frame = 0;
volatile unsigned int time_watchdog;
Và ntAVRnet.c cần include như thế này
<
#include <avr/io.h>
#include "ntAVRnet.h"
#include "ip.h"
extern struct ipConfig IpMyConfig;
>
Có gì sai anh Tâm chỉnh dùm nha. Tối nay về nạp vào mạch rồi Ping thôi. keke
AVRnet NTT.zip
Email:
Tel: 0983.497.310
Comment
-
Nguyên văn bởi tienhuypro Xem bài viếtĐã built xong code đến phần Ping được. Trong quá trình làm theo anh Tâm có vài điểm anh Tâm nói chưa rõ lắm nên hôm nay Huy port lên phần code mới làm xong và biên dịch OK.
Anh Tâm có nhầm một chỗ như sau :
Trong hàm này ta có sử dụng định nghĩa vector ngắt (ISR), do đó ta cần include file tương ứng vào. Thêm dòng này vào đầu file "ehternet.c"
Code:
#include <avr/interrupt.h>
Trong hàm này, ta sử dụng 2 biến toàn cục là eth_got_frame và time_watchdog, hai biến này cần được khai báo trong file “enc28j60.c” (nên để ở dầu file) thay bằng ethernet.c
Code:
unsigned char eth_got_frame = 0;
volatile unsigned int time_watchdog;
Và ntAVRnet.c cần include như thế này
<
#include <avr/io.h>
#include "ntAVRnet.h"
#include "ip.h"
extern struct ipConfig IpMyConfig;
>
Có gì sai anh Tâm chỉnh dùm nha. Tối nay về nạp vào mạch rồi Ping thôi. keke
[ATTACH]35223[/ATTACH]
[ATTACH=CONFIG]35224[/ATTACH]
Cảm ơn tienhuypro nhé.
Comment
-
IP checksum tôi đã giải thích ở post trước rồi mà, chương trình này đã test trên mạch, debug bản tin bằng wireshark và chạy chính xác. Nếu bạn test trên các môi trường khác thì chú ý là trật tự các byte thấp, byte cao trong số 16 bit cũng như trên buffer có thể khác nhau giữa trên máy tính và trên AVR cũng như các VĐK khác. điều này sẽ dẫn đến sai checksum nhé. Bạn có thể cho biết bạn chạy như thế nào để kiểm tra đúng hay sai không?
Comment
-
Em biết avr lưu kiểu big endian.Em cũng hiểu cái giải thuật đó.Cộng giá trị 16bit nếu giá trị cộng trên 16bit thì cộng 1 với 16bit thấp.Cộng đến khi kô còn trên 16bit.Em viết trên cfree thì đúng,trên codevision nó chạy kô đúng,dịch phải 16bit toàn nhận giá trị 0., , ,
Comment
-
-
Thêm code vì không cho up >5 fileAttached FilesLast edited by tienhuypro; 11-11-2011, 00:42.
Email:
Tel: 0983.497.310
Comment
-
Nguyên văn bởi tienhuypro Xem bài viếtChào các bạn !
Code anh Tâm viết rất ổn mình đã test Ping OK rồi nhưng phải sửa lại tí define và code để phù hợp với mạch mình thiết kế. Mình port vài cái hình và code test cho Board bà con xem nhé !
@Huy: nếu đã ping được thì Webserver, điều khiển qua Internet,... chỉ là chuyện nhỏ, vì như vậy là phần hardware giao tiếp ethernet và giao thức IP đã chạy OK, còn lại sử dụng thế nào là do các bạn thôi.
TienHuy đúng là dân pro thiệt đó, mặc dù viết hướng dẫn nhưng mình biết tự buid được mạch và code của mình theo đó cũng là rất khó, hướng dẫn chỉ là chung chung thôi. Huy có thể thay title của file code được rồi đó .
Comment
-
Nguyên văn bởi rptdnmqsNó chạy sai.em tự mò theo datasheet viết code.Rồi đối chiếu với code của thầy Tâm.Dịch xong debug bằng avrstudio chạy sai mất.Nên em chèn asm trong codevision.Nhưng lại chưa rõ cách chèn.Cũng mò tiếp thấy nó dịch vẫn sai nên em cứ loay hoay cái checksum.Chẳng biết sao nữa đành dÙng winavr vậy.Giá mà nó dịch được như thằng CCS thì tốt quá.Ôi 1 chút vấn đề làm mất thời gian.Em xin lỗi vì đã làm phiền.Thanks!.
Comment
-
Nguyên văn bởi dinh_dongBác Huy cho cái đơn giá board Bác làm em với, em đang sắp làm, đi mua linh kiện, mà chưa biết khoảng bao nhiêu.
Bác có ở TP HCM không? Ở nhật tảo mua linh kiện ở đâu thì okey zị.? Tks bác.
Có cái hóa đơn luôn nè keke
Email:
Tel: 0983.497.310
Comment
-
Nguyên văn bởi nttam79 Xem bài viếtMừng quá , vậy là code mình post hướng dẫn không có gì sai. Vẫn biết là chương trình mình viết thì chạy nhưng không biết post lên có sai sót gì không và mọi người có làm theo được không.
@Huy: nếu đã ping được thì Webserver, điều khiển qua Internet,... chỉ là chuyện nhỏ, vì như vậy là phần hardware giao tiếp ethernet và giao thức IP đã chạy OK, còn lại sử dụng thế nào là do các bạn thôi.
TienHuy đúng là dân pro thiệt đó, mặc dù viết hướng dẫn nhưng mình biết tự buid được mạch và code của mình theo đó cũng là rất khó, hướng dẫn chỉ là chung chung thôi. Huy có thể thay title của file code được rồi đó .
Hardware OK là mừng rùi vì nhìu bạn có thể tự làm cho đỡ tốn kém. Hjhj
Port lại cái mạch vì có sửa lại kích thước chân linh kiện, Via lớn hơn và lỗi thiếu dây ở chân thạch anh 25Mhz(lúc hàn mạch mới phát hiện) để các bạn dễ ủi.Attached FilesLast edited by tienhuypro; 11-11-2011, 01:40.
Email:
Tel: 0983.497.310
Comment
-
Giải thích cho 2 hàm chính trong giao thức TCP:
Hàm TCPPackedSend:
Code:void TCPPackedSend(struct tcpSession *pSession, unsigned char Flags, unsigned int len, unsigned char *dataBuffer)
- pSession là con trỏ, trỏ đến struct tcpSession trong bảng TCP Session Table tương ứng với phiên kết nối TCP mà ta muốn gửi gói tin đi (trong phần lập trình giao thức TCP này, ta hỗ trợ việc AVR đồng thời theo dõi và truyền data với nhiều kết nối (nhiều client) cùng lúc).
- Flags là các cờ tương ứng mà ta muốn set trong header TCP
- len: chiều dài buffer dữ liệu ứng dụng.
- dataBuffer: buffer chứa dữ liệu ứng dụng.
Cấu trúc frame dữ liệu mà ENC28J60 sẽ gửi đi như sau:
Lúc này, dataBuffer đang trỏ đến phần Application Data trong frame trên, biến len đang là chiều dài phần data này.
Khai báo các biến sử dụng trong hàm:
Code:unsigned int tmp; unsigned long checksum32;
Tiếp theo, ta khai báo 2 con trỏ, trỏ đến vùng IP Header và TCP Header (mới khai báo, chưa gán địa chỉ):
Code:struct ntTCPHeader* tcpHeader; struct ntIPHeader* ipHeader;
Code:if(Flags & TCP_SYN_FLAG){ //Option data dataBuffer[0] = 0x02; dataBuffer[1] = 0x04; dataBuffer[2] = (MAX_SEGMENT_SIZE >> 8) & 0xff; dataBuffer[3] = MAX_SEGMENT_SIZE & 0xff; dataBuffer[4] = 0x01; dataBuffer[5] = 0x03; dataBuffer[6] = 0x03; dataBuffer[7] = 0x00; }
Code:dataBuffer -= TCP_HEADER_LEN; tcpHeader = (struct ntTCPHeader*)dataBuffer;
- Source port và Des port lấy từ thông tin về session tương ứng:
Code:tcpHeader->srcPort = HTONS(pSession->srcPort); tcpHeader->desPort = HTONS(pSession->desPort);
Code:tcpHeader->seqNumber = HTONL(pSession->seqNumber);
Code:pSession->seqNumber = pSession->seqNumber + len;
Code:if(Flags & (TCP_FIN_FLAG|TCP_SYN_FLAG)) (pSession->seqNumber)++;
Code:tcpHeader->ackNumber = HTONL(pSession->ackNumber);
Code:if(Flags & TCP_SYN_FLAG){ tcpHeader->Offset = (0x07<<4); len += (TCP_HEADER_LEN + 8);
Code:}else{ tcpHeader->Offset = (0x05<<4); len += TCP_HEADER_LEN; }
Code:tcpHeader->Flags = Flags;
Code:tcpHeader->Window = HTONS(pSession->srcWin);//((NETSTACK_BUFFERSIZE-20-14));
Code:tcpHeader->Checksum = 0;
Code:tcpHeader->UrgentPtr = 0x0000;
Code:ipHeader = (struct ntIPHeader*)(dataBuffer-IP_HEADER_LEN);
Code:ipHeader->srcIPAddr = HTONL(ipGetConfig()->ip); ipHeader->desIPAddr = HTONL(pSession->desIP); ipHeader->Checksum = HTONS(len); ipHeader->TTL = 0x00; ipHeader->Protocol = IP_PROTO_TCP;
Tính checksum và ghi vào trường checksum của Header TCP
Code:checksum32 = 0; tmp = len + 12; tmp = checksum (((unsigned char *)ipHeader+8), tmp, checksum32); tcpHeader->Checksum = HTONS(tmp);
Code:ipSend(pSession->desIP, IP_PROTO_TCP, len, (unsigned char *)tcpHeader);
Comment
Bài viết mới nhất
Collapse
-
Trả lời cho Thắc mắc về nguồn tổ ong 12vbởi tuyennhanCách ly dây điện vào , bộ nguồn và đèn khỏi khung xe thì có rò thật cũng không lo bị giật .
-
Channel: Điện tử dành cho người mới bắt đầu
Hôm qua, 08:56 -
-
Trả lời cho Hỏi cách điều chế xungbởi thetungBạn cho qua cái Tờ ri gơ Sờ mít ấy ......
-
Channel: Kỹ thuật điện tử tương tự
16-12-2024, 11:26 -
-
Trả lời cho Hỏi cách điều chế xungbởi nguyendinhvanCó gì mà khó ?
Răn cưa vuông đây
...-
Channel: Kỹ thuật điện tử tương tự
15-12-2024, 23:36 -
-
Trả lời cho hỏi về tụ điệnbởi ndp62Chữ " VENT" không phải là tên hãng sx tụ đâu ,vó thế là 1 ký hiệu liên quan tụ lowesr ?
-
Channel: Điện thanh
15-12-2024, 18:24 -
-
Trả lời cho Thắc mắc về nguồn tổ ong 12vbởi bqvietTrừ trường hợp công suất (rất) thấp, hầu như tất cả các loại nguồn xung thông thường đều có tụ nhỏ 1 - 10nF nối giữa sơ cấp và thứ cấp, để thoát nhiễu và để chống hiện tượng tương tự tĩnh điện. Vụ này đã thảo luận vài...
-
Channel: Điện tử dành cho người mới bắt đầu
14-12-2024, 22:02 -
-
Trả lời cho Thắc mắc về nguồn tổ ong 12vbởi namlangnhoE thử 3 cái nguồn nó đều giống nhau. Nên e làm tiếp địa luôn.
-
Channel: Điện tử dành cho người mới bắt đầu
14-12-2024, 19:58 -
-
Trả lời cho Thắc mắc về nguồn tổ ong 12vbởi mèomướpDạ chú sắm con át chống giật và thay nguồn tổ ong khác cho an toàn ạ. Đa phần nguồn xung đều xả nhiễu của bên thứ cấp về điện lưới qua 1 con tụ nên cảm giác tê sẽ khó xác định rõ ràng là do rò điện hay là nó vốn vậy...
-
Channel: Điện tử dành cho người mới bắt đầu
14-12-2024, 18:51 -
-
bởi namlangnhoXin chào mọi người. E có sử dụng 1 cục nguồn tổ ong 12v-30A chạy đèn led xe trà sữa. Mà thợ thi công bị rò điện nên điện rò ra khung xe. E dùng đồng hồ đo điện ở khung xe và cả output thì thấy có dòng điện xoay chiều hơn 100v. Nên chạm...
-
Channel: Điện tử dành cho người mới bắt đầu
14-12-2024, 00:12 -
-
bởi Manh.n.trCác bác cho em hỏi cách điều chế xung răng cưa sang xung vuông với ạ. Em đang thấy khó ạ...
-
Channel: Kỹ thuật điện tử tương tự
13-12-2024, 20:46 -
Comment