Author Topic: Newbie's firsttime with uTasker  (Read 55399 times)

Offline echel0n

  • Newbie
  • *
  • Posts: 37
    • View Profile
Re: Newbie's firsttime with uTasker
« Reply #60 on: March 05, 2009, 01:32:16 AM »
Ok here's a update on all the code I have so far.
It appears to send data but once it gets to the 2nd time around it gives a exception error in vb.net

Code: [Select]
#include "config.h"
#include "IKSClient.h"

#define OWN_TASK TASK_IKS_CLIENT

#define INITIALISATION       0
#define ACTIVE               1

// TCP Settings
int connected = 0;
int busy = 0;
#define IKS_SERVER_PORT      8000
static USOCKET iks_client_socket;
static unsigned char iks_server_ip[IPV4_LENGTH] = {192, 168, 1, 69};
#define MAX_DATA_LEN 100
typedef struct stTCP_MESSAGE
{
    TCP_HEADER     tTCP_Header;                    // reserve header space
    unsigned char  ucTCP_Message[MAX_DATA_LEN];    // data payload space
} TCP_MESSAGE;
static TCP_MESSAGE IKSData;

// Serial Port Settings
int iSerialRxLenth = 0;
static unsigned char ucSerialInput[RX_BUFFER_SIZE];
QUEUE_HANDLE SerialPortID = 0;

static int fnIKSListener(USOCKET Socket, unsigned char ucEvent, unsigned char *ucIp_Data, unsigned short usPortLen)
{
    switch (ucEvent) {
case TCP_EVENT_CONNECTED:
connected = 1;
memcpy(IKSData.ucTCP_Message,ucSerialInput,iSerialRxLenth);
if(fnSendTCP(iks_client_socket, (unsigned char *)&IKSData.tTCP_Header, iSerialRxLenth, TCP_FLAG_PUSH) > 0)
return APP_SENT_DATA;
break;
    case TCP_EVENT_ARP_RESOLUTION_FAILED:
        break;
case TCP_EVENT_REGENERATE:
memcpy(IKSData.ucTCP_Message,ucSerialInput,iSerialRxLenth);
if(fnSendTCP(iks_client_socket, (unsigned char *)&IKSData.tTCP_Header, iSerialRxLenth, TCP_FLAG_PUSH) > 0)
return APP_SENT_DATA;
break;
    case TCP_EVENT_DATA:
busy = 0;
        break;
    case TCP_EVENT_CLOSE:
    case TCP_EVENT_CLOSED:
connected = 0;
        break;
case TCP_EVENT_ACK:
connected = 1;
uTaskerStateChange(OWN_TASK, UTASKER_ACTIVATE);
break;
    case TCP_EVENT_ABORT:
fnTCP_Connect(iks_client_socket, iks_server_ip, IKS_SERVER_PORT, 0, 0);
        break;
    }
    return APP_ACCEPT;
}

static int fnReadIrd(unsigned char * buf)
{
    static int iRxReceived = 0;                                          // the number of byte received (until now)
    static int iExpectedbytes = 0;
    unsigned char ucInputMessage;                                        // reserve space for receiving messages

    while (fnRead(SerialPortID, &ucInputMessage, 1) != 0) {              // read each presently available input byte
if (iRxReceived == 0) {                                            // searching for sync byte
          if (ucInputMessage != 0x21) {
              continue;                                                  // still not found sync byte
          }
          iRxReceived = 1;                                               // synchronised
          buf[0] = ucInputMessage;
      }
      else {
          if (iRxReceived >= RX_BUFFER_SIZE) {                           // protect buffer overrun on invalid frames
              iRxReceived = iExpectedbytes = 0;                          // go back to sync hunt mode
              continue;
          }
          buf[iRxReceived++] = ucInputMessage;                           // collect message content
          if (iRxReceived == 3) {                                        // the expected length is now known
              iExpectedbytes = (ucInputMessage + 4);                     // note the expected length
          }
          if (iRxReceived == iExpectedbytes) {                           // the complete message has now been collected
              return iExpectedbytes;                                     // inform of the frame length so that it can be processed
          }
      }

    }
    return -1;                                                           // frame not yet ready
}

// This task is started once to initialise the interface and then for each received character
//
extern void fnIKSClient(TTASKTABLE *ptrTaskTable)
{
    QUEUE_HANDLE        PortIDInternal = ptrTaskTable->TaskID;           // queue ID for task input

    if (!SerialPortID) {                                                 // configure interfaces on initialisation
        SerialPortID = fnSetNewSerialMode(FOR_I_O);
iks_client_socket = fnGetTCP_Socket(TOS_MINIMISE_DELAY, TCP_DEFAULT_TIMEOUT, fnIKSListener);
    }

    if (connected >= 2) {  // TCP transmission is busy so wait - queue all UART rx data in UART buffer in the meantime
        return;
    }

    while ((iSerialRxLenth = fnReadIrd(ucSerialInput)) != -1) {             // collect the data until ready
memcpy(IKSData.ucTCP_Message,ucSerialInput,iSerialRxLenth);

if(!connected){
fnTCP_Connect(iks_client_socket, iks_server_ip, IKS_SERVER_PORT, 0, 0);
connected = 2;
} else {
fnSendTCP(iks_client_socket, (unsigned char *)&IKSData.tTCP_Header, iSerialRxLenth, TCP_FLAG_PUSH);
connected = 3;
}
break;
}
    // else quit - we return on further input
}



