3

亲爱的 StackOverflowers 同胞,

我正在做一个项目,使用 Microchip 的 TCP/IP 堆栈在我的定制(和测试)板上实现 PIC18F87J60 上的某些东西。作为测试,我编写了一些代码来建立连接,将其保持 x 秒,然后优雅地关闭它。我已经将它实现为一个有限状态机。我还没有添加发送和接收数据。

但是,我的程序无法建立连接。使用 Wireshark,我注意到我的设备通过 DHCP 成功接收了 IP 地址,并且 ARP 解析正确完成。我暂时忽略了 DNS,因为这也会出错,但我稍后会解决这个问题。我还看到第一个 SYN 数据包由我的设备发送并由服务器按应有的方式响应,但 3 次握手中的 3e 步骤出错了。确认号只是一个随机数,因此服务器会感到困惑并使用 RST 数据包重置连接。然后我的设备使用带有另一个随机序列号的 ACK 数据包确认重置,并且服务器以某种方式接受该数据包。然后服务器尝试使用 SYN 数据包再次建立连接,但我的代码不侦听传入连接,因此连接结束。

这是我的代码:

#define THIS_IS_STACK_APPLICATION
#include "TCPIP.h"

APP_CONFIG AppConfig;

ROM char serverAddress[] = "data.zienu.eu"; //unused in this codefile: DNS doesn't work yet
ROM char serverIP[] = "80.69.92.56";
short authenticationPort = 5588;

typedef enum _SOCKET_STATE {
    SOCKET_DONE = 0,
    SETUP_CONNECTION,
    CONNECTING,
    CONNECTED,
    AWAITING_ANSWER,
    SENDING_DATA,
    CLOSE_CONNECTION,
    DISCONNECTING,
    DISCONNECTED
} SOCKET_STATE;

typedef struct _CONNECTION {
    TCP_SOCKET socketID;
    SOCKET_INFO* remoteInfo;
    const char* remoteHostName;
    WORD remotePort;
    SOCKET_STATE state, previousState;
    DWORD timeOut;
    BYTE purpose;
} CONNECTION;

void InitHardware();
void AuthenticateTask();
void FTPDownloadTask();
void HandleTCPConnection(CONNECTION* connection);

ROM BYTE SerializedMACAddress[6] = {MY_DEFAULT_MAC_BYTE1, MY_DEFAULT_MAC_BYTE2, MY_DEFAULT_MAC_BYTE3, MY_DEFAULT_MAC_BYTE4, MY_DEFAULT_MAC_BYTE5, MY_DEFAULT_MAC_BYTE6};
void InitAppConfig(void) {
    AppConfig.Flags.bIsDHCPEnabled = TRUE;
    AppConfig.Flags.bInConfigMode = TRUE;
    memcpypgm2ram((void*)&AppConfig.MyMACAddr, (ROM void*)SerializedMACAddress, sizeof(AppConfig.MyMACAddr));
    AppConfig.MyIPAddr.Val = MY_DEFAULT_IP_ADDR_BYTE1 | MY_DEFAULT_IP_ADDR_BYTE2<<8ul | MY_DEFAULT_IP_ADDR_BYTE3<<16ul | MY_DEFAULT_IP_ADDR_BYTE4<<24ul;
    AppConfig.DefaultIPAddr.Val = AppConfig.MyIPAddr.Val;
    AppConfig.MyMask.Val = MY_DEFAULT_MASK_BYTE1 | MY_DEFAULT_MASK_BYTE2<<8ul | MY_DEFAULT_MASK_BYTE3<<16ul | MY_DEFAULT_MASK_BYTE4<<24ul;
    AppConfig.DefaultMask.Val = AppConfig.MyMask.Val;
    AppConfig.MyGateway.Val = MY_DEFAULT_GATE_BYTE1 | MY_DEFAULT_GATE_BYTE2<<8ul | MY_DEFAULT_GATE_BYTE3<<16ul | MY_DEFAULT_GATE_BYTE4<<24ul;
    AppConfig.PrimaryDNSServer.Val = MY_DEFAULT_PRIMARY_DNS_BYTE1 | MY_DEFAULT_PRIMARY_DNS_BYTE2<<8ul  | MY_DEFAULT_PRIMARY_DNS_BYTE3<<16ul  | MY_DEFAULT_PRIMARY_DNS_BYTE4<<24ul;
    AppConfig.SecondaryDNSServer.Val = MY_DEFAULT_SECONDARY_DNS_BYTE1 | MY_DEFAULT_SECONDARY_DNS_BYTE2<<8ul  | MY_DEFAULT_SECONDARY_DNS_BYTE3<<16ul  | MY_DEFAULT_SECONDARY_DNS_BYTE4<<24ul;

    // Load the default NetBIOS Host Name
    memcpypgm2ram(AppConfig.NetBIOSName, (ROM void*)MY_DEFAULT_HOST_NAME, 10);
    FormatNetBIOSName(AppConfig.NetBIOSName);
}

