[En-Nut-Discussion] Calling the same function from different threads.

Javier Longares supertxaby at gmail.com
Wed Dec 2 12:19:21 CET 2009


Hello Ole,

Of course I've also seen the rs232d.c example, however there are significant
differents respect our target.  First, rs232d.c uses only a thread for the
UART and the TCP socket is opened in the main endless loop. In addition,
the  uart starts read only once the socket is opened and never else, and
there are no data processing (and here my problem, since I try to save data
which could come simoultaneously from UART and TCP in different buffers and
process it).

I'm trying also to make an implementation based on hardware interrupts for
the UART, thinking that it could solve part of the problem, nevertheless, I
post the code I'll be glad to appreciate your opinion.

typedef struct {
    unsigned char Data[BUFFER_LENGTH];
    FILE *stream;
    unsigned int Flags:16;
    unsigned char Retries;
    unsigned int Index:16;
    unsigned int CRC_RX:16;
    unsigned int CRC_Computed:16;
}COM_CHANNEL;

    static COM_CHANNEL TCPSocket;
    static COM_CHANNEL UART;

//definitions for Channel selection:
#define TCP_PORT 1 //For selecting the TCPSocket COM_CHANNEL when calling
several functions.
#define UART_CHANNEL 0 //For selecting the UART COM_CHANNEL when calling
those functions.

//There are also some definitions for values like STX, ETX, etc by I think
wititng here is irrelevant for this problem.

char ComputeCRC(unsigned char ChannelSelect)
{
   //several lines here... simply:
return 1 if CRC Checksum OK of data in the selected channel, else returns 0
}

void Tunnelize (unsigned char SourceSelect)
{
    unsigned char Counter = 0;
    switch(SourceSelect)
    {
        case TCP_PORT:
            while (Counter < TCPSocket.Index)
                fputc(TCPSocket.Data[Counter++], UART.stream);
            fflush(UART.stream);
            break;
        case UART_PORT:
            while (Counter < UART.Index)
                fputc(UART.Data[Counter++], TCPSocket.stream);
            fflush(TCPSocket.stream);
            break;
        break;
        default:
        break;
    }
}

void CleanChannel (unsigned char ChannelSelect)
{
    switch(ChannelSelect)
    {
        case TCP_PORT:
            TCPSocket.Index = 0;
            while (TCPSocket.Index < BUFFER_LENGTH)
TCPSocket.Data[TCPSocket.Index++] = 0;
            TCPSocket.Flags = RESET;
            TCPSocket.Index = 0;
            TCPSocket.Retries = 0;
            TCPSocket.CRC_RX = 0;
            TCPSocket.CRC_Computed = 0;
        break;
        case UART_PORT:
            UART.Index = 0;
            while (UART.Index < BUFFER_LENGTH)    UART.Data[UART.Index++] =
0;
            UART.Flags = RESET;
            UART.Index = 0;
            UART.Retries = 0;
            UART.CRC_RX = 0;
            UART.CRC_Computed = 0;
        break;
        default:
        break;
    }
}

unsigned char GetByte (unsigned char ChannelSelect)
{
    switch(ChannelSelect)
    {
        case TCP_PORT:
            return fgetc(TCPSocket.stream);
            break;
        case UART_PORT:
            return fgetc(UART.stream);
            break;
        default:
            return EOF;
            break;
    }
}

void PutByte (unsigned char Byte, unsigned char ChannelSelect)
{
    switch(ChannelSelect)
    {
        case TCP_PORT:
            fputc(Byte, TCPSocket.stream);
            break;
        case UART_PORT:
            fputc(Byte, UART.stream);
    }
}

/*
 * Process client requests.
 */