// After changes, we set up the new serial configuration
// (moved from application.c to here) - in application.s #undef SERIAL_INTERFACE added to remove its control of the serial interface
extern QUEUE_HANDLE fnSetNewSerialMode(unsigned char ucDriverMode)
{
    TTYTABLE tInterfaceParameters;                                       // table for passing information to driver
    tInterfaceParameters.Channel = DEMO_UART;                            // set UART channel for serial use
    tInterfaceParameters.ucSpeed = temp_pars->temp_parameters.ucSerialSpeed; // baud rate
    tInterfaceParameters.Rx_tx_sizes.RxQueueSize = RX_BUFFER_SIZE;       // input buffer size
    tInterfaceParameters.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE;       // output buffer size
    tInterfaceParameters.Task_to_wake = OWN_TASK;                        // wake self when messages have been received
    #ifdef SUPPORT_FLOW_HIGH_LOW
    tInterfaceParameters.ucFlowHighWater = temp_pars->temp_parameters.ucFlowHigh;// set the flow control high and low water levels in %
    tInterfaceParameters.ucFlowLowWater = temp_pars->temp_parameters.ucFlowLow;
    #endif
    tInterfaceParameters.usConfig = temp_pars->temp_parameters.usSerialMode;
    #ifdef SERIAL_SUPPORT_DMA
    tInterfaceParameters.ucDMAConfig = UART_TX_DMA;                      // activate DMA on transmission
    #endif
    if ((SerialPortID = fnOpen( TYPE_TTY, ucDriverMode, &tInterfaceParameters )) != 0) { // open or change the channel with defined configurations (initially inactive)
       fnDriver( SerialPortID, ( TX_ON | RX_ON ), 0 );                  // enable rx and tx
    }
    return SerialPortID;
}

BTW I appreciate all the time and effort your putting into this for me and others.
Thanks!!!
« Last Edit: March 05, 2009, 02:04:33 AM by echel0n »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Newbie's firsttime with uTasker
« Reply #61 on: March 05, 2009, 02:49:36 AM »
Hi

I see a few more things.

1) There is no need to do a memcpy(IKSData.ucTCP_Message,ucSerialInput,iSerialRxLenth); in the listener. The data is already in the IKSData.ucTCP_Message.

2) In the project we use uMemcpy() rather than memcpy(). uMempy() allows better debugging in the simulator (you can't step into memcpy() to check pointer values). Also it can (depending on processor type used) be accelerated by using DMA.

3) I don't know the length of the messages you are receiving but I think that the crash will be due to a buffer overflow. I think that
iRxReceived = iExpectedbytes = 0;                          // go back to sync hunt mode
must also be performed when the message has been completely received, as well as
              return iExpectedbytes;                                     // inform of the frame length so that it can be processed
otherwise following characters are not put to the start of the buffer - and also the sync hunting doesn't re-start. I don't actually see the crash reason but this should be much easier to find in the simulator than on the target since the simulator has very powerful debugging support (actually VS and not the simulator itself).

When you get an exception you should see lots of information - which line it is at, variable contents etc., which should help solve any such (quite normal software development issues...) quite easily.

Final note:
In fact you can save the ucSerialInput[] buffer in the code since you also have the static TCP_MESSAGE IKSData; Since no more UART rx data is being put into it during tcp transmission (until ACK confirmation) the next time you actually read UART data in, the IKSData.ucTCP_Message is free. This means that you can in fact read UART data directly into IKSData.ucTCP_Message. This saves a buffer and also a uMemcpy(), resulting in even more efficiency of memory and speed.

Good luck.

Regards

Mark

Offline echel0n

  • Newbie
  • *
  • Posts: 37
    • View Profile
Re: Newbie's firsttime with uTasker
« Reply #62 on: March 05, 2009, 03:18:01 AM »
Ok i'm now able to send and receive the data and send it out of my uart but I notice that it's all running rather slow like it doesn't try and get the next request from the uart after I send my response I got from ethernet out via the uart.

Anyway to rectify this to go quicker ?

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Newbie's firsttime with uTasker
« Reply #63 on: March 05, 2009, 03:40:56 AM »
Hi

You will need to look at the TCP flow (using WireShark) and also the pause periods on the UART (oscilloscope) to see what is really going on.

Here are a couple of notes:

1) When sending TCP data to a PC you will generally not get an ACK for about 150ms. This is due to the PC's TCP/IP stack performing Delayed- Ack operation. See more details here: http://www.utasker.com/forum/index.php?topic=396.0
To overcome this, either the PC program must disable Delayed- Ack operation or else it needs to be overcome by performing TCP windowing. This is automatically done when using a buffered TCP socket but is not that with a simple TCP socket (best use a buffered socket if this is what you are seeing and TCP speed in the PC direction is to be maximised.

2) When testing with the simulator, the throughput may be a little slower due to its polling operation. To see whether this is the case, try reducing the TICK to 20 or even 10ms. I don't expect that this will be the problem but when sending fast data that needs fast reaction it can help a bit. Also check the performance on the target to see whether there is a difference here or not.

