/** * Returns the number of bytes that can be read from the given buffer. * * @param bufID The buffer ID, is a number from 0 to n identifying the buffer * * @return The number of bytes that can be read from the given buffer */ BYTE busIsGetReady(BYTE bufID) { if (bufID >= BUS_BUFFERS) { #if (DEBUG_BUS >= LOG_ERROR) debugPutMsg(1); //@mxd:1:busIsGetReady called with invalid bufID: %d debugPutByte(bufID); #endif return 0; } //Get pointer to buffer activeBuf = busInfo.buf[bufID]; /* debugPutGenMsg(2); //@mxd:2:%s debugPutRomStringXNull("busGetReady = "); debugPutByte(5); debugPutByte(0); //Null terminate string */ #if (DEBUG_BUS >= LOG_DEBUG) debugPutMsg(3); //@mxd:3:busIsGetReady returned %d debugPutByte(bufID); #endif //return ((busInfo.put[bufID] - busInfo.get[bufID]) & (getBufSize(bufID)-1)); //return (busInfo.put[bufID] - busInfo.get[bufID]); return (busInfo.put[1] - busInfo.get[1]); //return (put - get); }
/** * Initialization code. */ void busInit(void) { BYTE i; //Initialize busInfo structure with configured values from EEPROM memclr(&busInfo, sizeof(busInfo)); //Clear busInfo structure busInfoInit(); //Initialze serial buses serInit(); #if defined(BRD_SBC65EC) ser2Init(); #endif i2cBusInit(); /* debugPutGenMsg(2); //@mxd:2:%s debugPutRomStringXNull((ROM char*)"Bus Ser1 Txbuf = 0x"); debugPutByteHex( (BYTE)(((WORD)busInfo.buf[BUSID_SER1].txBuf)>>8) ); debugPutByteHex( (BYTE)busInfo.buf[BUSID_SER1].txBuf ); debugPutByte(0); //Null terminate string debugPutGenMsg(2); //@mxd:2:%s debugPutRomStringXNull((ROM char*)"Bus Ser1 Rxbuf = 0x"); debugPutByteHex( (BYTE)(((WORD)busInfo.buf[BUSID_SER1].rxBuf)>>8) ); debugPutByteHex( (BYTE)busInfo.buf[BUSID_SER1].rxBuf ); debugPutByte(0); //Null terminate string */ #if (DEBUG_BUS >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Initialized Serial Buses #endif }
/** * Function for performing MAC related tasks * * @preCondition Must be called every couple of ms */ void MACTask(void) { #if (DEBUG_MAC >= LOG_WARN) BYTE tmpSum; char buf[5]; #endif #if defined(MAC_CNTR1_3) cntr0.Val += NICGet(CNTR0); cntr1.Val += NICGet(CNTR1); cntr2.Val += NICGet(CNTR2); #endif #if (DEBUG_MAC >= LOG_WARN) tmpSum = LSB(cntr0) + MSB(cntr0) + LSB(cntr1) + MSB(cntr1) + LSB(cntr2) + MSB(cntr2); //If any of the error counter have changed, print them out! if (cntrSum != tmpSum) { debugPutMsg(1); //@mxd:1:Frame Alignment=%s, CRC=%s, Missed Packets=%s itoa(cntr0.Val, buf); debugPutString(buf); itoa(cntr1.Val, buf); debugPutString(buf); itoa(cntr2.Val, buf); debugPutString(buf); cntrSum = tmpSum; } #endif }
/** * Returns the number of bytes that can be written to the given buffer. * * @param bufID The buffer ID, is a number from 0 to n identifying the buffer * * @return The number of bytes that can be written to the given buffer */ BYTE busIsPutReady(BYTE bufID) { if (bufID >= BUS_BUFFERS) { #if (DEBUG_BUS >= LOG_ERROR) debugPutMsg(2); //@mxd:2:busIsPutReady called with invalid buffer ID: %d debugPutByte(bufID); #endif return 0; } // TEST TEST return 8; }
BOOL FTPVerify(char *login, char *password) { #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(4); //@mxd:4:Received FTP Login (%s) and Password (%s) debugPutString(login); debugPutString(password); #endif if (strcmpee2ram(login, APPCFG_USERNAME0) == 0) { if (strcmpee2ram(password, APPCFG_PASSWORD0) == 0) { return TRUE; } } return FALSE; }
/** * Enables the DHCP Client. * Enables the DHCP client if it is disabled. If it is already enabled, * nothing is done. */ void DHCPEnable(void) { if(smDHCPState == SM_DHCP_DISABLED) { //Set DHCP flag appcfgPutc(APPCFG_NETFLAGS, appcfgGetc(APPCFG_NETFLAGS) | APPCFG_NETFLAGS_DHCP); smDHCPState = SM_DHCP_GET_SOCKET; DHCPBindCount = 0; DHCPFlags.bits.bIsBound = FALSE; } #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(15); //@mxd:15:Enabled #endif }
/********************************************************************* * Function: TFTP_RESULT TFTPIsOpened(void) * * PreCondition: TFTPOpen() is already called. * * Input: None * * Output: TFTP_OK if previous call to TFTPOpen is complete * * TFTP_TIMEOUT if remote host did not respond to * previous ARP request. * * TFTP_NOT_READY if remote has still not responded * and timeout has not expired. * * Side Effects: None * * Overview: Waits for ARP reply and opens a UDP socket * to perform further TFTP operations. * * Note: Once opened, application may keep TFTP socket * open and future TFTP operations. * If TFTPClose() is called to close the connection * TFTPOpen() must be called again before performing * any other TFTP operations. ********************************************************************/ TFTP_RESULT TFTPIsOpened(void) { switch(_tftpState) { default: DEBUG(printf("Resolving remote IP...\n")); // Check to see if adddress is resolved. if ( ARPIsResolved(&MutExVar.group1._hostInfo.IPAddr, &MutExVar.group1._hostInfo.MACAddr) ) { _tftpSocket = UDPOpen(TFTP_CLIENT_PORT, &MutExVar.group1._hostInfo, TFTP_SERVER_PORT); if( _tftpSocket == INVALID_UDP_SOCKET ) { #if (DEBUG_TFTPC >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Could not open UDP socket #endif } _tftpState = SM_TFTP_READY; } else break; case SM_TFTP_READY: // Wait for UDP to be ready. Immediately after this user will // may TFTPGetFile or TFTPPutFile and we have to make sure that // UDP is read to transmit. These functions do not check for // UDP to get ready. if ( UDPIsPutReady(_tftpSocket) ) return TFTP_OK; } // Make sure that we do not do this forever. if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_ARP_TIMEOUT_VAL ) { _tftpStartTick = TickGet(); // Forget about all previous attempts. _tftpRetries = 1; return TFTP_TIMEOUT; } return TFTP_NOT_READY; }
/** * Disables the DHCP Client. * Disables the DHCP client by sending the state machine to * "SM_DHCP_DISABLED". If the board was previously configured by DHCP, the * configuration will continue to be used but the module will no longer * preform any renewals. */ void DHCPDisable(void) { if(DHCPSocket != INVALID_UDP_SOCKET) { UDPClose(DHCPSocket); DHCPSocket = INVALID_UDP_SOCKET; } smDHCPState = SM_DHCP_DISABLED; //Clear DHCP flag appcfgPutc(APPCFG_NETFLAGS, appcfgGetc(APPCFG_NETFLAGS) & ~APPCFG_NETFLAGS_DHCP); #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(14); //@mxd:14:Disabled #endif }
/** * Reads the given amount of bytes via Remote DMA from the current MAC Receive buffer. * If the end of the RX Buffer is reached, this function automatically rolls over to * the first page of the RX Ring Buffer. See PreConditions above for more info. * * @preCondition Remote DMA address has to be set up prior to calling this function. * The Remote DMA registers are NOT configured by this function, * and simply continue reading from the current "Remote DMA Address". A function * like MACRxbufGetHdr() can be called prior to this function to configure Remote * DMA to read the next packet in RX Buffer (situated in Remote DMA RAM) * * @param len Length of array to be read * @param val Buffer to read packet into * * @return Number of bytes read * */ WORD MACRxbufGetArray(BYTE *val, WORD len) { #if defined(__18CXX) overlay #endif WORD_VAL t; t.Val = len; //Configure RBCR (Remote Byte Count Register) for bytes to be read via DMA FirstFastNICPut(RBCR0, t.byte.LSB); FastNICPut(RBCR1, t.byte.MSB); //Remote DMA Read command. This causes given (RBCR0 & 1) number of bytes, starting at given //address (RSAR0 & 1) set by NICSetAddr() to be read with each I/O read cycle. FastNICPut(CMDR, 0x0a); //Update DMAAddr for what it will be after all requested bytes are read DMAAddr.Val += len; if (DMAAddr.v[1] >= RXSTOP) { //If end of MAC Receive buffer is reached, roll over to beginning of buffer DMAAddr.Val -= (RXPAGES << 8); } //Read requested number of bytes from I/O port TRISD = 0xff; //Input WRITE_NIC_ADDR(NIC_DATAPORT); while( len-- > 0 ) { BEGIN_IO_CYCLE(); NIC_IOR_IO = 0; WAIT_FOR_IOCHRDY(); *val++ = NIC_DATA_IO; NIC_IOR_IO = 1; LEAVE_IO_CYCLE(); } #if (DEBUG_MAC >= LOG_ERROR) if (DMAAddr.Val != MACGetNICAddr()) { debugPutMsg(2); } #endif return t.Val; }
/** * Resets the DHCP Client. Resets the DHCP Client, giving up any current lease, knowledge of * DHCP servers, etc. */ void DHCPReset(void) { // Do nothing if DHCP is disabled if(smDHCPState == SM_DHCP_DISABLED) return; if(DHCPSocket != INVALID_UDP_SOCKET) smDHCPState = SM_DHCP_SEND_DISCOVERY; else smDHCPState = SM_DHCP_GET_SOCKET; #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(13); //@mxd:13:Reset! #endif DHCPBindCount = 0; DHCPFlags.bits.bIsBound = FALSE; }
/** * Reset the NIC */ void NICReset(void) { #if (DEBUG_MAC >= LOG_INFO) debugPutMsg(5); //@mxd:5:Reset MAC #endif TRISD = 0xff; //Input WRITE_NIC_ADDR(0); NIC_IOW_IO = 1; NIC_IOR_IO = 1; NIC_RESET_IO = 1; NIC_CTRL_TRIS = 0x00; // Reset pulse must be at least 800 ns. Delay10us(1); DelayMs(5); NIC_RESET_IO = 0; }
/** * This function is a "callback" from HTTPServer task. For each HTTP Header found in the HTTP Request * message from the client, this function is called. The application has the chance to parse the * received headers. * * @param httpInfo HTTP_INFO structure of current HTTP connection * @param hdr Buffer containing NULL terminated header to handle * @param rqstRes Name of the Requested resource - GET command's action. All characters are in uppercase! */ void HTTPProcessHdr(HTTP_INFO* httpInfo, BYTE* hdr, BYTE* rqstRes) { BYTE i; char unpw[20]; //Buffer for storing username and password, seperated by ':' char base64[25]; //Buffer for storing base64 result //Check if buffer begins with ROM string, ignore case if (strBeginsWithIC((char*)hdr, HTTPHDR_AUTHORIZATION)) { i = strcpyee2ram(unpw, APPCFG_USERNAME0, 8); //Returns number of bytes written, excluding terminating null unpw[i++] = ':'; //Overwrite terminating null with ':' strcpyee2ram(&unpw[i], APPCFG_PASSWORD0, 8); base64Encode((char*)base64, (char*)unpw, strlen(unpw)); if (strcmp( (char*)(&hdr[sizeof(HTTPHDR_AUTHORIZATION)-1]), base64) == 0) { httpInfo->flags.bits.bUserLoggedIn = TRUE; #if (DEBUG_MAIN >= LOG_DEBUG) debugPutMsg(6); //@mxd:6:HTTP User Authenticated #endif } } }
/** * Initializes "UDP Command Port" and "UDP Event Port". These * ports are used for sending and receiving and commands via the UDP port. * */ void evtInit(void) { NODE_INFO udpServerNode; activeEventPorts = 0; //Initialize to idle state smEvt = SM_EVT_INIT; //Initialize remote IP and MAC address of udpServerNode with 0, seeing that we don't know them for the node //that will send us an UDP message. The first time a message is received addressed to this port, the //remote IP and MAC addresses are automatically updated with the addresses of the remote node. memclr(&udpServerNode, sizeof(udpServerNode)); //Configure for local port 54124 and remote port INVALID_UDP_PORT. This opens the socket to //listen on the given port. udpSocketEvt = UDPOpen(EVENT_UDPPORT, &udpServerNode, INVALID_UDP_PORT); //An error occurred during the UDPOpen() function if (udpSocketEvt == INVALID_UDP_SOCKET) { #if (DEBUG_CMD >= LOG_ERROR) debugPutMsg(17); //@mxd:17:Could not open UDP event port #endif } }
/********************************************************************* * Function: void AnnounceIP(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: AnnounceIP opens a UDP socket and transmits a * broadcast packet to port 30303. If a computer is * on the same subnet and a utility is looking for * packets on the UDP port, it will receive the * broadcast. For this application, it is used to * announce the change of this board's IP address. * The messages can be viewed with the MCHPDetect.exe * program. * * Note: A UDP socket must be available before this * function is called. It is freed at the end of * the function. MAX_UDP_SOCKETS may need to be * increased if other modules use UDP sockets. ********************************************************************/ void AnnounceIP(void) { UDP_SOCKET MySocket; NODE_INFO Remote; BYTE i; // Set the socket's destination to be a broadcast over our IP // subnet // Set the MAC destination to be a broadcast memset(&Remote, 0xFF, sizeof(Remote)); // Open a UDP socket for outbound transmission MySocket = UDPOpen(2860, &Remote, ANNOUNCE_PORT); // Abort operation if no UDP sockets are available // If this ever happens, incrementing MAX_UDP_SOCKETS in // StackTsk.h may help (at the expense of more global memory // resources). if( MySocket == INVALID_UDP_SOCKET ) { #if (DEBUG_ANNOUNCE >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Could not open UDP socket #endif return; } // Make certain the socket can be written to while( !UDPIsPutReady(MySocket) ) FAST_USER_PROCESS(); // Begin sending our MAC address in human readable form. // The MAC address theoretically could be obtained from the // packet header when the computer receives our UDP packet, // however, in practice, the OS will abstract away the useful // information and it would be difficult to obtain. It also // would be lost if this broadcast packet were forwarded by a // router to a different portion of the network (note that // broadcasts are normally not forwarded by routers). for(i=0; i < 15; i++) //First 15 (0-14) characters are NetBIOS name, 16th character is 0x00 { UDPPut(NETBIOS_NAME_GETCHAR(i)); } UDPPut('\r'); UDPPut('\n'); // Convert the MAC address bytes to hex (text) and then send it i = 0; while(1) { UDPPut(btohexa_high(AppConfig.MyMACAddr.v[i])); UDPPut(btohexa_low(AppConfig.MyMACAddr.v[i])); if(++i == 6) break; UDPPut('-'); } UDPPut('\r'); UDPPut('\n'); // Send some other human readable information. UDPPut('D'); UDPPut('H'); UDPPut('C'); UDPPut('P'); UDPPut('/'); UDPPut('P'); UDPPut('o'); UDPPut('w'); UDPPut('e'); UDPPut('r'); UDPPut(' '); UDPPut('e'); UDPPut('v'); UDPPut('e'); UDPPut('n'); UDPPut('t'); UDPPut(' '); UDPPut('o'); UDPPut('c'); UDPPut('c'); UDPPut('u'); UDPPut('r'); UDPPut('r'); UDPPut('e'); UDPPut('d'); // Send the packet UDPFlush(); // Close the socket so it can be used by other modules UDPClose(MySocket); }
/***************************************************************************** Function: void DHCPTask(void) Summary: Performs periodic DHCP tasks. Description: This function performs any periodic tasks requied by the DHCP module, such as sending and receiving messages involved with obtaining and maintaining a lease. Precondition: None Parameters: None Returns: None ***************************************************************************/ void DHCPTask(void) { static TICK eventTime; switch(smDHCPState) { case SM_DHCP_GET_SOCKET: // Open a socket to send and receive broadcast messages on DHCPSocket = UDPOpen(DHCP_CLIENT_PORT, NULL, DHCP_SERVER_PORT); if(DHCPSocket == INVALID_UDP_SOCKET) { #if (DEBUG_DHCP >= LOG_ERROR) debugPutMsg(7); //@mxd:7:Could not open UDP socket #endif break; } smDHCPState = SM_DHCP_SEND_DISCOVERY; // No break case SM_DHCP_SEND_DISCOVERY: if(!UDPIsPutReady(DHCPSocket)) { #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(8); //@mxd:8:Can not Broadcast, UDP Not ready! #endif break; } // Ensure that we transmit to the broadcast IP and MAC addresses // The UDP Socket remembers who it was last talking to memset((void*)&UDPSocketInfo[DHCPSocket].remoteNode, 0xFF, sizeof(UDPSocketInfo[DHCPSocket].remoteNode)); // Assume default IP Lease time of 60 seconds. // This should be minimum possible to make sure that if // server did not specify lease time, we try again after this minimum time. DHCPLeaseTime.Val = 60; ValidValues.Val = 0x00; DHCPBindCount = 0; DHCPFlags.bits.bIsBound = FALSE; DHCPFlags.bits.bOfferReceived = FALSE; // Send the DHCP Discover broadcast _DHCPSend(DHCP_DISCOVER_MESSAGE, FALSE); #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(1); //@mxd:1:Broadcast #endif // Start a timer and begin looking for a response eventTime = TickGet(); smDHCPState = SM_DHCP_GET_OFFER; break; case SM_DHCP_GET_OFFER: // Check to see if a packet has arrived if(UDPIsGetReady_(DHCPSocket) < 250u) { // Go back and transmit a new discovery if we didn't get an offer after 2 seconds if(TickGet() - eventTime >= DHCP_TIMEOUT) { smDHCPState = SM_DHCP_SEND_DISCOVERY; #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(9); //@mxd:9:Discover time out #endif } break; } // Let the DHCP server module know that there is a DHCP server // on this network DHCPFlags.bits.bDHCPServerDetected = TRUE; // Check to see if we received an offer if(_DHCPReceive() != DHCP_OFFER_MESSAGE) break; #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(3); //@mxd:3:Offer Message #endif smDHCPState = SM_DHCP_SEND_REQUEST; // No break case SM_DHCP_SEND_REQUEST: if(!UDPIsPutReady(DHCPSocket)) break; // Send the DHCP request message _DHCPSend(DHCP_REQUEST_MESSAGE, FALSE); #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(12); //@mxd:12:Sending Request #endif // Start a timer and begin looking for a response eventTime = TickGet(); smDHCPState = SM_DHCP_GET_REQUEST_ACK; break; case SM_DHCP_GET_REQUEST_ACK: // Check to see if a packet has arrived if(UDPIsGetReady_(DHCPSocket) < 250u) { // Go back and transmit a new discovery if we didn't get an ACK after 2 seconds if(TickGet() - eventTime >= DHCP_TIMEOUT) smDHCPState = SM_DHCP_SEND_DISCOVERY; break; } // Check to see if we received an offer switch(_DHCPReceive()) { case DHCP_ACK_MESSAGE: UDPClose(DHCPSocket); DHCPSocket = INVALID_UDP_SOCKET; eventTime = TickGet(); smDHCPState = SM_DHCP_BOUND; DHCPFlags.bits.bIsBound = TRUE; DHCPBindCount++; if(ValidValues.bits.IPAddress) AppConfig.MyIPAddr = tempIPAddress; if(ValidValues.bits.Mask) AppConfig.MyMask = tempMask; if(ValidValues.bits.Gateway) AppConfig.MyGateway = tempGateway; #if defined(STACK_USE_DNS) if(ValidValues.bits.DNS) AppConfig.PrimaryDNSServer = tempDNS; if(ValidValues.bits.DNS2) AppConfig.SecondaryDNSServer = tempDNS2; #endif // if(ValidValues.bits.HostName) // memcpy(AppConfig.NetBIOSName, (void*)tempHostName, sizeof(AppConfig.NetBIOSName)); #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(5); //@mxd:5:ACK Received #endif break; case DHCP_NAK_MESSAGE: smDHCPState = SM_DHCP_SEND_DISCOVERY; #if (DEBUG_DHCP >= LOG_WARN) debugPutMsg(4); //@mxd:4:NAK recieved (RSS). DHCP server #endif break; } break; case SM_DHCP_BOUND: // TEST TEST //if(TickGet() - eventTime < TICK_SECOND) if(TickGet() - eventTime < ((TICK)200)) break; // Check to see if our lease is still valid, if so, decrement lease // time if(DHCPLeaseTime.Val >= 2ul) { // TEST TEST //eventTime += TICK_SECOND; eventTime += ((TICK)200); DHCPLeaseTime.Val--; #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(11); //@mxd:11:Lease time expired #endif break; } // Open a socket to send and receive DHCP messages on DHCPSocket = UDPOpen(DHCP_CLIENT_PORT, NULL, DHCP_SERVER_PORT); if(DHCPSocket == INVALID_UDP_SOCKET) break; smDHCPState = SM_DHCP_SEND_RENEW; // No break case SM_DHCP_SEND_RENEW: case SM_DHCP_SEND_RENEW2: case SM_DHCP_SEND_RENEW3: if(!UDPIsPutReady(DHCPSocket)) break; // Send the DHCP request message _DHCPSend(DHCP_REQUEST_MESSAGE, TRUE); DHCPFlags.bits.bOfferReceived = FALSE; // Start a timer and begin looking for a response eventTime = TickGet(); smDHCPState++; break; case SM_DHCP_GET_RENEW_ACK: case SM_DHCP_GET_RENEW_ACK2: case SM_DHCP_GET_RENEW_ACK3: // Check to see if a packet has arrived if(UDPIsGetReady_(DHCPSocket) < 250u) { // Go back and transmit a new discovery if we didn't get an ACK after 2 seconds if(TickGet() - eventTime >= DHCP_TIMEOUT) { if(++smDHCPState > SM_DHCP_GET_RENEW_ACK3) smDHCPState = SM_DHCP_SEND_DISCOVERY; } break; } // Check to see if we received an offer switch(_DHCPReceive()) { case DHCP_ACK_MESSAGE: UDPClose(DHCPSocket); DHCPSocket = INVALID_UDP_SOCKET; eventTime = TickGet(); DHCPBindCount++; smDHCPState = SM_DHCP_BOUND; #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(5); //@mxd:5:ACK Received #endif break; case DHCP_NAK_MESSAGE: smDHCPState = SM_DHCP_SEND_DISCOVERY; #if (DEBUG_DHCP >= LOG_WARN) debugPutMsg(4); //@mxd:4:NAK recieved (RSS). DHCP server #endif break; } break; // Handle SM_DHCP_DISABLED state by doing nothing. Default case needed // to supress compiler diagnostic. default: break; } }
/** * Fetches pending UDP packet from MAC receive buffer and dispatches it appropriate UDP socket. * If not UDP socket is matched, UDP packet is silently discarded. * Note: Caller must make sure that MAC receive buffer * access pointer is set to begining of UDP packet. * Required steps before calling this function is: * * If ( MACIsRxReady() ) * { * MACGetHeader() * If MACFrameType == IP * IPGetHeader() * if ( IPFrameType == IP_PROT_UDP ) * Call DHCPTask() * ... * } * * @@preCondition DHCPInit() is already called AND IPGetHeader() is called with * IPFrameType == IP_PROT_UDP */ void DHCPTask(void) { NODE_INFO DHCPServerNode; static TICK16 lastTryTick; BYTE DHCPRecvReturnValue; static BYTE broadcastCount; switch(smDHCPState) { case SM_DHCP_INIT_FIRST_TIME: tempIPAddress.Val = 0x0; // smDHCPState = SM_DHCP_INIT; // State automatically changes /* No break */ case SM_DHCP_INIT: broadcastCount = 3; DHCPServerNode.MACAddr.v[0] = 0xff; DHCPServerNode.MACAddr.v[1] = 0xff; DHCPServerNode.MACAddr.v[2] = 0xff; DHCPServerNode.MACAddr.v[3] = 0xff; DHCPServerNode.MACAddr.v[4] = 0xff; DHCPServerNode.MACAddr.v[5] = 0xff; DHCPServerNode.IPAddr.Val = 0xffffffff; DHCPSocket = UDPOpen(DHCP_CLIENT_PORT, &DHCPServerNode, DHCP_SERVER_PORT); if( DHCPSocket == INVALID_UDP_SOCKET ) { #if (DEBUG_DHCP >= LOG_ERROR) debugPutMsg(7); //@mxd:7:Could not open UDP socket #endif break; } lastTryTick = TickGet16bit(); smDHCPState = SM_DHCP_RESET_WAIT; /* No break */ case SM_DHCP_RESET_WAIT: //More then 200ms has passed if ( TickGetDiff16bit(lastTryTick) >= ((TICK16)TICKS_PER_SECOND / (TICK16)5) ) smDHCPState = SM_DHCP_BROADCAST; break; case SM_DHCP_BROADCAST: // Assume default IP Lease time of 60 seconds. // This should be minimum possible to make sure that if // server did not specify lease time, we try again after this minimum time. DHCPLeaseTime.Val = 60; //After a certian number of tries, give up, and assign a static IP address if (broadcastCount-- == 0) { //Once DCHP is successful, release the UDP socket //This will ensure that UDP layer discards any further DHCP related packets. UDPClose(DHCPSocket); DHCPSocket = INVALID_UDP_SOCKET; smDHCPState = SM_DHCP_BOUND; DHCPState.bits.bIsBound = TRUE; DHCPBindCount++; //Disable DHCP. No more attempts will be made to obtain a IP from the DHCP server, except //if the cable is unplugged. DHCPState.bits.bStaticIP = TRUE; MY_IP_BYTE1 = MY_STATIC_IP_BYTE1; MY_IP_BYTE2 = MY_STATIC_IP_BYTE2; MY_IP_BYTE3 = MY_STATIC_IP_BYTE3; MY_IP_BYTE4 = MY_STATIC_IP_BYTE4; #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(10); //@mxd:10:Maxumum Broadcast tries, assigned static IP address #endif return; } // If we have already obtained some IP address, renew it. if(DHCPState.bits.bIsBound) { smDHCPState = SM_DHCP_REQUEST; } else if ( UDPIsPutReady(DHCPSocket) ) { // To minimize code requirement, user must make sure that // above call will be successful by making at least one // UDP socket available. // Usually this will be the case, given that DHCP will be // the first one to use UDP socket. // Also, we will not check for transmitter readiness, // we assume it to be ready. _DHCPSend(DHCP_DISCOVER_MESSAGE); ValidValues.Val = 0x00; // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(1); //@mxd:1:Broadcast #endif lastTryTick = TickGet16bit(); smDHCPState = SM_DHCP_DISCOVER; } else { // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(8); //@mxd:8:Can not Broadcase, UDP Not ready! #endif } break; case SM_DHCP_DISCOVER: if ( TickGetDiff16bit(lastTryTick) >= DHCP_TIMEOUT) //Timeout has expired { smDHCPState = SM_DHCP_BROADCAST; // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(9); //@mxd:9:Discover time out #endif break; } if ( UDPIsGetReady(DHCPSocket) ) { // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(2); //@mxd:2:Discover #endif if ( _DHCPReceive() == DHCP_OFFER_MESSAGE ) { // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(3); //@mxd:3:Offer Message #endif smDHCPState = SM_DHCP_REQUEST; } else break; } else break; case SM_DHCP_REQUEST: if ( UDPIsPutReady(DHCPSocket) ) { _DHCPSend(DHCP_REQUEST_MESSAGE); lastTryTick = TickGet16bit(); smDHCPState = SM_DHCP_BIND; // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(12); //@mxd:12:Sending Request #endif } break; case SM_DHCP_BIND: if ( UDPIsGetReady(DHCPSocket) ) { DHCPRecvReturnValue = _DHCPReceive(); if ( DHCPRecvReturnValue == DHCP_NAK_MESSAGE ) { // (RSS) NAK recieved. DHCP server didn't like our DHCP Request (format wrong/IP address allocated to someone else/outside IP pool) #if (DEBUG_DHCP >= LOG_WARN) debugPutMsg(4); //@mxd:4:NAK recieved (RSS). DHCP server didn't like our DHCP Request format #endif DHCPReset(); // Start all over again return; } else if ( DHCPRecvReturnValue == DHCP_ACK_MESSAGE ) { // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(5); //@mxd:5:ACK Received #endif // Once DCHP is successful, release the UDP socket // This will ensure that UDP layer discards any further DHCP related packets. UDPClose(DHCPSocket); DHCPSocket = INVALID_UDP_SOCKET; lastTryTick = TickGet16bit(); smDHCPState = SM_DHCP_BOUND; if(ValidValues.bits.IPAddress) { MY_IP_BYTE1 = tempIPAddress.v[0]; MY_IP_BYTE2 = tempIPAddress.v[1]; MY_IP_BYTE3 = tempIPAddress.v[2]; MY_IP_BYTE4 = tempIPAddress.v[3]; } if(ValidValues.bits.Mask) { MY_MASK_BYTE1 = tempMask.v[0]; MY_MASK_BYTE2 = tempMask.v[1]; MY_MASK_BYTE3 = tempMask.v[2]; MY_MASK_BYTE4 = tempMask.v[3]; } if(ValidValues.bits.Gateway) { MY_GATE_BYTE1 = tempGateway.v[0]; MY_GATE_BYTE2 = tempGateway.v[1]; MY_GATE_BYTE3 = tempGateway.v[2]; MY_GATE_BYTE4 = tempGateway.v[3]; } #if defined(STACK_USE_DNS) if(ValidValues.bits.DNS) { MY_DNS_BYTE1_SET(tempDNS.v[0]); MY_DNS_BYTE2_SET(tempDNS.v[1]); MY_DNS_BYTE3_SET(tempDNS.v[2]); MY_DNS_BYTE4_SET(tempDNS.v[3]); } #endif // if(ValidValues.bits.HostName) // memcpy(AppConfig.NetBIOSName, (void*)tempHostName, sizeof(AppConfig.NetBIOSName)); DHCPState.bits.bIsBound = TRUE; DHCPBindCount++; return; } } else if ( TickGetDiff16bit(lastTryTick) >= DHCP_TIMEOUT ) //Timeout has expired { #if (DEBUG_DHCP >= LOG_WARN) debugPutMsg(6); //@mxd:6:Timeout #endif smDHCPState = SM_DHCP_BROADCAST; } break; case SM_DHCP_BOUND: //If a static IP was assigned, it never times out. Only when the cable is unplugged, will //the DHCP server be reset, and start looking for an IP again. if (DHCPState.bits.bStaticIP) return; // Keep track of how long we use this IP configuration. // When lease period expires, renew the configuration. while ( TickGetDiff16bit(lastTryTick) >= ((TICK16)TICKS_PER_SECOND) ) { DHCPLeaseTime.Val--; //Decrement lease time if ( DHCPLeaseTime.Val == 0 ) { smDHCPState = SM_DHCP_INIT; // DEBUG #if (DEBUG_DHCP >= LOG_INFO) debugPutMsg(11); //@mxd:11:Lease time expired #endif } //Add 1 seconds to lastTryTick - will cause this statement to execute in 1 second again lastTryTick += ((TICK16)TICKS_PER_SECOND); //Add 1 second to lastTryTick } } }
/* * Main entry point. */ void main(void) { static TICK8 t = 0; #ifdef HEATHERD NODE_INFO tcpServerNode; static TCP_SOCKET tcpSocketUser = INVALID_SOCKET; BYTE c; #endif static BYTE testLED; testLED = 1; //Set SWDTEN bit, this will enable the watch dog timer WDTCON_SWDTEN = 1; aliveCntrMain = 0xff; //Disable alive counter during initialization. Setting to 0xff disables it. //Initialize any application specific hardware. InitializeBoard(); //Initialize all stack related components. Following steps must //be performed for all applications using PICmicro TCP/IP Stack. TickInit(); //Initialize buses busInit(); //Initialize serial ports early, because they could be required for debugging if (appcfgGetc(APPCFG_USART1_CFG & APPCFG_USART_ENABLE)) { appcfgUSART(); //Configure the USART1 } if (appcfgGetc(APPCFG_USART2_CFG & APPCFG_USART_ENABLE)) { appcfgUSART2(); //Configure the USART2 } //After initializing all modules that use interrupts, enable global interrupts INTCON_GIEH = 1; INTCON_GIEL = 1; //Initialize file system. fsysInit(); //Intialize HTTP Execution unit htpexecInit(); //Initialize Stack and application related NV variables. appcfgInit(); //First call appcfgCpuIOValues() and then only appcfgCpuIO()!!! This ensures the value are set, before enabling ports. appcfgCpuIOValues(); //Configure the CPU's I/O port pin default values appcfgCpuIO(); //Configure the CPU's I/O port pin directions - input or output appcfgADC(); //Configure ADC unit appcfgPWM(); //Configure PWM Channels //Serial configuration menu - display it for configured time and allow user to enter configuration menu scfInit(appcfgGetc(APPCFG_STARTUP_SER_DLY)); //LCD Display Initialize lcdInit(); //Initialize expansion board appcfgXboard(); StackInit(); #if defined(STACK_USE_HTTP_SERVER) HTTPInit(); #endif #if defined(STACK_USE_FTP_SERVER) FTPInit(); #endif //Intialise network componet of buses - only call after StackInit()! busNetInit(); //Initializes events. evtInit(); //Initializes "UDP Command Port" and "UDP Even Port". cmdInit(); ioInit(); #if (DEBUG_MAIN >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:Starting main loop #endif /* * Once all items are initialized, go into infinite loop and let * stack items execute their tasks. * If application needs to perform its own task, it should be * done at the end of while loop. * Note that this is a "co-operative mult-tasking" mechanism * where every task performs its tasks (whether all in one shot * or part of it) and returns so that other tasks can do their * job. * If a task needs very long time to do its job, it must broken * down into smaller pieces so that other tasks can have CPU time. */ #ifdef HEATHERD //Create a TCP socket that listens on port 54123 tcpSocketUser = TCPListen(HEATHERD); #define HEATHERD_ENABLE (!(appcfgGetc(APPCFG_TRISA) & 1)) #define HEATHERD_WRITE_ENABLE (!(appcfgGetc(APPCFG_TRISA) & 2)) #endif while(1) { aliveCntrMain = 38; //Reset if not services in 52.42ms x 38 = 2 seconds //Blink SYSTEM LED every second. if (appcfgGetc(APPCFG_SYSFLAGS) & APPCFG_SYSFLAGS_BLINKB6) { //Configure RB6 as output, and blink it every 500ms if ( TickGetDiff8bit(t) >= ((TICK8)TICKS_PER_SECOND / (TICK8)2) ) { t = TickGet8bit(); //If B6 is configured as input, change to output if (appcfgGetc(APPCFG_TRISB) & 0x40) { appcfgPutc(APPCFG_TRISB, appcfgGetc(APPCFG_TRISB) & 0b10111111); } TRISB_RB6 = 0; LATB6 ^= 1; //Toggle //Toggle IOR5E LED, if IOR5E is present if (appcfgGetc(APPCFG_XBRD_TYPE) == XBRD_TYPE_IOR5E) { ior5eLatchData.bits.ledPWR ^= 1; // Toggle } } } //This task performs normal stack task including checking for incoming packet, //type of packet and calling appropriate stack entity to process it. StackTask(); //Service LCD display lcdService(); //Process commands cmdTask(); //Process events evtTask(); //Process serial busses busTask(); //I2C Task i2cTask(); #ifdef HEATHERD //Has a remote node made connection with the port we are listening on if ((tcpSocketUser != INVALID_SOCKET) && TCPIsConnected(tcpSocketUser)) { if (HEATHERD_ENABLE) { //Is there any data waiting for us on the TCP socket? //Because of the design of the Modtronix TCP/IP stack we have to //consume all data sent to us as soon as we detect it. while(TCPIsGetReady(tcpSocketUser)) { //We are only interrested in the first byte of the message. TCPGet(tcpSocketUser, &c); if (HEATHERD_WRITE_ENABLE) serPutByte(c); } //Discard the socket buffer. TCPDiscard(tcpSocketUser); while (serIsGetReady() && TCPIsPutReady(tcpSocketUser)) { TCPPut(tcpSocketUser,serGetByte()); } TCPFlush(tcpSocketUser); } else { TCPDisconnect(tcpSocketUser); } } #endif #if defined(STACK_USE_HTTP_SERVER) //This is a TCP application. It listens to TCP port 80 //with one or more sockets and responds to remote requests. HTTPServer(); #endif #if defined(STACK_USE_FTP_SERVER) FTPServer(); #endif #if defined(STACK_USE_ANNOUNCE) DiscoveryTask(); #endif #if defined(STACK_USE_NBNS) NBNSTask(); #endif //Add your application speicifc tasks here. ProcessIO(); //For DHCP information, display how many times we have renewed the IP //configuration since last reset. if ( DHCPBindCount != myDHCPBindCount ) { #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(2); //@mxd:2:DHCP Bind Count = %D debugPutByteHex(DHCPBindCount); #endif //Display new IP address #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(3); //@mxd:3:DHCP complete, IP = %D.%D.%D.%D debugPutByteHex(AppConfig.MyIPAddr.v[0]); debugPutByteHex(AppConfig.MyIPAddr.v[1]); debugPutByteHex(AppConfig.MyIPAddr.v[2]); debugPutByteHex(AppConfig.MyIPAddr.v[3]); #endif myDHCPBindCount = DHCPBindCount; #if defined(STACK_USE_ANNOUNCE) AnnounceIP(); #endif } } }
/////////////////////////////////////////////////////////////////////////////// // Main entry point. // void main(void) { static TICK8 t = 0; BYTE i; char strBuf[10]; // Initialize any application specific hardware. InitializeBoard(); // Initialize all stack related components. // Following steps must be performed for all applications using // PICmicro TCP/IP Stack. TickInit(); // Initialize file system. fsysInit(); // Intialize HTTP Execution unit htpexecInit(); // Initialze serial port serInit(); // Initialize Stack and application related NV variables. appcfgInit(); appcfgUSART(); // Configure the USART #ifdef SER_USE_INTERRUPT // Interrupt enabled serial ports have to be enabled serEnable(); #endif appcfgCpuIO(); // Configure the CPU's I/O port pin directions - input or output appcfgCpuIOValues(); // Configure the CPU's I/O port pin default values appcfgADC(); // Configure ADC unit appcfgPWM(); // Configure PWM unit // Serial configuration menu - display it for configured time and // allow user to enter configuration menu scfInit( appcfgGetc( APPCFG_STARTUP_SER_DLY ) ); StackInit(); #if defined(STACK_USE_HTTP_SERVER) HTTPInit(); #endif #if defined( STACK_USE_DHCP ) || defined( STACK_USE_IP_GLEANING ) // If DHCP is NOT enabled if ( ( appcfgGetc( APPCFG_NETFLAGS ) & APPCFG_NETFLAGS_DHCP ) == 0 ) { // Force IP address display update. myDHCPBindCount = 1; #if defined( STACK_USE_DHCP ) DHCPDisable(); #endif } #endif #if ( DEBUG_MAIN >= LOG_DEBUG ) debugPutMsg(1); //@mxd:1:Starting main loop #endif // Init VSCP functionality vscp_init(); bInitialized = FALSE; // Not initialized #if defined(STACK_USE_NTP_SERVER) // Initialize time hour = 0; minute = 0; second = 0; #endif appcfgPutc( VSCP_DM_MATRIX_BASE, 0x00 ); appcfgPutc( VSCP_DM_MATRIX_BASE+1, 0x00 ); appcfgPutc( VSCP_DM_MATRIX_BASE+2, 0x00 ); appcfgPutc( VSCP_DM_MATRIX_BASE+3, 0x00 ); // // Once all items are initialized, go into infinite loop and let // stack items execute their tasks. // If application needs to perform its own task, it should be // done at the end of while loop. // Note that this is a "co-operative mult-tasking" mechanism // where every task performs its tasks (whether all in one shot // or part of it) and returns so that other tasks can do their // job. // If a task needs very long time to do its job, it must broken // down into smaller pieces so that other tasks can have CPU time. // while ( 1 ) { // Used for initial delay to give stack and chip some time to // initialize. If not used messages sent during this time will // fail. if ( TickGet() > ( 5 * TICK_SECOND ) ) { bInitialized = TRUE; } // We should do the ftp download every three hours //if ( TickGetDiff( TickGet(), loadTime ) >= ( 3 * 3600 * TICK_SECOND ) ) { // loadTime = TickGet(); // bftpLoadWork = TRUE; //} // Blink SYSTEM LED every second. if ( appcfgGetc( APPCFG_SYSFLAGS ) & APPCFG_SYSFLAGS_BLINKB6 ) { if ( TickGetDiff8bit( t ) >= ((TICK8)( TICKS_PER_SECOND / 2 ) ) ) { t = TickGet8bit(); TRISB_RB6 = 0; LATB6 ^= 1; } } // This task performs normal stack task including checking for incoming packet, // type of packet and calling appropriate stack entity to process it. StackTask(); #if defined(STACK_USE_HTTP_SERVER) // This is a TCP application. It listens to TCP port 80 // with one or more sockets and responds to remote requests. HTTPServer(); #endif #if defined(STACK_USE_FTP_SERVER) FTPServer(); #endif // Add your application speicifc tasks here. ProcessIO(); #if defined(VSCP_USE_TCP ) // VSCP Task if ( bInitialized ) { vscp_tcp_task(); } #endif if ( bInitialized ) { vscp_main_task(); process_can_message(); if ( g_can_error ) { send_can_error_message( g_can_error ); g_can_error = 0; } } #if defined(STACK_USE_NTP_SERVER) if ( bInitialized ) { //ntp_task(); } #endif // For DHCP information, display how many times we have renewed the IP // configuration since last reset. if ( DHCPBindCount != myDHCPBindCount ) { #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg( 2 ); // @mxd:2:DHCP Bind Count = %D debugPutByteHex(DHCPBindCount); #endif // Display new IP address #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg( 3 ); //@mxd:3:DHCP complete, IP = %D.%D.%D.%D debugPutByteHex( AppConfig.MyIPAddr.v[ 0 ] ); debugPutByteHex( AppConfig.MyIPAddr.v[ 1 ] ); debugPutByteHex( AppConfig.MyIPAddr.v[ 2 ] ); debugPutByteHex( AppConfig.MyIPAddr.v[ 3 ] ); #endif myDHCPBindCount = DHCPBindCount; } } }
/* * Main entry point. */ void main(void) { static TICK tickHeartBeat = 0xffffffff; static BYTE testLED; testLED = 1; // Destination address - Always MAC broadcast address broadcastTargetMACAddr.v[ 0 ] = 0xff; broadcastTargetMACAddr.v[ 1 ] = 0xff; broadcastTargetMACAddr.v[ 2 ] = 0xff; broadcastTargetMACAddr.v[ 3 ] = 0xff; broadcastTargetMACAddr.v[ 4 ] = 0xff; broadcastTargetMACAddr.v[ 5 ] = 0xff; //Set SWDTEN bit, this will enable the watch dog timer WDTCON_SWDTEN = 1; aliveCntrMain = 0xff; //Disable alive counter during initialization. Setting to 0xff disables it. //Initialize any application specific hardware. InitializeBoard(); //Initialize all stack related components. Following steps must //be performed for all applications using PICmicro TCP/IP Stack. TickInit(); //Initialize serial ports early, because they could be required for debugging if (appcfgGetc(APPCFG_USART1_CFG & APPCFG_USART_ENABLE)) { appcfgUSART(); //Configure the USART1 } #if defined(BRD_SBC65EC) if (appcfgGetc(APPCFG_USART2_CFG & APPCFG_USART_ENABLE)) { appcfgUSART2(); //Configure the USART2 } #endif //After initializing all modules that use interrupts, enable global interrupts INTCON_GIEH = 1; INTCON_GIEL = 1; //Initialize Stack and application related NV variables. appcfgInit(); //First call appcfgCpuIOValues() and then only appcfgCpuIO()!!! This ensures the value are set, before enabling ports. appcfgCpuIOValues(); //Configure the CPU's I/O port pin default values appcfgCpuIO(); //Configure the CPU's I/O port pin directions - input or output appcfgADC(); //Configure ADC unit appcfgPWM(); //Configure PWM Channels MACInit(); #if (DEBUG_MAIN >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:Starting main loop #endif /* * Once all items are initialized, go into infinite loop and let * stack items execute their tasks. * If application needs to perform its own task, it should be * done at the end of while loop. * Note that this is a "co-operative mult-tasking" mechanism * where every task performs its tasks (whether all in one shot * or part of it) and returns so that other tasks can do their * job. * If a task needs very long time to do its job, it must broken * down into smaller pieces so that other tasks can have CPU time. */ while ( 1 ) { //aliveCntrMain = 38; //Reset if not services in 52.42ms x 38 = 2 seconds aliveCntrMain = 0xff; CLRWDT(); // Check for event if ( vscp_getRawPacket() ) { feedVSCP(); } // Send heartbeat every 30 seconds if ( TickGetDiff( tickHeartBeat ) >= ( TICKS_PER_SECOND * 30 ) ) { //vscpevent.head = VSCP_PRIORITY_NORMAL; //vscpevent.vscp_class = VSCP_CLASS2_LEVEL1_INFORMATION; //vscpevent.vscp_type = VSCP_TYPE_INFORMATION_NODE_HEARTBEAT; //vscpevent.sizeData = 3; //vscpevent.data[ 0 ] = 0; //vscpevent.data[ 1 ] = 0; // Zone //vscpevent.data[ 2 ] = 0; // subzone //vscp_sendRawPacket( &vscpevent ); //SendTestVSCPPacket(); tickHeartBeat = TickGet(); /* //If B6 is configured as input, change to output if (appcfgGetc(APPCFG_TRISB) & 0x40) { appcfgPutc(APPCFG_TRISB, appcfgGetc(APPCFG_TRISB) & 0b10111111); } TRISB_RB6 = 0; LATB6 ^= 1; //Toggle //Toggle IOR5E LED, if IOR5E is present if (appcfgGetc(APPCFG_XBRD_TYPE) == XBRD_TYPE_IOR5E) { ior5eLatchData.bits.ledPWR ^= 1; // Toggle } */ } // Do MAC work StackTask(); //MACTask();; //I2C Task i2cTask(); //Add your application specific tasks here. ProcessIO(); // Do VSCP periodic tasks periodicVSCPWork(); } }
/** * Call DNSIsResolved() until the host is resolved. * You cannot start two DNS resolution proceedures concurrently. * You must not modify *Hostname until DNSIsResolved() returns TRUE. * * @preCondition DNSResolve() was called. * * @param HostIP 4 byte IP address */ BOOL DNSIsResolved(IP_ADDR *HostIP) { static UDP_SOCKET MySocket; static NODE_INFO Remote; static TICK StartTime; BYTE i; WORD_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; IP_ADDR tmpIpAddr; switch(smDNS) { case DNS_HOME: tmpIpAddr.v[0] = MY_DNS_BYTE1; tmpIpAddr.v[1] = MY_DNS_BYTE2; tmpIpAddr.v[2] = MY_DNS_BYTE3; tmpIpAddr.v[3] = MY_DNS_BYTE4; ARPResolve(&tmpIpAddr); StartTime = TickGet(); smDNS++; break; case DNS_RESOLVE_ARP: if(!ARPIsResolved(&tmpIpAddr, &Remote.MACAddr)) { if(TickGet() - StartTime > DNS_TIMEOUT) { smDNS--; } break; } Remote.IPAddr.Val = tmpIpAddr.Val; smDNS++; // No need to break, we can immediately start resolution case DNS_OPEN_SOCKET: MySocket = UDPOpen(0, &Remote, DNS_PORT); if(MySocket == INVALID_UDP_SOCKET) { #if (DEBUG_DNS >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Could not open UDP socket #endif break; } smDNS++; // No need to break, we can immediately start resolution case DNS_QUERY: if(!UDPIsPutReady(MySocket)) break; // Put DNS query here UDPPut(0x12); // User chosen ID UDPPut(0x34); UDPPut(0x01); // Standard query with recursion UDPPut(0x00); UDPPut(0x00); // 0x0001 questions UDPPut(0x01); UDPPut(0x00); // 0x0000 answers UDPPut(0x00); UDPPut(0x00); // 0x0000 name server resource records UDPPut(0x00); UDPPut(0x00); // 0x0000 additional records UDPPut(0x00); // Put hostname string to resolve DNSPutString(DNSHostName); UDPPut(0x00); // Type: A (host address) UDPPut(0x01); UDPPut(0x00); // Class: IN (Internet) UDPPut(0x01); UDPFlush(); StartTime = TickGet(); smDNS++; break; case DNS_GET_RESULT: if(!UDPIsGetReady(MySocket)) { if(TickGet() - StartTime > DNS_TIMEOUT) { smDNS--; } break; } // Retrieve the DNS header and de-big-endian it UDPGet(&DNSHeader.TransactionID.v[1]); UDPGet(&DNSHeader.TransactionID.v[0]); UDPGet(&DNSHeader.Flags.v[1]); UDPGet(&DNSHeader.Flags.v[0]); UDPGet(&DNSHeader.Questions.v[1]); UDPGet(&DNSHeader.Questions.v[0]); UDPGet(&DNSHeader.Answers.v[1]); UDPGet(&DNSHeader.Answers.v[0]); UDPGet(&DNSHeader.AuthoritativeRecords.v[1]); UDPGet(&DNSHeader.AuthoritativeRecords.v[0]); UDPGet(&DNSHeader.AdditionalRecords.v[1]); UDPGet(&DNSHeader.AdditionalRecords.v[0]); // Remove all questions while(DNSHeader.Questions.Val--) { DNSGetString(NULL); UDPGet(&w.v[1]); // Question type UDPGet(&w.v[0]); UDPGet(&w.v[1]); // Question class UDPGet(&w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name UDPGet(&DNSAnswerHeader.ResponseName.v[0]); UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { UDPGet(&HostIP->v[0]); UDPGet(&HostIP->v[1]); UDPGet(&HostIP->v[2]); UDPGet(&HostIP->v[3]); break; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } UDPDiscard(); UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; smDNS++; // No need to break, we are done and need to return TRUE case DNS_DONE: return TRUE; } return FALSE; }
/** * This function is a "callback" from HTTPServer task. Whenever a remote node performs interactive * GET task on page that was served, HTTPServer calls this functions. Use HTTPGetParam() * to get all name-value parameters. * * @param httpInfo Socket that is currently receiving this HTTP command * @param rqstRes Name of the Requested resource - GET command's action. All characters are * in uppercase! */ void HTTPExecGetCmd(HTTP_INFO* httpInfo, BYTE* rqstRes) { BYTE param[64]; WORD wUpdate; //Contains CMD_UD_XXX flags indicating what has to be updated //Used as input AND output parameter for HTTPGetParams. // - Input parameter indicates size of param buffer // - On return of HTTPGerParam() valueIdx will contain index of value string in param BYTE valueIdx; BYTE moreParams; BYTE paramCount; //The number of parameters (name-value pairs) we have received BYTE user; BYTE tmp; BYTE executed; //Indicates if the command has been executed already or not #if (DEBUG_HTTPEXEC >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:HTTPExecGetCmd() called for file %s debugPutString(rqstRes); #endif wUpdate = 0; //Clear all update flags paramCount = 0; //Get the current user logged in for this HTTP connection user = HTTPGetCurrentUser(httpInfo); //Get next name-value parameter do { valueIdx = (BYTE)sizeof(param); //Input parameter is size of param buffer //Get name-value parameters. Returns true if there are more name-value parameters to follow //- Pointer to Name parameter = ¶m[0] //- Pointer to Value parameter = ¶m[valueIdx] moreParams = HTTPGetParam(httpInfo->socket, param, &valueIdx); paramCount++; executed = 0; //Current name-value command has not been executed yet ///////////////////////////////////////////////// //We received a general command with value if (param[0] == CMDGROUP_GENERAL) { #if (DEBUG_CMD >= LOG_DEBUG) debugPutMsg(8); //@mxd:8:Received General Command #endif //The second character of the name part of the name-value pair will be the "Command Code". switch(param[1]) { case CMDCODE_GEN_PASSWORD: executed = 1; //Indicates that the command has been executed // This command is NOT used any more, seeing that we now use HTTP Authentication break; case CMDCODE_GEN_USERNAME: executed = 1; //Indicates that the command has been executed // This command is NOT used any more, seeing that we now use HTTP Authentication break; } } ///////////////////////////////////////////////// //We received a general command without value else if (param[0] == CMDGROUP_GENERAL_NOVAL) { #if (DEBUG_CMD >= LOG_DEBUG) debugPutMsg(10); //@mxd:10:Received General Command without value #endif ///////////////////////////////////////////////// // The following commands can ONLY be executed by "Admin" or "Super User" if (user != USER_GUEST) { //The first character of the value part of the name-value pair will be the "Command Code". switch(param[valueIdx]) { //There is no logout command anymore with HTTP Authentication! case CMDCODE_GENNOVAL_LOGOUT: executed = 1; //Indicates that the command has been executed #if (DEBUG_CMD >= LOG_INFO) debugPutMsg(14); //@mxd:14:Received Log Off command #endif //There is no logout command anymore with HTTP Authentication! //Update HTTP_INFO structure's user information //httpInfo->flags.bits.bUserLoggedIn = FALSE; break; } } //The first character of the value part of the name-value pair will be the "Command Code". switch(param[valueIdx]) { //Causes requested to log in, if not already Authenticated case CMDCODE_GENNOVAL_LOGIN: executed = 1; //Indicates that the command has been executed httpInfo->flags.bits.bLoginReq = TRUE; break; } } //If this command has not been executed yet, pass it on to the execNaveValueCmd function if ( !executed) { //Execute the given name-value command wUpdate |= execNameValueCmd(param, ¶m[valueIdx], user); } } while (moreParams); //Network settings have changed if (wUpdate & CMD_UD_NETWORK) { //Reconfigure USART with new value //appcfgNetwork(); } else if (wUpdate & CMD_UD_USART) { //Reconfigure USART with new value appcfgUSART(); appcfgUSART2(); } else if (wUpdate & CMD_UD_CPU_IO) { //Reconfigure IO ports appcfgCpuIO(); } else if (wUpdate & CMD_UD_ADC) { //Reconfigure IO ports appcfgADC(); } else if (wUpdate & CMD_UD_PWM) { //Reconfigure PWM appcfgPWM(); } else if (wUpdate & CMD_UD_XBOARD) { //Reconfigure Expansion Board appcfgXboard(); } else if (wUpdate & CMD_UD_BUSBUF) { //Reconfigure Bus Buffers busInfoInit(); } else if (wUpdate & CMD_UD_BUSNET) { //Reconfigure UDP Buses busNetInit(); } }
/** * Check if the MAC Receive Buffer has any received packets. * Reads the following data from the next available packet in the RX buffer: <ul> * <li> The MAC 4 bytes RX packet header (status, nex receive packet, length) </li> * <li> The 14 byte Ethernet header </li></ul> * Once a data packet is fetched by calling MACRxbufGetHdr, the complete data * packet must be fetched (using MACRxbufGet) and discarded (using MACRxbufDiscard). * Users cannot call MACRxbufGetHdr multiple times to receive multiple packets * and fetch data later on. * * @param[out] remote Pointer to a MAC_ADDR structure. This function will write the MAC address of the * node who sent this packet to this structure * @param[out] type Pointer to byte. This function will write the type of header to this variable. * Can be ETHER_IP, ETHER_ARP or MAC_UNKNOWN * * @return True if RX Buffer contained a packet and it's header was read, False if not * */ BOOL MACRxbufGetHdr(MAC_ADDR *remote, BYTE* type) { NE_PREAMBLE header; BYTE NICWritePtr; BYTE NICReadPtr; WORD_VAL temp; *type = MAC_UNKNOWN; //Read CURR and BNDY registers = RX Buffer's GET and PUT pointers NICPut(CMDR, 0x60); //Set page 1 NICWritePtr = NICGet(CURRP); //Curr is the RX Buffer's PUT pointer NICPut(CMDR, 0x20); //Reset to page 0 NICReadPtr = NICGet(BNRY); //Get BNRY pointer // Reset NIC if overrun has occured. if ( NICGet(ISR) & 0x10 ) { BYTE resend; #if (DEBUG_MAC >= LOG_ERROR) debugPutMsg(3); //@mxd:3:Overrun error! Reseting MAC! #endif // Save TXP bit resend = NICGet(CMDR) & 0x04; //Issue STOP command to NIC and delay 2ms NICPut(CMDR, 0x21); DelayMs(2); //Clear Remote Byte count registers NICPut(RBCR0, 0); NICPut(RBCR1, 0); // TXP bit set? if (resend) // No re-send if Packet Transmitted or Transmit Error bit is set resend = !(NICGet(ISR) & 0x0A); //Put NIC in loopback mode and issue start command NICPut(TCR, 0x02); NICPut(CMDR, 0x22); // HM: Modified, changed to 22 to re-start NIC // Empty ring buffer completely MACCurrRxbuf = NICWritePtr; MACRxbufDiscard(); //Reset ISR by writing FF to it NICPut(ISR, 0xff); //Take NIC out of loopback mode NICPut(TCR, 0x00); //Resend the packet if(resend) NICPut(CMDR, 0x26); return FALSE; } //Is there something in the buffer if ( NICWritePtr != NICReadPtr ) { temp.v[1] = NICReadPtr; //Pointer to RAM page, is MSB of address temp.v[0] = 0; //LSB is 0 NICSetAddr(temp.Val); //Read the following from the current MAC RX Buffer: // - The MAC 4 bytes RX packet header (status, nex receive packet, length) // - The 14 byte Ethernet header MACRxbufGetArray((BYTE*)&header, sizeof(header)); // Validate packet length and status as. if ( header.Status.PRX && (header.ReceivedBytes >= MINFRAMEC) && (header.ReceivedBytes <= MAXFRAMEC) && (header.NextPacketPointer < RXSTOP) && (header.NextPacketPointer >= RXSTART) ) { header.Type.Val = swaps(header.Type.Val); memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote)); if ( (header.Type.v[1] == 0x08) && ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) ) *type = header.Type.v[0]; MACCurrRxbuf = NICReadPtr; //Set MACCurrRxbuf with page address of current RX Buffer return TRUE; } //ERROR!!! Invalid packet received! #if (DEBUG_MAC >= LOG_ERROR) debugPutMsg(4); //@mxd:4:Invalid Packet Error! #endif //Ring now contains garbage MACCurrRxbuf = NICWritePtr; // Empty ring buffer completely MACRxbufDiscard(); } return FALSE; }
/* * Main entry point. */ void main(void) { static TICK8 t = 0; static TICK8 tmr10ms = 0; //Initialize any application specific hardware. InitializeBoard(); //Initialize all stack related components. Following steps must //be performed for all applications using PICmicro TCP/IP Stack. TickInit(); //Initialize file system. fsysInit(); //Intialize HTTP Execution unit htpexecInit(); //Initialze serial port serInit(); //Initialize Stack and application related NV variables. appcfgInit(); appcfgUSART(); //Configure the USART #ifdef SER_USE_INTERRUPT //Interrupt enabled serial ports have to be enabled serEnable(); #endif appcfgCpuIO(); //Configure the CPU's I/O port pin directions - input or output appcfgCpuIOValues(); //Configure the CPU's I/O port pin default values appcfgADC(); //Configure ADC unit appcfgPWM(); //Configure PWM Channels //Serial configuration menu - display it for configured time and allow user to enter configuration menu scfInit(appcfgGetc(APPCFG_STARTUP_SER_DLY)); //LCD Display Initialize lcdInit(); StackInit(); #if defined(STACK_USE_HTTP_SERVER) HTTPInit(); #endif #if defined(STACK_USE_FTP_SERVER) FTPInit(); #endif //Initializes "UDP Command Port" and "UDP Command Responce Port". cmdUdpInit(); #if defined(STACK_USE_DHCP) || defined(STACK_USE_IP_GLEANING) DHCPReset(); //Initialize DHCP module //If DHCP is NOT enabled if ((appcfgGetc(APPCFG_NETFLAGS) & APPCFG_NETFLAGS_DHCP) == 0) { //Force IP address display update. myDHCPBindCount = 1; #if defined(STACK_USE_DHCP) DHCPDisable(); #endif } #endif #if (DEBUG_MAIN >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:Starting main loop #endif /* * Once all items are initialized, go into infinite loop and let * stack items execute their tasks. * If application needs to perform its own task, it should be * done at the end of while loop. * Note that this is a "co-operative mult-tasking" mechanism * where every task performs its tasks (whether all in one shot * or part of it) and returns so that other tasks can do their * job. * If a task needs very long time to do its job, it must broken * down into smaller pieces so that other tasks can have CPU time. */ while(1) { //Clear timer 1 every cycle, can be used to measure events. Has a overflow of 65ms. //Get delay in this function with: // TMR1L | (TMR1H<<8) TMR1H = 0; //First write to TMR1H buffer! TMR1L = 0; //This write will also update TMR1H with value written above to buffer //Blink SYSTEM LED every second. if (appcfgGetc(APPCFG_SYSFLAGS) & APPCFG_SYSFLAGS_BLINKB6) { if ( TickGetDiff8bit(t) >= ((TICK8)TICKS_PER_SECOND / (TICK8)2) ) { t = TickGet8bit(); TRISB_RB6 = 0; LATB6 ^= 1; } } //Enter each 10ms if ( TickGetDiff8bit(tmr10ms) >= ((TICK8)TICKS_PER_SECOND / (TICK8)100) ) { tmr10ms = TickGet8bit(); } //This task performs normal stack task including checking for incoming packet, //type of packet and calling appropriate stack entity to process it. StackTask(); //Process "UDP Command Port" and "UDP Command Responce Port" cmdProcess(); #if defined(STACK_USE_HTTP_SERVER) //This is a TCP application. It listens to TCP port 80 //with one or more sockets and responds to remote requests. HTTPServer(); #endif #if defined(STACK_USE_FTP_SERVER) FTPServer(); #endif #if defined(STACK_USE_ANNOUNCE) DiscoveryTask(); #endif #if defined(STACK_USE_NBNS) NBNSTask(); #endif //Add your application speicifc tasks here. ProcessIO(); //For DHCP information, display how many times we have renewed the IP //configuration since last reset. if ( DHCPBindCount != myDHCPBindCount ) { #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(2); //@mxd:2:DHCP Bind Count = %D debugPutByteHex(DHCPBindCount); #endif //Display new IP address #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(3); //@mxd:3:DHCP complete, IP = %D.%D.%D.%D debugPutByteHex(AppConfig.MyIPAddr.v[0]); debugPutByteHex(AppConfig.MyIPAddr.v[1]); debugPutByteHex(AppConfig.MyIPAddr.v[2]); debugPutByteHex(AppConfig.MyIPAddr.v[3]); #endif myDHCPBindCount = DHCPBindCount; #if defined(STACK_USE_ANNOUNCE) AnnounceIP(); #endif } } }
/** * Initialize bus network components * * @preCondition Do NOT call this function before stackInit() has been called! */ void busNetInit(void) { BYTE cfg; NODE_INFO udpServerNode; //Initialize remote IP and MAC address of udpServerNode with 0, seeing that we don't know them for the node //that will send us an UDP message. The first time a message is received addressed to this port, the //remote IP and MAC addresses are automatically updated with the addresses of the remote node. memclr(&udpServerNode, sizeof(udpServerNode)); //Get UDP Port 1 configuration, is a BUSSTAT_UDP_XXX define cfg = appcfgGetc(BUSCFG_UDP1_CFG); if (cfg & BUSSTAT_UDP_ENABLE) { //Only continue if udpBus1 has not already been initialized if (udpBus1 == INVALID_UDP_SOCKET) { //Open for configured local port, and INVALID_UDP_PORT remote port. This opens the socket to //listen on the given port. udpBus1 = UDPOpen(BUS_UDP1PORT, &udpServerNode, INVALID_UDP_PORT); //An error occurred during the UDPOpen() function if (udpBus1 == INVALID_UDP_SOCKET) { #if (DEBUG_BUS >= LOG_ERROR) debugPutMsg(2); //@mxd:2:Could not open UDP1 port #endif } } } //Disable udpBus1 else { //If udpBus1 currently open, close it if (udpBus1 != INVALID_UDP_SOCKET) { UDPClose(udpBus1); udpBus1 = INVALID_UDP_SOCKET; } } //Get UDP Port 1 configuration, is a BUSSTAT_UDP_XXX define cfg = appcfgGetc(BUSCFG_UDP2_CFG); if (cfg & BUSSTAT_UDP_ENABLE) { //Only continue if udpBus2 has not already been initialized if (udpBus2 == INVALID_UDP_SOCKET) { //Open for configured local port, and INVALID_UDP_PORT remote port. This opens the socket to //listen on the given port. udpBus2 = UDPOpen(BUS_UDP2PORT, &udpServerNode, INVALID_UDP_PORT); //An error occurred during the UDPOpen() function if (udpBus2 == INVALID_UDP_SOCKET) { #if (DEBUG_BUS >= LOG_ERROR) debugPutMsg(3); //@mxd:2:Could not open UDP2 port #endif } } } //Disable udpBus2 else { //If udpBus2 currently open, close it if (udpBus2 != INVALID_UDP_SOCKET) { UDPClose(udpBus2); udpBus2 = INVALID_UDP_SOCKET; } } }
/** * This FSM checks for new incoming packets, and routes it to appropriate * stack components. It also performs timed operations. * * This function must be called periodically called * to make sure that timely response. * * @preCondition StackInit() is already called. * * side affect: Stack FSM is executed. */ void StackTask(void) { static NODE_INFO remoteNode; static WORD dataCount; #if defined(STACK_USE_ICMP) static BYTE data[MAX_ICMP_DATA_LEN]; static WORD ICMPId; static WORD ICMPSeq; #endif IP_ADDR destIP; //Is filled with the Destination IP address contained in the IP header union { BYTE MACFrameType; BYTE IPFrameType; ICMP_CODE ICMPCode; } type; BOOL lbContinue; lbContinue = TRUE; while( lbContinue ) { lbContinue = FALSE; switch(smStack) { case SM_STACK_IDLE: case SM_STACK_MAC: //Check if the MAC RX Buffer has any data, and if it does, read the header. //Get the next header from the NIC. The node who sent it's address will be copied to //'remoteNode.MACAddr'. if ( !MACRxbufGetHdr(&remoteNode.MACAddr, &type.MACFrameType) ) { //Header was NOT read if MACRxbufGetHdr returned FALSE #if defined(STACK_USE_DHCP) //If DHCP is enabled AND MAC is not linked yet, set our IP to 0 if (STACK_IS_DHCP_ENABLED) { if ( !MACIsLinked() ) { #if (DEBUG_STACKTSK >= LOG_INFO) debugPutMsg(1); //@mxd:1:DHCP Enabled but MAC not linked yet - set IP to 0.0.0.0 #endif //IP address must be 0.0.0.0 before DHCP has obtained a valid IP address MY_IP_BYTE1 = 0; MY_IP_BYTE2 = 0; MY_IP_BYTE3 = 0; MY_IP_BYTE4 = 0; stackFlags.bits.bInConfigMode = TRUE; DHCPReset(); } } #endif break; } lbContinue = TRUE; if ( type.MACFrameType == MAC_IP ) { smStack = SM_STACK_IP; #if (DEBUG_STACKTSK >= LOG_DEBUG) debugPutMsg(2); //@mxd:2:Reading MAC IP header #endif } else if ( type.MACFrameType == MAC_ARP ) { smStack = SM_STACK_ARP; #if (DEBUG_STACKTSK >= LOG_DEBUG) debugPutMsg(3); //@mxd:3:Reading MAC ARP header #endif } else { MACRxbufDiscard(); #if (DEBUG_STACKTSK >= LOG_WARN) debugPutMsg(4); //@mxd:4:Unknown MAC header read, MAC Frame Type = 0x%x debugPutByteHex(type.MACFrameType); #endif } break; case SM_STACK_ARP: lbContinue = FALSE; if ( ARPProcess() ) smStack = SM_STACK_IDLE; break; case SM_STACK_IP: if ( IPGetHeader(&destIP, /* Get Destination IP Address as received in IP header */ &remoteNode, &type.IPFrameType, &dataCount) ) { lbContinue = TRUE; if ( type.IPFrameType == IP_PROT_ICMP ) { smStack = SM_STACK_ICMP; #if defined(STACK_USE_IP_GLEANING) if ( stackFlags.bits.bInConfigMode ) { /* * Accoriding to "IP Gleaning" procedure, when we receive an ICMP packet * with a valid IP address while we are still in configuration mode, * accept that address as ours and conclude configuration mode. */ if ( destIP.Val != 0xffffffff ) { stackFlags.bits.bInConfigMode = FALSE; MY_IP_BYTE1 = destIP.v[0]; MY_IP_BYTE2 = destIP.v[1]; MY_IP_BYTE3 = destIP.v[2]; MY_IP_BYTE4 = destIP.v[3]; #if defined(STACK_USE_DHCP) /* * If DHCP and IP gleaning is enabled at the * same time, we must ensuer that once we have * IP address through IP gleaning, we abort * any pending DHCP requests and do not renew * any new DHCP configuration. */ DHCPAbort(); #endif } } #endif } #if defined(STACK_USE_TCP) else if ( type.IPFrameType == IP_PROT_TCP ) smStack = SM_STACK_TCP; #endif #if defined(STACK_USE_UDP) else if ( type.IPFrameType == IP_PROT_UDP ) smStack = SM_STACK_UDP; #endif else { lbContinue = FALSE; MACRxbufDiscard(); smStack = SM_STACK_IDLE; } } else { MACRxbufDiscard(); smStack = SM_STACK_IDLE; } break; #if defined(STACK_USE_UDP) case SM_STACK_UDP: //tempLocalIP.v[0] = MY_IP_BYTE1; //tempLocalIP.v[1] = MY_IP_BYTE2; //tempLocalIP.v[2] = MY_IP_BYTE3; //tempLocalIP.v[3] = MY_IP_BYTE4; if ( UDPProcess(&remoteNode, &destIP, dataCount) ) smStack = SM_STACK_IDLE; lbContinue = FALSE; break; #endif #if defined(STACK_USE_TCP) case SM_STACK_TCP: //tempLocalIP.v[0] = MY_IP_BYTE1; //tempLocalIP.v[1] = MY_IP_BYTE2; //tempLocalIP.v[2] = MY_IP_BYTE3; //tempLocalIP.v[3] = MY_IP_BYTE4; //Will return TRUE if TCPProcess finished it's task, else FALSE if ( TCPProcess(&remoteNode, &destIP, dataCount) ) smStack = SM_STACK_IDLE; lbContinue = FALSE; break; #endif case SM_STACK_ICMP: smStack = SM_STACK_IDLE; #if defined(STACK_USE_ICMP) if ( dataCount <= (MAX_ICMP_DATA_LEN+9) ) { if ( ICMPGet(&type.ICMPCode, data, (BYTE*)&dataCount, &ICMPId, &ICMPSeq) ) { if ( type.ICMPCode == ICMP_ECHO_REQUEST ) { lbContinue = TRUE; smStack = SM_STACK_ICMP_REPLY; } else { smStack = SM_STACK_IDLE; } } else { smStack = SM_STACK_IDLE; } } #endif MACRxbufDiscard(); break; #if defined(STACK_USE_ICMP) case SM_STACK_ICMP_REPLY: if ( ICMPIsTxReady() ) { ICMPPut(&remoteNode, ICMP_ECHO_REPLY, data, (BYTE)dataCount, ICMPId, ICMPSeq); smStack = SM_STACK_IDLE; } break; #endif } } #if defined(STACK_USE_TCP) // Perform timed TCP FSM. TCPTick(); #endif #if defined(STACK_USE_DHCP) /* * DHCP must be called all the time even after IP configuration is discovered. * DHCP has to account lease expiration time and renew the configuration time. */ DHCPTask(); if ( DHCPIsBound() ) stackFlags.bits.bInConfigMode = FALSE; #endif //Perform routine MAC tasks MACTask(); }
/** * Only one IP message can be received. Caller may not transmit and receive * a message at the same time. * * @preCondition MACRxbufGetHdr() == TRUE * * @param localIP Local node IP Address (Destination IP Address) as received in current IP header. * If this information is not required caller may pass NULL value. * @param remote Remote node info * @param protocol Current packet protocol * @param len Length of IP data. For example, if TCP is contained in this IP * packet, this will be = TCP Header length + TCP Data Length * * @return TRUE, if valid packet was received <br> * FALSE otherwise */ BOOL IPGetHeader(IP_ADDR *localIP, NODE_INFO *remote, BYTE *protocol, WORD *len) { WORD_VAL ReceivedChecksum; WORD_VAL CalcChecksum; WORD checksums[2]; IP_HEADER header; BYTE optionsLen; #define MAX_OPTIONS_LEN (20) // As per RFC 791. BYTE options[MAX_OPTIONS_LEN]; //Read IP header. The data is read from the current MAC RX Buffer MACRxbufGetArray((BYTE*)&header, sizeof(header)); //Write out ID of received IP header #if (DEBUG_IP >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:Received IP header with ID=0x%x%x //Write HEX WORD value of tmp debugPutByteHex(header.Identification.v[0]); debugPutByteHex(header.Identification.v[1]); #endif // Make sure that this IPv4 packet. if ( (header.VersionIHL & 0xf0) != IP_VERSION ) { goto IPGetHeader_Discard; } /* * Calculate options length in this header, if there is any. * IHL is in terms of numbers of 32-bit DWORDs; i.e. actual * length is 4 times IHL. */ optionsLen = ((header.VersionIHL & 0x0f) << 2) - sizeof(header); /* * If there is any option(s), read it so that we can include them * in checksum calculation. */ if ( optionsLen > MAX_OPTIONS_LEN ) { goto IPGetHeader_Discard; } if ( optionsLen > 0 ) { //Read options data. The data is read from the current MAC RX Buffer MACRxbufGetArray(options, optionsLen); } // Save header checksum; clear it and recalculate it ourselves. ReceivedChecksum.Val = header.HeaderChecksum.Val; header.HeaderChecksum.Val = 0; // Calculate checksum of header including options bytes. checksums[0] = ~CalcIPChecksum((BYTE*)&header, sizeof(header)); // Calculate Options checksum too, if they are present. if ( optionsLen > 0 ) checksums[1] = ~CalcIPChecksum((BYTE*)options, optionsLen); else checksums[1] = 0; CalcChecksum.Val = CalcIPChecksum((BYTE*)checksums, 2 * sizeof(WORD)); // Network to host conversion. SwapIPHeader(&header); // Make sure that checksum is correct and IP version is supported. if ( ReceivedChecksum.Val != CalcChecksum.Val || (header.VersionIHL & 0xf0) != IP_VERSION ) { // Bad/Unknown packet. Discard it. goto IPGetHeader_Discard; } /* * If caller is intrested, return destination IP address * as seen in this IP header. */ if ( localIP ) localIP->Val = header.DestAddress.Val; remote->IPAddr.Val = header.SourceAddress.Val; *protocol = header.Protocol; *len = header.TotalLength.Val - optionsLen - sizeof(header); return TRUE; IPGetHeader_Discard: MACRxbufDiscard(); return FALSE; }
/** * This FSM checks for new incoming packets, and routes it to appropriate * stack components. It also performs timed operations. * * This function must be called periodically called * to make sure that timely response. * * @preCondition StackInit() is already called. * * side affect: Stack FSM is executed. */ void StackTask(void) { static WORD dataCount; #if defined(STACK_USE_ICMP) static BYTE data[MAX_ICMP_DATA_LEN]; static WORD ICMPId; static WORD ICMPSeq; #endif IP_ADDR destIP; //Is filled with the Destination IP address contained in the IP header union { BYTE MACFrameType; BYTE IPFrameType; ICMP_CODE ICMPCode; } type; BOOL lbContinue; do { lbContinue = FALSE; switch(smStack) { case SM_STACK_IDLE: case SM_STACK_MAC: //debugPutGenRomStr(2, (ROM char*)"1"); //@mxd:2:%s //Check if the MAC RX Buffer has any data, and if it does, read the header. //Get the next header from the NIC. The node who sent it's address will be copied to //'remoteNode.MACAddr'. //Header was NOT read if MACGetHeader returned FALSE if ( !MACGetHeader(&remoteNode.MACAddr, &type.MACFrameType) ) { //debugPutGenRomStr(2, (ROM char*)"2"); //@mxd:2:%s //MODIFIED DHCP BEGIN // ADDED #if defined(STACK_USE_DHCP) // Normally, an application would not include DHCP module // if it is not enabled. But in case some one wants to disable // DHCP module at run-time, remember to not clear our IP // address if link is removed. if(STACK_IS_DHCP_ENABLED) { if(!MACIsLinked()) { AppConfig.MyIPAddr.v[0] = MY_DEFAULT_IP_ADDR_BYTE1; AppConfig.MyIPAddr.v[1] = MY_DEFAULT_IP_ADDR_BYTE2; AppConfig.MyIPAddr.v[2] = MY_DEFAULT_IP_ADDR_BYTE3; AppConfig.MyIPAddr.v[3] = MY_DEFAULT_IP_ADDR_BYTE4; AppConfig.MyMask.v[0] = MY_DEFAULT_MASK_BYTE1; AppConfig.MyMask.v[1] = MY_DEFAULT_MASK_BYTE2; AppConfig.MyMask.v[2] = MY_DEFAULT_MASK_BYTE3; AppConfig.MyMask.v[3] = MY_DEFAULT_MASK_BYTE4; DHCPFlags.bits.bDHCPServerDetected = FALSE; stackFlags.bits.bInConfigMode = TRUE; DHCPReset(); } // DHCP must be called all the time even after IP configuration is // discovered. // DHCP has to account lease expiration time and renew the configuration // time. DHCPTask(); if(DHCPIsBound()) stackFlags.bits.bInConfigMode = FALSE; } #endif //MODIFIED DHCP END //MODIFIED DHCP BEGIN // Removed /* #if defined(STACK_USE_DHCP) // Normally, an application would not include DHCP module // if it is not enabled. But in case some one wants to disable // DHCP module at run-time, remember to not clear our IP // address if link is removed. //Set our IP to 0.0.0.0 if all the following are TRUE: // - DHCP is enabled // - MAC is not linked yet (or cable is unplugged) if (STACK_IS_DHCP_ENABLED) { if ( !MACIsLinked() ) { //debugPutGenRomStr(2, (ROM char*)"3"); //@mxd:2:%s #if (DEBUG_STACKTSK >= LOG_INFO) //debugPutMsg(1); //@mxd:1:DHCP Enabled but MAC not linked yet - set IP to 0.0.0.0 #endif //if (stackFlags.bits.bInConfigMode) { //IP address must be 0.0.0.0 before DHCP has obtained a valid IP address MY_IP_BYTE1 = 0; MY_IP_BYTE2 = 0; MY_IP_BYTE3 = 0; MY_IP_BYTE4 = 0; //} stackFlags.bits.bInConfigMode = TRUE; DHCPReset(); } } #endif */ //MODIFIED DHCP END break; //case SM_STACK_IDLE: AND case SM_STACK_MAC: } //debugPutGenRomStr(2, (ROM char*)"4"); //@mxd:2:%s lbContinue = TRUE; if ( type.MACFrameType == MAC_IP ) { smStack = SM_STACK_IP; #if (DEBUG_STACKTSK >= LOG_DEBUG) debugPutMsg(2); //@mxd:2:Reading MAC IP header #endif } else if ( type.MACFrameType == MAC_ARP ) { smStack = SM_STACK_ARP; #if (DEBUG_STACKTSK >= LOG_DEBUG) debugPutMsg(3); //@mxd:3:Reading MAC ARP header #endif } else { MACDiscardRx(); //Discard the contents of the current RX buffer #if (DEBUG_STACKTSK >= LOG_WARN) debugPutMsg(4); //@mxd:4:Unknown MAC header read, MAC Frame Type = 0x%x debugPutByteHex(type.MACFrameType); #endif } break; //case SM_STACK_IDLE: AND case SM_STACK_MAC: case SM_STACK_ARP: if ( ARPProcess() ) smStack = SM_STACK_IDLE; //lbContinue = FALSE; //Removed in latest Microchip TCP/IP stack break; case SM_STACK_IP: if ( IPGetHeader(&destIP, /* Get Destination IP Address as received in IP header */ &remoteNode, &type.IPFrameType, &dataCount) ) { lbContinue = TRUE; if ( type.IPFrameType == IP_PROT_ICMP ) { smStack = SM_STACK_ICMP; #if defined(STACK_USE_IP_GLEANING) if(stackFlags.bits.bInConfigMode && STACK_IS_DHCP_ENABLED) { // Accoriding to "IP Gleaning" procedure, // when we receive an ICMP packet with a valid // IP address while we are still in configuration // mode, accept that address as ours and conclude // configuration mode. if ( destIP.Val != 0xffffffff ) { stackFlags.bits.bInConfigMode = FALSE; MY_IP_BYTE1 = destIP.v[0]; MY_IP_BYTE2 = destIP.v[1]; MY_IP_BYTE3 = destIP.v[2]; MY_IP_BYTE4 = destIP.v[3]; myDHCPBindCount--; } } #endif } #if defined(STACK_USE_TCP) else if ( type.IPFrameType == IP_PROT_TCP ) smStack = SM_STACK_TCP; #endif #if defined(STACK_USE_UDP) else if ( type.IPFrameType == IP_PROT_UDP ) smStack = SM_STACK_UDP; #endif else // Unknown/unsupported higher level protocol { lbContinue = FALSE; MACDiscardRx(); //Discard the contents of the current RX buffer smStack = SM_STACK_IDLE; } } else // Improper IP header version or checksum { MACDiscardRx(); //Discard the contents of the current RX buffer smStack = SM_STACK_IDLE; } break; //case SM_STACK_IP: #if defined(STACK_USE_UDP) case SM_STACK_UDP: if ( UDPProcess(&remoteNode, &destIP, dataCount) ) smStack = SM_STACK_IDLE; //lbContinue = FALSE; //Removed in latest Microchip TCP/IP stack break; //case SM_STACK_UDP: #endif #if defined(STACK_USE_TCP) case SM_STACK_TCP: if ( TCPProcess(&remoteNode, &destIP, dataCount) ) //Will return TRUE if TCPProcess finished it's task, else FALSE smStack = SM_STACK_IDLE; //lbContinue = FALSE; //Removed in latest Microchip TCP/IP stack break; //case SM_STACK_TCP: #endif case SM_STACK_ICMP: smStack = SM_STACK_IDLE; #if defined(STACK_USE_ICMP) if ( dataCount <= (MAX_ICMP_DATA_LEN+9) ) { if ( ICMPGet(&type.ICMPCode, data, (BYTE*)&dataCount, &ICMPId, &ICMPSeq) ) { if ( type.ICMPCode == ICMP_ECHO_REQUEST ) { lbContinue = TRUE; smStack = SM_STACK_ICMP_REPLY; } } } #endif MACDiscardRx(); //Discard the contents of the current RX buffer break; //case SM_STACK_ICMP: #if defined(STACK_USE_ICMP) case SM_STACK_ICMP_REPLY: if ( ICMPIsTxReady() ) { ICMPPut(&remoteNode, ICMP_ECHO_REPLY, data, (BYTE)dataCount, ICMPId, ICMPSeq); smStack = SM_STACK_IDLE; } break; //case SM_STACK_ICMP_REPLY: #endif } //switch(smStack) FAST_USER_PROCESS(); } while(lbContinue); #if defined(STACK_USE_TCP) // Perform timed TCP FSM. TCPTick(); #endif //MODIFIED DHCP BEGIN // Removed this //#if defined(STACK_USE_DHCP) /* * DHCP must be called all the time even after IP configuration is * discovered. * DHCP has to account lease expiration time and renew the configuration * time. */ // DHCPTask(); // if(DHCPIsBound()) // stackFlags.bits.bInConfigMode = FALSE; //#endif //debugPutGenRomStr(2, (ROM char*)"MACTask"); //@mxd:2:%s //Perform routine MAC tasks MACTask(); }
/* * Main entry point. */ void main(void) { static TICK8 t = 0; BYTE i; char strBuf[10]; /* * Initialize any application specific hardware. */ InitializeBoard(); /* * Initialize all stack related components. * Following steps must be performed for all applications using * PICmicro TCP/IP Stack. */ TickInit(); /* * Initialize file system. */ fsysInit(); //Intialize HTTP Execution unit htpexecInit(); //Initialze serial port serInit(); /* * Initialize Stack and application related NV variables. */ appcfgInit(); appcfgUSART(); //Configure the USART #ifdef SER_USE_INTERRUPT //Interrupt enabled serial ports have to be enabled serEnable(); #endif appcfgCpuIO(); //Configure the CPU's I/O port pin directions - input or output appcfgCpuIOValues(); //Configure the CPU's I/O port pin default values appcfgADC(); //Configure ADC unit //Serial configuration menu - display it for configured time and allow user to enter configuration menu scfInit(appcfgGetc(APPCFG_STARTUP_SER_DLY)); StackInit(); #if defined(STACK_USE_HTTP_SERVER) HTTPInit(); #endif #if defined(STACK_USE_FTP_SERVER) FTPInit(); #endif #if defined(STACK_USE_DHCP) || defined(STACK_USE_IP_GLEANING) //If DHCP is NOT enabled if ((appcfgGetc(APPCFG_NETFLAGS) & APPCFG_NETFLAGS_DHCP) == 0) { //Force IP address display update. myDHCPBindCount = 1; #if defined(STACK_USE_DHCP) DHCPDisable(); #endif } #endif #if (DEBUG_MAIN >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:Starting main loop #endif /* * Once all items are initialized, go into infinite loop and let * stack items execute their tasks. * If application needs to perform its own task, it should be * done at the end of while loop. * Note that this is a "co-operative mult-tasking" mechanism * where every task performs its tasks (whether all in one shot * or part of it) and returns so that other tasks can do their * job. * If a task needs very long time to do its job, it must broken * down into smaller pieces so that other tasks can have CPU time. */ while(1) { //Blink SYSTEM LED every second. if (appcfgGetc(APPCFG_SYSFLAGS) & APPCFG_SYSFLAGS_BLINKB6) { if ( TickGetDiff8bit(t) >= ((TICK8)(TICKS_PER_SECOND/2)) ) { t = TickGet8bit(); TRISB_RB6 = 0; LATB6 ^= 1; } } //This task performs normal stack task including checking for incoming packet, //type of packet and calling appropriate stack entity to process it. StackTask(); #if defined(STACK_USE_HTTP_SERVER) //This is a TCP application. It listens to TCP port 80 //with one or more sockets and responds to remote requests. HTTPServer(); #endif #if defined(STACK_USE_FTP_SERVER) FTPServer(); #endif //Add your application speicifc tasks here. ProcessIO(); //For DHCP information, display how many times we have renewed the IP //configuration since last reset. if ( DHCPBindCount != myDHCPBindCount ) { #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(2); //@mxd:2:DHCP Bind Count = %D debugPutByteHex(DHCPBindCount); #endif //Display new IP address #if (DEBUG_MAIN >= LOG_INFO) debugPutMsg(3); //@mxd:3:DHCP complete, IP = %D.%D.%D.%D debugPutByteHex(AppConfig.MyIPAddr.v[0]); debugPutByteHex(AppConfig.MyIPAddr.v[1]); debugPutByteHex(AppConfig.MyIPAddr.v[2]); debugPutByteHex(AppConfig.MyIPAddr.v[3]); #endif myDHCPBindCount = DHCPBindCount; } } }