void ProcessTCPRequests(void)
{
    unsigned char Room1, Room2;

    TCPSocket.Index = 0;
    fputs("Dentro socket", UART.stream);
    //Room1 = fgetc(TCPSocket.stream);
    //Room2 = fgetc(TCPSocket.stream);
    Room1 = GetByte(TCP_PORT);
    Room2=GetByte(TCP_PORT);

    while (TCPSocket.Flags != EOT)
    {
        TCPSocket.Data[TCPSocket.Index] = GetByte(TCP_PORT);//
fgetc(TCPSocket.stream);

        if (TCPSocket.Data[TCPSocket.Index] == ETX)
            if(TCPSocket.Data[TCPSocket.Index - 1] == DLE)
            {
                TCPSocket.Flags = EOT;
            }
        TCPSocket.Index++;
    }

    if(ComputeCRC(TCP_PORT) == 1)
    {
        fputc(ACK_BYTE1, TCPSocket.stream);
        fputc(ACK_BYTE2, TCPSocket.stream);
        fputc(ACK_BYTE3, TCPSocket.stream);
        Tunnelize(TCP_PORT);
    }
    else
    {
        fputc(NACK_BYTE1, UART.stream);
        fputc(NACK_BYTE2, UART.stream);
        fputc(NACK_BYTE3, UART.stream);

    }
}


/*
 * TCP socket thread (based on tcps.c example.  DOESNT WORK!
 */
THREAD(Thread1, arg)
{
    TCPSOCKET *sock;
    COM_CHANNEL TCPSocket;
    u_char mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x55 };


    NutRegisterDevice(&DEV_ETHER, 0x8300, 5);

    NutNetLoadConfig(DEV_ETHER_NAME);
    memcpy(confnet.cdn_mac, mac, 6);
    NutNetSaveConfig();

     /*
     * Setup the ethernet device. Try DHCP first. If this is
     * the first time boot with empty EEPROM and no DHCP server
     * was found, use hardcoded values.
     */
    //printf("Configure eth0...");

    if (NutDhcpIfConfig("eth0", 0, 60000)) {
        printf("initial boot...");
        if (NutDhcpIfConfig("eth0", mac, 60000)) {
            u_long ip_addr = inet_addr("192.168.1.102");
            u_long ip_mask = inet_addr("255.255.255.0");

            //printf("no DHCP...");
            NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
            /* If not in a local network, we must also call
               NutIpRouteAdd() to configure the routing. */
        }
    }

    /*
     * Endless loop in high priority thread.
     */
    NutThreadSetPriority(16);
    for (;;) {

        CleanChannel(TCP_PORT);

        printf("Creating Socket...\n\r");
        if ((sock = NutTcpCreateSocket()) != 0) {
            /*
             * Listen on port 1999. If we return, we got a client.
             */
            printf("Waiting for a telnet client...");
            if (NutTcpAccept(sock, 1999) == 0) {
                TCPSocket.Flags |= ACTIVE;
                //TCPState =TCP_CONNECTED;
                //printf("Socket connected");

                /*
                 * Open a stream and associate it with the socket, so
                 * we can use standard I/O. Note, that socket streams
                 * currently do support text mode.
                 */
                if ((TCPSocket.stream = _fdopen((int) sock, "r+b")) != 0)
                {
                    /*
                     * Process client requests.
                     */

                    ProcessTCPRequests();

                    fclose(TCPSocket.stream);
                } else
                    printf("Assigning a stream failed");
            } else
                printf("failed");

            /*
             * Close our socket.
             */
            NutTcpCloseSocket(sock);
        }
        NutSleep(125);
    }
}

