/** * Send the given byte to the USART. It is added to the transmit buffer, and asynchronously * transmitted. * * @param c Byte to write out on the serial port */ void serPutByte(BYTE c) { //Check if buffer is full. #ifdef SER_WAIT_FOR_TXBUF //Wait until a byte is transmitted by the interrupt routine and buffer has place again. while (busIsTxBufFull(BUSID)) { FAST_USER_PROCESS(); } #else if (busIsTxBufFull(BUSID)) { serStat |= SER1_TXBUF_OVERRUN; return; } #endif //Enter critical section DISBALE_INTERRUPTS(); //If we are not currently TXing, the TX buffer will be empty. No need to transmit via buffer, //just write direct to TXREG if ( !PIE1_TXIE) { TXREG = c; //Send byte PIE1_TXIE = 1; //Indicate that we are currently TXing ENABLE_INTERRUPTS(); } //We are currently TXing. This means that the TXIF will soon be set after the current byte //has been transmitted, and the TX buffer will be checked for any unsent data. Add current //byte to TX buffer. else { //Add byte to TX buffer, and update buffer pointers busPutByteTxBuf(BUFID, c); ENABLE_INTERRUPTS(); } }
/** * Set a specified byte in the APP_CONFIG configuration structure to a given value. * This function will only update the EEPROM if the given new value is different from the * current old value. This saves the EEPROM, and increases it's live! * * IMPORTANT - EEADRH must be set before calling this function! This configures the EEPROM page. * * @param offset Contains the offset in the APP_CONFIG structure of the byte to get * * @return Returns the requested byte */ void _appcfgPutc(WORD offset) { BYTE newValue; newValue = EEDATA; //Store new value //Set address EEADR = (BYTE)offset; EEADRH = (BYTE)(offset >> 8); //Wait if something is currently being written while(EECON1_WR) FAST_USER_PROCESS(); ///////////////////////////////////////////////// //Only write to EEPROM if new value is different from old value - this saves the EEPROM! //Configure for EEPROM reading, EEPGD=0, CFGS=0 EECON1 &= 0x3F; EECON1_RD = 1; //After setting this bit, the data is available on next cycle. Is cleared by hardware. //If new value is the same as the old value, return if (EEDATA == newValue) { return; } ///////////////////////////////////////////////// //Write new value to EEPROM EEDATA = newValue; //New value to be written //Configure for EEPROM writing, EEPGD=0, CFGS=0, FREE=0 EECON1 &= 0x2F; EECON1_WREN = 1; //Write enable EECON2 = 0x55; EECON2 = 0xAA; EECON1_WR = 1; Nop(); //Wait for write to finish while(EECON1_WR) FAST_USER_PROCESS(); EECON1_WREN = 0; return; }
/** * Delays for the given time. * @param ms Time to delay = given time x 1ms */ void DelayMs(unsigned char ms) { #if defined(HITECH_C18) while (ms--) { Delay10us(99); FAST_USER_PROCESS(); } #elif defined(MCHP_C18) while (ms--) { #if (CLOCK_FREQ == 40000000) Delay1KTCYx(8); //Delay 1ms #elif (CLOCK_FREQ == 20000000) Delay1KTCYx(4); //Delay 1ms #endif FAST_USER_PROCESS(); } #endif }
/** * Get a specified byte from the APP_CONFIG configuration structure * * @param offset Contains the offset in the APP_CONFIG structure of the byte to get * * @return Returns the requested byte */ BYTE appcfgGetc(WORD offset) { //Set address EEADR = (BYTE)offset; EEADRH = (BYTE)(offset >> 8); //Wait if something is currently being written while(EECON1_WR) FAST_USER_PROCESS(); //Configure for EEPROM reading, EEPGD=0, CFGS=0 EECON1 &= 0x3F; EECON1_RD = 1; //After setting this bit, the data is available on next cycle. Is cleared by hardware. return EEDATA; }
/** * Read single byte from I2C bus * * @param ack Indicates if a ACK is sent after reading the byte. During sequencial read * the master will usually send an ACK after each byte read except the last byte. Not * sending the ack will indicate to the slave that this is the end of sequential read * * @return Contents of SSPBUF register */ unsigned char i2cGetByte(BOOL ack) { SSPCON2_RCEN = 1; // enable master for 1 byte reception //At this stage, the slave can use clock streching to give it more time to collect the requested data. while ( !SSPSTAT_BF ) FAST_USER_PROCESS(); // wait until byte received while ( SSPCON2_RCEN ); // check that receive sequence is over //Send ACK or NACK SSPCON2_ACKDT = ack ? 0 : 1; //Send ACK when 0 and NACK when 1 SSPCON2_ACKEN = 1; while(SSPCON2_ACKEN); // Wait till finished return ( SSPBUF ); // return with read byte }
/** * This function transmit all data from the active UDP socket. * * @preCondition UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * @return All and any data associated with active UDP socket * buffer is marked as ready for transmission. * */ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ) FAST_USER_PROCESS(); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort.Val = swaps(p->localPort); h.DestinationPort.Val = swaps(p->remotePort); h.Length.Val = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum.Val = 0x00; //Makes the given TX Buffer active, and set's the pointer to the first byte after the IP //header. This is the first byte of the UDP header. The UDP header follows the IP header. IPSetTxBuffer(p->TxBuffer, 0); //Load IP header. IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length.Val ); //Now swap h.Length.Val h.Length.Val = swaps(h.Length.Val); //Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); //Update checksum. !!!!!!!!!!!!!!! TO BE IMPLEMENTED !!!!!!!!!!!!!!!!!!! //Send data contained in TX Buffer via MAC MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
static void ProcessIO(void) { //Convert next ADC channel, and store result in adcChannel array #if (defined(APP_USE_ADC8) || defined(APP_USE_ADC10)) && (ADC_CHANNELS > 0) static BYTE adcChannel; //Current ADC channel. Value from 0 - n //We are allowed to update AdcValues[] buffer //if (!mainFlags.bits.bFreezeADCBuf) { //Increment to next ADC channel if ((++adcChannel) >= ADC_CHANNELS) { adcChannel = 0; } //Check if current ADC channel (adcChannel) is configured to be ADC channel if (adcChannel < ((~ADCON1) & 0x0F)) { //Convert next ADC Channel ADCON0 &= ~0x3C; ADCON0 |= (adcChannel << 2); ADCON0_ADON = 1; //Switch on ADC ADCON0_GO = 1; //Go while (ADCON0_GO) FAST_USER_PROCESS(); //Wait for conversion to finish #if defined(APP_USE_ADC8) AdcValues[adcChannel] = ADRESH; #elif defined(APP_USE_ADC10) AdcValues[adcChannel] = ((WORD)ADRESH << 8) || ADRESL; #endif } //Not ADC channel, set to 0 else { AdcValues[adcChannel] = 0; } } #endif }
/** * 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(); }
/********************************************************************* * 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); }
/** * Must be called every couple of ms * */ void busTask(void) { BYTE c; BYTE bytesRead; BYTE busId; BYTE linkedMask; ///////////////////////////////////////////////// //UDP 1 //Get bus to link to UDP 1 busId = appcfgGetc(BUSCFG_UDP1_LINK); #if defined(BRD_SBC65EC) //Currently UDP 1 can only be linked to Serial 1, Serial 2 and I2C for SBC65EC if ((busId >= BUSID_SER1) && (busId <= BUSID_I2C1) && (udpBus1 != INVALID_UDP_SOCKET)) { #else //Currently UDP 1 can only be linked to Serial 1 and I2C for SBC68EC if ( ((busId == BUSID_SER1) || (busId == BUSID_I2C1)) && (udpBus1 != INVALID_UDP_SOCKET)) { #endif //Is there any data waiting for us on this UDP port? if (UDPIsGetReady(udpBus1)) { if (busIsEnabled(busId)) { //Read bytes while (UDPGet(&c)) { //Wait until a byte is transmitted by the interrupt routine and buffer has place again. while (busIsTxBufFull(busId)) { busService(busId); FAST_USER_PROCESS(); } //Add byte to TX buffer, and update buffer pointers busPutByteTxBuf(busId, c); } //Initiate transmitting if not already transmitting if (!busIsTxing(busId)) { busService(busId); } } //Discard the socket buffer. UDPDiscard(); } //Is there any data to send on UDP port if(busRxBufHasData(busId)) { if (UDPIsPutReady(udpBus1)) { while(busRxBufHasData(busId)) { //Read and remove byte from buffer c = busPeekByteRxBuf(busId); busRemoveByteRxBuf(busId); UDPPut(c); } // Now transmit it. UDPFlush(); } } } ///////////////////////////////////////////////// //UDP 2 //Get bus to link to UDP 2 busId = appcfgGetc(BUSCFG_UDP2_LINK); #if defined(BRD_SBC65EC) //Currently UDP 1 can only be linked to Serial 1, Serial 2 and I2C for SBC65EC if ((busId >= BUSID_SER1) && (busId <= BUSID_I2C1) && (udpBus1 != INVALID_UDP_SOCKET)) { #else //Currently UDP 1 can only be linked to Serial 1 and I2C for SBC68EC if ( ((busId == BUSID_SER1) || (busId == BUSID_I2C1)) && (udpBus1 != INVALID_UDP_SOCKET)) { #endif //Is there any data waiting for us on this UDP port? if (UDPIsGetReady(udpBus2)) { if (busIsEnabled(busId)) { //Read bytes while (UDPGet(&c)) { //Wait until a byte is transmitted by the interrupt routine and buffer has place again. while (busIsTxBufFull(busId)) { busService(busId); FAST_USER_PROCESS(); } //Add byte to TX buffer, and update buffer pointers busPutByteTxBuf(busId, c); } //Initiate transmitting if not already transmitting if (!busIsTxing(busId)) { busService(busId); } } //Discard the socket buffer. UDPDiscard(); } //Is there any data to send on UDP port if(busRxBufHasData(busId)) { if (UDPIsPutReady(udpBus2)) { while(busRxBufHasData(busId)) { //Read and remove byte from buffer c = busPeekByteRxBuf(busId); busRemoveByteRxBuf(busId); UDPPut(c); } // Now transmit it. UDPFlush(); } } } ///////////////////////////////////////////////// //Service all serial buses for (busId=0; busId<BUS_COUNT; busId++) { busService(busId); } } /** * Service the given bus. If our code has a section where it has to wait for the transmit * buffer of a bus to be empties, it should call this function while waiting. * * @param busId The bus ID of the requested bus. Is a BUSID_XXX variable * */ void busService(BYTE busId) { switch(busId) { case BUSID_SER1: serService(); break; #if defined(BRD_SBC65EC) case BUSID_SER2: ser2Service(); break; #endif case BUSID_I2C1: i2cBusService(); break; case BUSID_SPI1: NOP(); break; } } /** * Gets a byte at the given offset from the Transmit Buffer, without removing it. * The byte is NOT removed from the buffer, and the buffer pointers are NOT updated! * The byte at the given offset it returned. The offset is how deep the byte is in * the buffer. For example, 0 will return first byte in buffer, 5 will return the 6th * byte in the buffer. * * @preCondition Ensure offset parameter is not larger than current number of bytes * contained in buffer. Call busGetTxBufCount() to get current number of bytes in buffer. * * @param busId The bus ID of the requested bus. Is a BUSID_XXX variable * @param offset Offset of byte to return. Is a value from 0-n, where n = (busGetTxBufCount() - 1) * * @return Returns the byte at the given offset in the given bus's Transmit buffer. */ BYTE busPeekByteTxBufAt(BYTE busId, BYTE offset) { BYTE ofst; ofst = busInfo.buf[busId].getTx + offset; //Check if offset wrap around if (ofst >= busInfo.buf[busId].txBufSize) { ofst = ofst - busInfo.buf[busId].txBufSize; } return *(busInfo.buf[busId].txBuf + ofst); } /** * Gets a byte at the given offset from the Receive Buffer, without removing it. * The byte is NOT removed from the buffer, and the buffer pointers are NOT updated! * The byte at the given offset it returned. The offset is how deep the byte is in * the buffer. For example, 0 will return first byte in buffer, 5 will return the 6th * byte in the buffer. * * @preCondition Ensure offset parameter is not larger than current number of bytes * contained in buffer. Call busGetRxBufCount() to get current number of bytes in buffer. * * @param busId The bus ID of the requested bus. Is a BUSID_XXX variable * @param offset Offset of byte to return. Is a value from 0-n, where n = (busGetRxBufCount() - 1) * * @return Returns the byte at the given offset in the given bus's Receive buffer. */ BYTE busPeekByteRxBufAt(BYTE busId, BYTE offset) { BYTE ofst; ofst = busInfo.buf[busId].getRx + offset; //Check if offset wrap around if (ofst >= busInfo.buf[busId].rxBufSize) { ofst = ofst - busInfo.buf[busId].rxBufSize; } return *(busInfo.buf[busId].rxBuf + ofst); }
/** * This function transmit all data from the active UDP socket. * * @preCondition UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * @return All and any data associated with active UDP socket * buffer is marked as ready for transmission. * */ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; WORD csLength; DWORD_VAL csChecksum; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ) FAST_USER_PROCESS(); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort.Val = swaps(p->localPort); h.DestinationPort.Val = swaps(p->remotePort); h.Length.Val = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum.Val = 0x00; //Makes the given TX Buffer active, and set's the pointer to the first byte after the IP //header. This is the first byte of the UDP header. The UDP header follows the IP header. IPSetTxBuffer(p->TxBuffer, 0); //Load IP header. IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length.Val ); // save length before swap for checksum calculation csLength = p->TxCount; //Now swap h.Length.Val h.Length.Val = swaps(h.Length.Val); //Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); //Update checksum. !!!!!!!!!!!!!!! TO BE IMPLEMENTED !!!!!!!!!!!!!!!!!!! // Update checksum. // start the checksum with value for UDP protocol & length from pseudo header (and in the actual packet) csChecksum.Val = (WORD)IP_PROT_UDP + (WORD)csLength + sizeof(UDP_HEADER); // add in my address and the remoteNode address csChecksum.Val += ((WORD)MY_IP_BYTE1 << 8) + MY_IP_BYTE2; csChecksum.Val += ((WORD)MY_IP_BYTE3 << 8) + MY_IP_BYTE4; csChecksum.Val += ((WORD)p->remoteNode.IPAddr.v[0] << 8) + ((WORD)p->remoteNode.IPAddr.v[1] ) + ((WORD)p->remoteNode.IPAddr.v[2] << 8) + ((WORD)p->remoteNode.IPAddr.v[3] ); // set mac pointer to the ip_addr of the source, so all of pseudo header but length is included. // length of pseudo header is already included in previous instruction. //MACSetRxBuffer( sizeof(IP_HEADER)+sizeof(UDP_HEADER) ); csChecksum.Val += (WORD)p->localPort; csChecksum.Val += (WORD)p->remotePort; csChecksum.Val += (WORD)csLength + sizeof(UDP_HEADER); //IPSetRxBuffer(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) - ( sizeof(IP_ADDR) * 2 ) ); // handled in UdpPut routines csChecksum.Val += udpChecksum; // add any carry over to the last word while((DWORD)csChecksum.word.MSW) { csChecksum.Val = (DWORD)csChecksum.word.LSW + (DWORD)csChecksum.word.MSW; } // add any carry over from adding the carry over //csChecksum.Val = (DWORD)csChecksum.word.LSW + (DWORD)csChecksum.word.MSW; // invert csChecksum.Val = ~csChecksum.Val; // set write pointer to location of checksum in packet //MACSetWritePtr( sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + sizeof(UDP_HEADER) - 2 ); IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER) - 2); // write the swapped checksum to the packet //MACPut( csChecksum.v[1] ); //MACPut( csChecksum.v[0] ); MACPut(0); MACPut(0); //Send data contained in TX Buffer via MAC MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/** * DHCP PACKET FORMAT AS PER RFC 1541 * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | op (1) | htype (1) | hlen (1) | hops (1) | * +---------------+---------------+---------------+---------------+ * | xid (4) | * +-------------------------------+-------------------------------+ * | secs (2) | flags (2) | * +-------------------------------+-------------------------------+ * | ciaddr (4) | * +---------------------------------------------------------------+ * | yiaddr (4) | * +---------------------------------------------------------------+ * | siaddr (4) | * +---------------------------------------------------------------+ * | giaddr (4) | * +---------------------------------------------------------------+ * | | * | chaddr (16) | * | | * | | * +---------------------------------------------------------------+ * | | * | sname (64) | * +---------------------------------------------------------------+ * | | * | file (128) | * +---------------------------------------------------------------+ * | | * | options (312) | * +---------------------------------------------------------------+ * */ static BYTE _DHCPReceive(void) { BYTE v; BYTE i, j; BYTE type; BOOL lbDone; DWORD_VAL tempServerID; MAC_ADDR tempMacAddr; // Assume unknown message until proven otherwise. type = DHCP_UNKNOWN_MESSAGE; UDPGet(&v); // op // Make sure this is BOOT_REPLY. if ( v == BOOT_REPLY ) { // Discard htype, hlen, hops, xid, secs, flags, ciaddr. for ( i = 0; i < 15u; i++ ) UDPGet(&v); // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered IP address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { // Save offered IP address until we know for sure that we have it. UDPGet(&tempIPAddress.v[0]); UDPGet(&tempIPAddress.v[1]); UDPGet(&tempIPAddress.v[2]); UDPGet(&tempIPAddress.v[3]); ValidValues.bits.IPAddress = 1; } // Ignore siaddr, giaddr for ( i = 0; i < 8u; i++ ) UDPGet(&v); // Check to see if chaddr (Client Hardware Address) belongs to us. tempMacAddr.v[0] = MY_MAC_BYTE1; tempMacAddr.v[1] = MY_MAC_BYTE2; tempMacAddr.v[2] = MY_MAC_BYTE3; tempMacAddr.v[3] = MY_MAC_BYTE4; tempMacAddr.v[4] = MY_MAC_BYTE5; tempMacAddr.v[5] = MY_MAC_BYTE6; for ( i = 0; i < 6u; i++ ) { UDPGet(&v); if ( v != tempMacAddr.v[i]) goto UDPInvalid; } // Ignore part of chaddr, sname, file, magic cookie. for ( i = 0; i < 206u; i++ ) UDPGet(&v); lbDone = FALSE; do { // Get the Option number // Break out eventually in case if this is a malformed // DHCP message, ie: missing DHCP_END_OPTION marker if(!UDPGet(&v)) { lbDone = TRUE; break; } switch(v) { case DHCP_MESSAGE_TYPE: UDPGet(&v); // Skip len // Len must be 1. if ( v == 1u ) { UDPGet(&type); // Get type // Throw away the packet if we know we don't need it (ie: another offer when we already have one) if(DHCPState.bits.bOfferReceived && (type == DHCP_OFFER_MESSAGE)) { goto UDPInvalid; } } else goto UDPInvalid; break; case DHCP_SUBNET_MASK: UDPGet(&v); // Skip len // Len must be 4. if ( v == 4u ) { // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered IP mask, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&tempMask.v[0]); UDPGet(&tempMask.v[1]); UDPGet(&tempMask.v[2]); UDPGet(&tempMask.v[3]); ValidValues.bits.Mask = 1; } } else goto UDPInvalid; break; case DHCP_ROUTER: UDPGet(&j); // Len must be >= 4. if ( j >= 4u ) { // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered Gateway address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&tempGateway.v[0]); UDPGet(&tempGateway.v[1]); UDPGet(&tempGateway.v[2]); UDPGet(&tempGateway.v[3]); ValidValues.bits.Gateway = 1; } } else goto UDPInvalid; // Discard any other router addresses. j -= 4; while(j--) UDPGet(&v); break; #if defined(STACK_USE_DNS) case DHCP_DNS: UDPGet(&j); // Len must be >= 4. if ( j >= 4u ) { // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered DNS server address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&tempDNS.v[0]); UDPGet(&tempDNS.v[1]); UDPGet(&tempDNS.v[2]); UDPGet(&tempDNS.v[3]); ValidValues.bits.DNS = 1; } } else goto UDPInvalid; // Discard any other DNS server addresses j -= 4; while(j--) UDPGet(&v); break; #endif // case DHCP_HOST_NAME: // UDPGet(&j); // // Len must be >= 4. // if(j < 1u) // goto UDPInvalid; // // // Check to see if this is the first offer // if(DHCPState.bits.bOfferReceived) // { // // Discard offered host name, we already have an offer // while(j--) // UDPGet(&v); // } // else // { // for(i = 0; j, i < sizeof(tempHostName); i++, j--) // { // UDPGet(&tempHostName[i]); // } // while(j--) // { // UDPGet(&v); // } // ValidValues.bits.HostName = 1; // } // // break; case DHCP_SERVER_IDENTIFIER: UDPGet(&v); // Get len // Len must be 4. if ( v == 4u ) { UDPGet(&tempServerID.v[3]); // Get the id UDPGet(&tempServerID.v[2]); UDPGet(&tempServerID.v[1]); UDPGet(&tempServerID.v[0]); } else goto UDPInvalid; break; case DHCP_END_OPTION: lbDone = TRUE; break; case DHCP_IP_LEASE_TIME: UDPGet(&v); // Get len // Len must be 4. if ( v == 4u ) { // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered lease time, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&DHCPLeaseTime.v[3]); UDPGet(&DHCPLeaseTime.v[2]); UDPGet(&DHCPLeaseTime.v[1]); UDPGet(&DHCPLeaseTime.v[0]); // Due to possible timing delays, consider actual lease // time less by half hour. if ( DHCPLeaseTime.Val > HALF_HOUR ) DHCPLeaseTime.Val = DHCPLeaseTime.Val - HALF_HOUR; } } else goto UDPInvalid; break; default: // Ignore all unsupport tags. UDPGet(&j); // Get option len while( j-- ) // Ignore option values UDPGet(&v); } FAST_USER_PROCESS(); } while( !lbDone ); } // If this is an OFFER message, remember current server id. if ( type == DHCP_OFFER_MESSAGE ) { DHCPServerID.Val = tempServerID.Val; DHCPState.bits.bOfferReceived = TRUE; } else { // For other types of messages, make sure that received // server id matches with our previous one. if ( DHCPServerID.Val != tempServerID.Val ) type = DHCP_UNKNOWN_MESSAGE; } UDPDiscard(); // We are done with this packet return type; UDPInvalid: UDPDiscard(); return DHCP_UNKNOWN_MESSAGE; }
/***************************************************************************** Function: void _DHCPReceive(void) Description: Receives and parses a DHCP message. Precondition: A DHCP message is waiting in the UDP buffer. Parameters: None Returns: One of the DCHP_TYPE* contants. ***************************************************************************/ static BYTE _DHCPReceive(void) { /********************************************************************* DHCP PACKET FORMAT AS PER RFC 1541 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | op (1) | htype (1) | hlen (1) | hops (1) | +---------------+---------------+---------------+---------------+ | xid (4) | +-------------------------------+-------------------------------+ | secs (2) | flags (2) | +-------------------------------+-------------------------------+ | ciaddr (4) | +---------------------------------------------------------------+ | yiaddr (4) | +---------------------------------------------------------------+ | siaddr (4) | +---------------------------------------------------------------+ | giaddr (4) | +---------------------------------------------------------------+ | | | chaddr (16) | | | | | +---------------------------------------------------------------+ | | | sname (64) | +---------------------------------------------------------------+ | | | file (128) | +---------------------------------------------------------------+ | | | options (312) | +---------------------------------------------------------------+ ********************************************************************/ BYTE v; BYTE i, j; BYTE type; BOOL lbDone; DWORD_VAL tempServerID; // Assume unknown message until proven otherwise. type = DHCP_UNKNOWN_MESSAGE; UDPGet(&v); // op // Make sure this is BOOT_REPLY. if ( v == BOOT_REPLY ) { // Discard htype, hlen, hops, xid, secs, flags, ciaddr. for ( i = 0; i < 15u; i++ ) UDPGet(&v); // Check to see if this is the first offer if(DHCPFlags.bits.bOfferReceived) { // Discard offered IP address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { // Save offered IP address until we know for sure that we have it. UDPGetArray((BYTE*)&tempIPAddress, sizeof(tempIPAddress)); ValidValues.bits.IPAddress = 1; } // Ignore siaddr, giaddr for ( i = 0; i < 8u; i++ ) UDPGet(&v); // Check to see if chaddr (Client Hardware Address) belongs to us. for ( i = 0; i < 6u; i++ ) { UDPGet(&v); if ( v != AppConfig.MyMACAddr.v[i]) goto UDPInvalid; } // Ignore part of chaddr, sname, file, magic cookie. for ( i = 0; i < 206u; i++ ) UDPGet(&v); lbDone = FALSE; do { // Get the Option number // Break out eventually in case if this is a malformed // DHCP message, ie: missing DHCP_END_OPTION marker if(!UDPGet(&v)) { lbDone = TRUE; break; } switch(v) { case DHCP_MESSAGE_TYPE: UDPGet(&v); // Skip len // Len must be 1. if ( v == 1u ) { UDPGet(&type); // Get type // Throw away the packet if we know we don't need it (ie: another offer when we already have one) if(DHCPFlags.bits.bOfferReceived && (type == DHCP_OFFER_MESSAGE)) { goto UDPInvalid; } } else goto UDPInvalid; break; case DHCP_SUBNET_MASK: UDPGet(&v); // Skip len // Len must be 4. if ( v == 4u ) { // Check to see if this is the first offer if(DHCPFlags.bits.bOfferReceived) { // Discard offered IP mask, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGetArray((BYTE*)&tempMask, sizeof(tempMask)); ValidValues.bits.Mask = 1; } } else goto UDPInvalid; break; case DHCP_ROUTER: UDPGet(&j); // Len must be >= 4. if ( j >= 4u ) { // Check to see if this is the first offer if(DHCPFlags.bits.bOfferReceived) { // Discard offered Gateway address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGetArray((BYTE*)&tempGateway, sizeof(tempGateway)); ValidValues.bits.Gateway = 1; } } else goto UDPInvalid; // Discard any other router addresses. j -= 4; while(j--) UDPGet(&v); break; #if defined(STACK_USE_DNS) case DHCP_DNS: UDPGet(&j); // Len must be >= 4. if(j < 4u) goto UDPInvalid; // Check to see if this is the first offer if(!DHCPFlags.bits.bOfferReceived) { UDPGetArray((BYTE*)&tempDNS, sizeof(tempDNS)); ValidValues.bits.DNS = 1; j -= 4; } // Len must be >= 4 for a secondary DNS server address if(j >= 4u) { // Check to see if this is the first offer if(!DHCPFlags.bits.bOfferReceived) { UDPGetArray((BYTE*)&tempDNS2, sizeof(tempDNS2)); ValidValues.bits.DNS2 = 1; j -= 4; } } // Discard any other DNS server addresses while(j--) UDPGet(&v); break; #endif // case DHCP_HOST_NAME: // UDPGet(&j); // // Len must be >= 4. // if(j < 1u) // goto UDPInvalid; // // // Check to see if this is the first offer // if(DHCPFlags.bits.bOfferReceived) // { // // Discard offered host name, we already have an offer // while(j--) // UDPGet(&v); // } // else // { // for(i = 0; j, i < sizeof(tempHostName); i++, j--) // { // UDPGet(&tempHostName[i]); // } // while(j--) // { // UDPGet(&v); // } // ValidValues.bits.HostName = 1; // } // // break; case DHCP_SERVER_IDENTIFIER: UDPGet(&v); // Get len // Len must be 4. if ( v == 4u ) { UDPGet(&tempServerID.v[3]); // Get the id UDPGet(&tempServerID.v[2]); UDPGet(&tempServerID.v[1]); UDPGet(&tempServerID.v[0]); } else goto UDPInvalid; break; case DHCP_END_OPTION: lbDone = TRUE; break; case DHCP_IP_LEASE_TIME: UDPGet(&v); // Get len // Len must be 4. if ( v == 4u ) { // Check to see if this is the first offer if(DHCPFlags.bits.bOfferReceived) { // Discard offered lease time, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&DHCPLeaseTime.v[3]); UDPGet(&DHCPLeaseTime.v[2]); UDPGet(&DHCPLeaseTime.v[1]); UDPGet(&DHCPLeaseTime.v[0]); // In case if our clock is not as accurate as the remote // DHCP server's clock, let's treat the lease time as only // 96.875% of the value given DHCPLeaseTime.Val -= DHCPLeaseTime.Val>>5; } } else goto UDPInvalid; break; default: // Ignore all unsupport tags. UDPGet(&j); // Get option len while( j-- ) // Ignore option values UDPGet(&v); } FAST_USER_PROCESS(); } while( !lbDone ); }