In config.h

#ifdef _WINDOWS
    #define TICK_RESOLUTION      20  // increase tick rate to speed up simulator reaction time
#else
    #define TICK_RESOLUTION      50 // no need to speed up on teh target since it is purely interrupt driven
#endif


Beware that going below about 10ms on XP or Vista PC will cause it to start going slower again due to the increasing TICK overhead for Windows...!!


3) I didn't understand exactly in which path the delay is but you should find that the reaction time between the ACK being received and the task reading its UART input again (on the target) is only a few us. In the simulator it may be up to the TICK interval value. You also didn't quantify what you mean by slow. Is this in the us, ms or seconds range? I wouldn't expect the simulator delay to be that noticeable. The Ethernet part of the simulator is a bit different and doesn't poll. Its though-put is usually a bit higher than on the target since the PCs processor and its support hardware is rather fast in comparison.

Regards

Mark


Offline echel0n

  • Newbie
  • *
  • Posts: 37
    • View Profile
Re: Newbie's firsttime with uTasker
« Reply #64 on: March 05, 2009, 04:23:05 AM »
Ok let me explain my self a little better on whats really slow.

I can send the data to the server and get a response back right away it's the time after that I wait for it to process the next request from the uart thats slow.
See the device that is sending requests to my ARM7 device responds right away but if not answered right away it'll timeout so what needs to happen is after the response comes back from the server and gets sent out via the uart to my other device the task needs to restart and get data from the uart again right away.
« Last Edit: March 05, 2009, 04:29:50 AM by echel0n »

Offline echel0n

  • Newbie
  • *
  • Posts: 37
    • View Profile
Re: Newbie's firsttime with uTasker
« Reply #65 on: March 05, 2009, 05:19:54 AM »
Ok i've changed the following code and things seemed to have sped up a bit but it's like it comes in bursts but just isn't a steady enough speed to keep communication with my device going.

Code: [Select]
static int fnReadIrd(unsigned char * buf)
{
    static int iRxReceived = 0;                                          // the number of byte received (until now)
    static int iExpectedbytes = 0;
    unsigned char ucInputMessage;                                        // reserve space for receiving messages

iRxReceived = iExpectedbytes = 0;
    while (fnRead(SerialPortID, &ucInputMessage, 1) != 0) {              // read each presently available input byte
if (iRxReceived == 0) {                                            // searching for sync byte
          if (ucInputMessage != 0x21) {
              continue;                                                  // still not found sync byte
          }
          iRxReceived = 1;                                               // synchronised
          buf[0] = ucInputMessage;
      }
      else {
          if (iRxReceived >= RX_BUFFER_SIZE) {                           // protect buffer overrun on invalid frames
              iRxReceived = iExpectedbytes = 0;                          // go back to sync hunt mode
              continue;
          }
          buf[iRxReceived++] = ucInputMessage;                           // collect message content
          if (iRxReceived == 3) {                                        // the expected length is now known
              iExpectedbytes = (ucInputMessage + 4);                     // note the expected length
          }
          if (iRxReceived == iExpectedbytes) {                           // the complete message has now been collected
              return iExpectedbytes;                                     // inform of the frame length so that it can be processed
          }
      }

    }
    return -1;                                                           // frame not yet ready
}

Not sure if I placed the iRxReceived = iExpectedbytes = 0; in the correct place but it seems to work better now.

Now I'm not sure if buffered TCP would work since the device needs to make a request and then get a response before it can make another request or it'll just timeout and go back to the very first request it made.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Newbie's firsttime with uTasker
« Reply #66 on: March 05, 2009, 01:09:52 PM »
Hi

I don't think the reset of iRxReceived and iExpectedbytes is in a good place. It will trash any UART messages not received in a single block.
Try the following position.

          if (iRxReceived == iExpectedbytes) {                    // the complete message has now been collected
              int iRtn = iExpectedbytes;
              iRxReceived = iExpectedbytes = 0;                   // reset counter and start searching for next frame synch
              return iRtn ;                                                      // inform of the frame length so that it can be processed
          }


I expect that (from your explanation) the UART reception is missing messages (due to the fact that the buffer counters are not being handled correctly). Then there is a timeout (and I assume repeat from the device or PC sending to the UART) which is then synchronised to. Probably the repetitions are seen as delays.

You didn't say whether you are presently working with the simulator only, the target only or both.
As explained before the simulator may have slight delays in the order or 10ms but the target should only have delays in the order of us. I do work a lot with such protocols (eg. MODBUS running on multiple UARTs and multiple TCP sessions) using both simulator and target. There is a slight difference in maximum speed but it is still fast. Any sluggishness will almost certainly be due to the code so this must be analysed and corrected where necessary.

Regards

Mark