void ProcessUARTRequests(void)
{
    UART.Data[UART.Index] = GetByte(UART_PORT);//getc(UART.stream);
    if(UART.Index == 0)
    {
        if(UART.Data[UART.Index] != STX)
        {
            UART.Flags = (ERROR | EOT);
        }
        else
            UART.Index++;
    }
    else
    {
        if(UART.Index == 1)
        {
            switch (UART.Data[UART.Index])
            {
                case ACK:
                    UART.Flags |= ACK_RECEIVED;
                    UART.Index++;
                    break;
                case NACK:
                    UART.Flags |= NACK_RECEIVED;
                    UART.Flags |= ERROR;
                    UART.Index++;
                    break;
                case DATA:
                    UART.Flags |= DATA_RECEIVED;
                    UART.Index++;
                    break;
                default:
                    UART.Flags |= ERROR;
                    UART.Index = 0;
                    break;
            }
        }
        else
        {
            if(UART.Flags & ACK_RECEIVED)
                UART.Flags |= EOT;
            if(UART.Flags & NACK_RECEIVED)
                UART.Flags |= EOT;
            if(UART.Flags & DATA_RECEIVED)
            {
                if(UART.Data[UART.Index] == ETX)
                    if(UART.Data[UART.Index - 1] == DLE)
                        UART.Flags |= EOT;
                UART.Index++;
            }
        }
    }


    if(UART.Flags & EOT)
    {
        fputs("\n\rSERIAL DATA ANALYSIS\n\r", UART.stream);
        fflush(UART.stream);
        fputs("====================\n\n\n\r", UART.stream);
        fflush(UART.stream);
        ////Process the message content here.
        if(UART.Flags & ACK_RECEIVED)
        {
            fputs("ACK\n\r", UART.stream);
            fflush(UART.stream);
            CleanChannel(UART_PORT);
        }
        if(UART.Flags & NACK_RECEIVED)
        {
            fputs("NACK\n\r", UART.stream);
            fflush(UART.stream);
            CleanChannel(UART_PORT);
        }
        if(UART.Flags &DATA_RECEIVED)
        {
            fputs("Data\n\r", UART.stream);
            fflush(UART.stream);
            if(TCPSocket.Flags & ACTIVE)
                Tunnelize(UART_PORT);
        }
        if(UART.Flags & ERROR)
        {
            fputs("ERROR Flag\n\r", UART.stream);
        }
        UART.Flags = RESET;
        UART.Index = 0;
    }
}


/*
 * UART thread
 */
THREAD(Thread2, arg)
{
    u_long baud = 115200;
    NutRegisterDevice(&DEV_UART, 0, 0);
    UART.stream = freopen(DEV_UART_NAME, "r+b", stdout);
    _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
    fputs("\n\rSystem ready\n\r", UART.stream);
    NutThreadSetPriority(128);
    for (;;) {
        ProcessUARTRequests();
        NutSleep(125);
    }
}

/*
 * Main application thread.
 */
int main(void)
{
    NutThreadCreate("Uart", Thread2, 0, 512);
    NutThreadCreate("Socket", Thread1, 0, 512);

    for (;;) NutSleep(125);
}


2009/12/2 Ole Reinhardt <ole.reinhardt at embedded-it.de>

> Hello,
>
> > However, because they are allways listening, both threads calls the getc
> > functions and I think it can be a problem.  On the one hand, I can test
> the
> > UART tasks and it works fine, but when I open the TCP port the systems
> > doesn't work further, neither UART and TCP.  TCP thread is based in the
> > tcps.c sample.
>
> Take a look into rs232d.c which might be what you are planning to do.
>
> There should be no problem if you call the file io functions from
> different threads. There are only very few functions that are not
> thread safe at all (and those should be marked in the documentation).
>
> If you use the same file descriptor from different threads, use a mutex
> to lock concurrent access. Otherwise you might get interleaved data if
> you call e.g. fprintf on the same filedscriptor from both threads.
>
> If your program hangs you might have produced a buffer overflow. Or do
> you have an endless loop without thread switching point?
>
> If this does not help, please post your code here, so we could help you
> better.
>
> Bye,
>
> Ole Reinhardt
>
> --
>
> Thermotemp GmbH, Embedded-IT
>
> Embedded Hard-/ Software and Open Source Development,
> Integration and Consulting
>
> Geschäftsstelle Siegen - Steinstraße 67 - D-57072 Siegen -
> tel +49 (0)271 5513597, +49 (0)271-73681 - fax +49 (0)271 736 97
>
> Hauptsitz - Hademarscher Weg 7 - 13503 Berlin
> Tel +49 (0)30 4315205 - Fax +49 (0)30 43665002
> Geschäftsführer: Jörg Friedrichs, Ole Reinhardt
> Handelsregister Berlin Charlottenburg HRB 45978 UstID DE 156329280
>
> _______________________________________________
> http://lists.egnite.de/mailman/listinfo/en-nut-discussion
>



More information about the En-Nut-Discussion mailing list