void InitHardware() {
    /** \var isBoot (LATH0_bit) tells the boot-interrupt handler that boot is busy */
    LATHbits.LATH0 = 1;

    ADCON1 |= 0x0f;         // adc pins as I/0
    CMCON  |= 7;            // Disable comperator

    OSCCON = 0x04;
    OSCTUNE = 0x40; //41 MHz

    /******************************************************************/
    // init========
//    Het TRISA en TRISF register moeten goed zijn ingesteld voor de analoge input:
    PORTA = 0x00;
    TRISA = 0x20;   /* Bit 1 and 2 are used by ethernet LEDS */
    PORTB = 0x00;
    TRISB = 0x00;   /* output mode */
    PORTC = 0x03;   /* LED R en G off */
    TRISC = 0xc0;   /* Bit 6 and 7 are used by UART 1 */
    PORTD = 0x00;   /* used to display ethernetsecond_timer in DEBUG mode*/
    TRISD = 0x00;   /* output mode */
    PORTE = 0x00;
    TRISE = 0x00;   /* output mode */
    PORTF = 0x00;
    TRISF = 0x0E;   /* output mode */
    PORTG = 0x00;
    TRISG = 0x00;
    PORTH = 0x00;
    TRISH = 0x00;

    /* interrupt priorities are possible with microC */
    IPR1bits.ADIP = 0;      //give ADC LOW interrupt priority
    RCONbits.IPEN = 1;      //Enable interrupt priorities
    INTCON2bits.RBPU = 1;   // Disable internal PORTB pull-ups

    INTCONbits.GIEH = 1;
    INTCONbits.GIEL = 1;
}

void interrupt low_priority LowISR(void) {
    TickUpdate();
}

void interrupt HighISR(void) {
}

void HandleTCPConnection(CONNECTION* connection) {
    switch(connection->state) {
        case SETUP_CONNECTION:
            if(!AppConfig.Flags.bInConfigMode) {
                connection->socketID = TCPOpen((DWORD) (PTR_BASE)&serverIP[0], TCP_OPEN_ROM_HOST, connection->remotePort, connection->purpose);

                connection->timeOut = TickGet() + TICK_SECOND * 15;
                connection->previousState = SETUP_CONNECTION;
                connection->state = CONNECTING;
                TCPWasReset(connection->socketID);
            }
            break;
        case CONNECTING:
            if(TCPIsConnected(connection->socketID)) {
                connection->previousState = CONNECTING;
                connection->state = CONNECTED;
                connection->remoteInfo = TCPGetRemoteInfo(connection->socketID);
                connection->timeOut = TickGet() + TICK_SECOND * 10;
            }
            else if(TickGet() >= connection->timeOut) {
                connection->previousState = CONNECTING;
                connection->state = CLOSE_CONNECTION;
            }
            break;
        case CONNECTED:
            if(TickGet() >= connection->timeOut) {
                connection->previousState = CONNECTED;
                connection->state = CLOSE_CONNECTION;
            }
            else if(TCPWasReset(connection->socketID)) {
                connection->previousState = CONNECTED;
                connection->state = CLOSE_CONNECTION;
            }
            break;
        case CLOSE_CONNECTION:
                connection->previousState = CLOSE_CONNECTION;
                connection->state = DISCONNECTING;
                TCPDisconnect(connection->socketID);        //Send a TCP FIN packet
                connection->timeOut = TickGet() + TICK_SECOND * 5;
            break;
        case DISCONNECTING:
            if(TCPIsConnected(connection->socketID)) {
                connection->previousState = DISCONNECTING;
                connection->state = DISCONNECTED;
            }
            else if(TickGet() >= connection->timeOut) {
                TCPDisconnect(connection->socketID);
                TCPDisconnect(connection->socketID);    //Time out: Send a RST packet and proceed
                connection->previousState = DISCONNECTING;
                connection->state = DISCONNECTED;
            }
            break;
        case DISCONNECTED:
            connection->previousState = DISCONNECTED;
            connection->state = SOCKET_DONE;
            break;
        case SOCKET_DONE:
            break;
        default:
            break;
    }
}

void main() {
    InitHardware();
    TickInit();
    InitAppConfig();
    StackInit();

    CONNECTION connection;
    connection.purpose = TCP_PURPOSE_CUSTOM_FTP_CMD;
    connection.remoteHostName = serverIP;
    connection.remotePort = authenticationPort;
    connection.previousState = SOCKET_DONE;
    connection.state = SETUP_CONNECTION;
    while(TRUE) {
        HandleTCPConnection(&connection);
        StackTask();
        StackApplications();
    }
}

这是Wireshark 日志的屏幕截图。

在此先感谢,BitJunky

编辑:这是wireshark 转储文件。我过滤了 MAC 地址,因此部分 DHCP 进程未显示在此转储中。

4

1 回答 1

2

我解决了这个问题。我认为 TCPIP 堆栈与高科技编译器兼容,但似乎并非如此。C18 和 XC8 编译器与我发布的代码完美配合。

Greetz BitJunky

于 2012-12-06T15:39:30.613 回答