Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - mark

Pages: 1 ... 213 214 [215] 216 217 218
3211
µTasker general / Re: Using TCP in the uTasker project
« on: July 23, 2007, 02:17:13 PM »
Hi Neil

Take a look at the first example. It uses:

if (fnSendTCP(Socket, (unsigned char *)&test_message->tTCP_Header, 4, TCP_FLAG_PUSH) > 0)

when sending.

Note that the buffer should also supply space for the TCP layer to add its header. This is so that TCP doesnt have to copy data contents to merge it with its header and is a rather specific solution - however once you have the buffer set up accordingly it should be easy to use.

Your copy is effectively giving  a pointer to your test message which TCP will overwrite with the header and it will then send 5 extra bytes beyond the header length, which will be a bit random since this is beyond the end of your buffer.

If you use a structure as in the example and build your test message up in the data part of the buffer it should then send the content that you are expecting.

Good luck

Regards

Mark

3212
ATMELTM AT91SAM7X and AVR32 / Re: porting uTasker to the winarmgcc
« on: July 22, 2007, 10:57:31 AM »
Hi Emerson

When you set the variable to zero you are 'correcting' the error in one place but then it will also have further problems afterwards. This does however seem to confirm the fact that the BSS variables are really not getting set to zero.

Therefore the only solution is to solve the problem there. Here is the code which performs the initialisation. Check that it is really being called, that the values are correct (check that the addresses which are taken from the linker script are from the correct linker script). The same is valid for the initialised variables since these may well  have the same problem.

1. In sam7x.c, the routine AT91F_LowLevelInit() is called from the start up assembler file.
2. __init_gnu_data(); is called to perform variable initialisation. Note that it is conditional on the define _GNU. Make sure that your make file is defining this (-D _GNU)
3. This code copies the variables. You need to study this and try to work out why it is not setting the values of all variables in the BSS section to 0 and possibly why it is not copying initialised variables from FLASH to RAM.

Code: [Select]
extern unsigned char __data_start__, __data_end__;
extern const unsigned char __data_load_start__;
extern unsigned char __text_start__, __text_end__;
extern const unsigned char __text_load_start__;
extern unsigned char __bss_start__, __bss_end__;

extern void __init_gnu_data(void)
{
    unsigned char *ptrData = &__data_start__;
    const unsigned char *ptrFlash = &__data_load_start__;
    unsigned long ulInitDataLength = (&__data_end__ - &__data_start__);
    while (ulInitDataLength--) {                                         // initialise data
        *ptrData++ = *ptrFlash++;
    }

    ptrData = &__text_start__;
    ptrFlash = &__text_load_start__;
    ulInitDataLength = (&__text_end__ - &__text_start__);
    while (ulInitDataLength--) {                                         // initialise text
        *ptrData++ = *ptrFlash++;
    }

    ptrData = &__bss_start__;
    ulInitDataLength = (&__bss_end__ - &__bss_start__);
    while (ulInitDataLength--) {                                         // initialise bss
        *ptrData++ = 0;
    }
}

Only once you have solved this will it be possible to continue.

Good luck

Regrads

Mark

3213
µTasker general / Re: Boot Loader
« on: July 21, 2007, 08:12:17 PM »
Neil

By setting the define SPI_FILE_SYSTEM in config.h rather than FLASH_FILE_SYSTEM (either one or the other) the file system and parameter system are located in external SPI EEPROM. See the document http://www.utasker.com/docs/uTasker/uTaskerSPI_EEPROM.pdf

The size of the EEPROM and other parameters are set up in app_hw_xxxx.h.

Presently the device supported is an EEPROM but it is controlled as if it were a FLASH device.
To add the larger FLASH SPI devices to the SPI_FILE_SYSTEM (as Dean has already done) just the driver interface needs to be changed. The size of the chip is not a problem since this just defines how many pages actually exist. A project can set this up for the specific type to be used. A possible configuration for a 1Meg device would be
Code: [Select]
    #define FILE_GRANULARITY (512)                                                // Page size
    #define SINGLE_FILE_SIZE (32*2*FILE_GRANULARITY)                    // each file a multiple of 32k
    #define FILE_SYSTEM_SIZE (32*SINGLE_FILE_SIZE)                       // 32 files (1Meg) reserved for file system (including parameter blocks)

If more than 1 FLASH device is used the driver would in addition need to know the size of each in order to set the correct CS line. Presently the code only supports one chip but this is of course only a detail as long as the second CS is physically available.

The QSPI is specific to the M5223X but until now I haven't found any advantage in using the CS lines dedicated to the QSPI for such control. It takes much more code to control them from the QSPI hardware than as GPIOs.

Since I have the 45DB041 code ready in my project (configurable for 021..161) I think that I can adapt the boot loader if you need it. Say from mid. August 2007. It is certainly possible to also share it with other things, the only complication is ensuring a generic solution. This would be a second step.

I have a question for you, since you know the 45DB081 well:

The SPI FLASH has page sizes of either 264 or 256 bytes. Default is 264. Therefore the part actually has 32k more that its 1Meg if used in 264 byte mode(?).
Once the device is set to 254 byte page size it can not be switched back.
254 byte page sizes are easier to work with (SW is more efficient since it can use power of 2 multiplication and divides when calculating addresses of pages etc.). How do you use it? I am still wondering on how best to set it up, although I still have 264 bytes pages at the moment. What strategy should I go for??

Regards

Mark

3214
µTasker general / Re: Boot Loader
« on: July 21, 2007, 06:47:02 PM »
Hi Neil

As you have noticed, the boot loader technique - due to its requirement for fail safe uploads - requires the old and new code to both be present in FLASH at the same time. This does require that the available FLASH can handle this or puts more of a limit on the maximum program size.

Often it is possible to use the existing file system to temporarily store the new code, however overwriting and files there. Afterwards the overwritten files can be re-loaded - via FTP for example. This can often optimise the amount of FLASH to enable what is required.

Of course there is always some limit and the next step will be to allow the new code to be stored in inexpensive off-chip FLASH. See the topic about the external EEPROM alternative: http://www.utasker.com/forum/index.php?topic=4.0
Presently I am implementing this for the Atmel part (512K) and Dean has already something running on the ST part (note that ST has two parts - one is a data flash and one is a program FLASH. Dean has used the data FLASH because it is well suited to a file system with fine FLASH granularity. If only software uploads are to be performed the program FLASH part would also be suitable).

In the application there are three choices:
1. Have the file system completely in external SPI FLASH (maximised code space and Dean has it working)
2. Have the file system in internel FLASH and a software upoad in external SPI FLASH (this is what my first project is doing).
3. Have files in both internal FLASH and external SPI (file location can be defined to be in either) but SW uploads will be external due to space. (this is a bit more complicated and needs still to be solved at the FS level).

1 and 2 are basically working and make most sense for SW uploads.

What then needs to be done is to add the new driver code to the "Bare-Minimum" boot software - it is not much more code since the driver is basically some extra SPI routines. I expect that it will still fit in 2k.

Therefore my conclusion is that it is an important addition to the present concept which will allow more SW size flexibility with only small HW cost increase (one-off price for the SPI FLASH is about $3 for my ATMEL 512K part and in quantity they are certainly good value).
If you need it, I think there is no problem to recon on it being available in the short term. If it is not ready when you need it, available code and support should allow you to integrate it with quite small effort.

Regards

Mark



3215
µTasker general / Re: Boot Loader
« on: July 21, 2007, 05:14:01 PM »
Hi Neil

1. The project includes all routines necessary to do updates in various ways. The demo project allows for example uploading new code using FTP or by using HTTP post. If you have a GPSR connection it is probably connected via UART and so a routine to store the new code received via UART to the same file can be added (there is not one in the present project but this is not difficult to add).

As long as the loaded file has the correct format and is at the correct location it will be compatible with the "Bare-Minimum" Boot loader and so how it is actually loaded (whether via EThernet or another interface) makes no real difference.

2. The "Bare-Minimum" Boot loader is presently supported by the M5223X and SAM7X projects. It occupies about 2k of memory. Get full detail from:
http://www.utasker.com/docs/uTasker/uTaskerBootLoader.PDF
http://www.utasker.com/docs/uTasker/BM-Booloader_for_SAM7X.PDF
http://www.utasker.com/docs/uTasker/BM-Booloader_for_M5223X.PDF

If a file upload is unsuccessful it doesn't affect the normal operation of the application and so can be repeated at a later time. The processor resets only once the upload is complete (although exactly how it responds can be defined by the application).

After a reset, the procedure ensures that a power loss can not cause the device to be left without either the original application or the new one intack. The only thing that could go wrong is when the user actually loads a new application which is non-operational. It is in the user's responsibility to ensure that only tested software is converted to the correct format and loaded to remote devices!!

Regards

Mark

3216
µTasker general / Re: Using TCP in the uTasker project
« on: July 21, 2007, 04:36:56 PM »
Neil

Code: [Select]
fnTCP_Connect(Test_socket, "192.168.0.184", 10000, 0, 0); //my server address and port...
The first problem that I see is in the use of the IP address.
The uTasker project doesn't store IP addresses as strings but rather as arrays.

Therefore you need to spefify your IP address like this :

Code: [Select]
unsigned char ucMyIp[IPV4_LENGTH] = {192,168,0,198};
fnTCP_Connect(Test_socket, ucMyIp, 10000, 0, 0); //my server address and port...

This may then work.
What the previous version probably did was send the connection request to 31.39.32.31 which would then be directed to your default gateway and sent out onto the internet.
If you are receiving TCP_EVENT_ARP_RESOLUTION_FAILED (this will occur after about 4..5 seconds) it would imply that you don't have a local gateway.

Note that you can also activate "USE_TIME_SERVER" in config.h to see how it program operates. It is a client example and there are a number of timer servers which it attempts to contact until one if successful. The time server will send one message (with the time - surprise surprise) and close the connection.

On thing to note is a difference here between when working with the simulator and working on the target. When the client tries to connect in the initialisation of application.c the simulator can send immediately. On the target it generally takes a few seconds for the Ethernet link to become ready and so it takes a little longer before it all works.

Another point to note is that a client connection attempt often causes an ARP resolve to be initialted. This is because the address of the destination is not yet in the local ARP table. A server will invariably have the IP address already in the table since it was refreshed there as it received the connection attempt (SYN) from the remote client. For the user this is in fact totally transparent since TCP handles it itself when connecting. It is however possible that during an active connection the ARP entry times out (due to non activity or a network with high activity causing it to be flushed). In this case the ARP resolve will be automatically started but the listener will need to be able to resend the last message via the TCP_EVENT_REGENERATE.

fnSendTCP() will return the number of bytes transmitted. If it has to start an ARP resolution it will however return NO_ARP_ENTRY. In this case the user can also prepare for the regeneration event which is expected. Should instead TCP_EVENT_ARP_RESOLUTION_FAILED be received, it means that the connection partner is no longer reachable - it has maybe turned off in the meantime and so the connection could be terminated.

Regards

Mark





3217
µTasker general / Re: Using TCP in the uTasker project
« on: July 21, 2007, 04:31:35 PM »
Neil

Quote
Does this mean its not possible to have 2 or more clients connecting to a server?

What I meant was that it is no two clients from the same IP address may have the same port number when connected to the same server port number. This is also the same restriction for the clients at the other end of the connection when we are acting as server.
So there is no problem with having multiple clients connected to a server.

I should be more precise. This is not an implementation restriction but a simple TCP connection rule:
A TCP connection is determined by two parameters; IP addresses at the two ends and Port numbers at the two ends.
For example Device A is at 192.168.0.3 and device B is at 192.168.0.4 in a local network
Device A and B have servers running on Port 80 (HTTP port).

Now Device A and Device B both have clients which connect to the server.
Let's say there are 2 connections from each. The clients will use a 'random' port number when connecting for the first (the uTasker uses a dynamic port range between 49152 and 65535) and each subsequent connection then uses the next port number.

Therefore the following 4 connection may exist, which are defined by the unique connection pairs (IP and Port):
Connection 1 (Client at A connected to server at B)
    192.168.0.3:50672 <-> 192.168.0.4:80
Connection 2 (Client at A connected to server at B)
    192.168.0.3:50673 <-> 192.168.0.4:80
Connection 3 (Client at B connected to server at A)
    192.168.0.3:80 <-> 192.168.0.4:52819
Connection 4 (Client at B connected to server at A)
    192.168.0.3:80 <-> 192.168.0.4:52820

As you can see. The server uses the same port but there is always a different client port number. Therefore each TCP connection is unique since the port pairs are never the same.

Regards

Mark


3218
µTasker general / Re: Using TCP in the uTasker project
« on: July 21, 2007, 01:21:44 PM »
Hi Neil

The framework of the call back is basically the same in every use. In some cases unused cases can be grouped to a default handling, although the compiler probably optimises to this any way. Data can be either handled in the TCP_EVENT_DATA case directly or else call further subroutines for readability.
Since the data is passed via pointer to the callback (it is still in the LAN input buffer) it should either be fully processed or copied to a permenent buffer if the processing were to be delayed for later. As soon as the call back returns the LAN input buffer will be unblocked so that the LAN controller can re-use it.
Note also that handling the data in another task has no real benefits since it is already being handled in the Ethernet task and so is not blocking interrupts. The LAN Rx interrupt simply schedules the LAN task which is doing the work 'off-line'. It has checked IP and determined that it is a valid TCP frame and the TCP module is a subroutine to the Ethernet task. TCP does have its own task but this is only used for monitoring connection timers and retransmissions in case of timeouts or ARP resolution. The TCP task doesn't handle rx data.


If you set fnGetTCP_Socket(TOS_MINIMISE_DELAY, 130, fnTestListener) the socket will have an idle time out of 130s and so will do what you require. As soon as your 'Keep-Alive' message stops retriggering the connection it will timeout and close.
The range of the idle timer is 1...0xfffe (1s to 65534s). 0 should not be used and 0xffff means NO IDLE TIMEOUT or infinite.

A client doesn't need to listen and so after actively starting a connection the rest is basically the same, so your assumption is correct. Also a listener can establish a client type connection by actively establishing it itself (when no connection already exists on the socket), so the only real difference is that it is not possible to establish a TCP connection with a client socket from a remote peer since there is no listener on the port.

Note that several listeners (servers) are possible on a single port (each needs a seperate socket) but only one client is possible. A client will generally get a "random" free port number for each connection - the function which does this is called:
extern unsigned short fnGetFreeTCP_Port(void);
and it is handled by TCP itself when a connection is to be established.

If you have multiple servers on the port they can share the call back by adding a loops as follows. This example if from the HTTP code where each HTTP socket has a structure which saves the socket index of each connection. Since the socket belonging to the TCP event is passed as a parameter it is then quite easy to search which session the connection belongs to.

Code: [Select]
static int fnHTTPListener(USOCKET Socket, unsigned char ucEvent, unsigned char *ucIp_Data, unsigned short usPortLen)
    HTTP *HTTP_session = ptrHTTP;
    int iSessionNumber;

    for (iSessionNumber = 0; iSessionNumber < NO_OF_HTTP_SESSIONS; iSessionNumber++) {
        if (HTTP_session->OwnerTCPSocket == Socket) {                    // search for the session to handle this event
            switch (ucEvent) {
            case TCP_EVENT_CONREQ:                                       // session requested
                return APP_ACCEPT;                                            // accept connection request
...etc.
            }
        }
        HTTP_session++;
    }
    return APP_REJECT;                                                        // owner socket not found!
}


Regards

Mark

3219
µTasker general / Re: Using TCP in the uTasker project
« on: July 20, 2007, 11:22:34 PM »
Hi

Here is some general information about TCP use in the uTasker project. It is an overview rather than a tutorial and is possibly a little vague in some respects. I hope that it doesn't confuse more that it helps, but it may well contain something of interest so here it is:



Here are the main user calls for working with TCP (see tcpip.h). You will find that the uTasker project is not based on Berkley conventions – it was designed as an alternative solution in small footprint projects where a mix between performance, reliability, simplicity and user comfort was defined, based on typical embedded project use. Therefore it doesn’t not try to copy any existing solution but goes its own way.


extern USOCKET fnTCP_Listen(USOCKET TCP_socket, unsigned short usPort, unsigned short usMaxWindow);

extern unsigned short fnGetFreeTCP_Port(void);

extern USOCKET fnGetTCP_Socket(unsigned char ucTos, unsigned short usIdleTimeout, int (*listener)(USOCKET, unsigned char, unsigned char *, unsigned short) );

extern USOCKET fnReleaseTCP_Socket(USOCKET TCPSocket);

extern USOCKET fnTCP_Connect(USOCKET TCP_socket, unsigned char *RemoteIP, unsigned short usRemotePort, unsigned short usOurPort, unsigned short usMaxWindow );

extern USOCKET fnTCP_close(USOCKET TCP_Socket);

extern signed short fnSendTCP(USOCKET TCP_socket, unsigned char *ptrBuf, unsigned short usDataLen, unsigned char ucTempFlags);

extern QUEUE_TRANSFER fnSendBufTCP(USOCKET TCP_socket, unsigned char *ptrBuf, unsigned short usDataLen, unsigned char ucCommand);

extern void fnModifyTCPWindow(USOCKET Socket, unsigned short usSafetyWindow);

extern void fnReportWindow(USOCKET Socket, unsigned short usBufferSpace);

 

The TCP task handles ARP so ARP is fully transparent to the user. However there are three types of TCP sockets which can be used.

The first is a RAW socket where the user supplied call back handles all events (see for example the http call back) which means that also repetitions must be handled there.

The second is a buffered socket. TELNET is an example of a protocol which makes use of this. The TCP socket has an inbuild data buffer for backing up data. It can send data of 'random' nature  rather than 'regeneratable' data at higher rates because it uses windowing and the buffered for retransmissions if necessary, as well as grouping single data transissions into larger transmission packets.

The third is a TELNET like socket where a TELNET socket is used instead of a TCP buffered socket – the TELNET socket can be in RAW mode so that it is otherwise transparent and doesn’t do negotiation or byte stuffing etc. The advantage of the TELNET like socket is that the TELNET layer provides an intermediate handler which handles repetitions and also TCP windowing so that high through put can be easily achieved. The down side is that it requires some buffer space (it works with fnSendBufTCP() rather than fnSendTCP()) to allow back ups of transmitted frames where the user simply writes to the socket as if it were any data port like a serial interface – the TELNET layer gets rid of the buffered data in the most efficient manor possible and ensures reliable delivery. There is an example of this in the demo project in debug.c (Telnet_socket and fnTELNETListener). The advantage to a application using a TELNET like socket rather than directly a buffered TCP socket is that the TELNET layer handles all detail - the application interface profits from the intermediate TELNET layer to do the "dirty work".

 

These are the TELNET specific routines:

extern USOCKET fnStartTelnet(unsigned short usTelnetPortNumber, unsigned short usIdleTimeout, unsigned short usMaxWindow, UTASK_TASK wakeOnAck, int (*listener)(USOCKET, unsigned char, unsigned char *, unsigned short) );

extern void fnStopTelnet(USOCKET TelnetSocket);

extern int  fnTelnet(USOCKET Telnet_socket, int iCommand);

extern int  fnCheckTelnetBinaryTx(USOCKET Socket);



The sockets in the uTasker project are always 'non-blocking' sockets (it is not possible to really compare them with sockets used with Windows etc.). Reception frames result in call back events and transmitted frames are either successful (an ACK call back event is received at some time in the future) or fail (a REGENERATE call back event is received at some time in the future – note that the REGENERATE event also results when a frame couldn’t be sent until ARP was resolved). These events will be handled by a TELNET layer if a TELNET like socket is used or else it is up to the application behind the TCP socket to handle them. Again the way this is performed is easy to see in the various protocols. If something is not clear, simply run the demo project in the simulator and set a break point in any code which is of interest – the code will break when it is used and the rest is usually self-explanatory.




I expect that various points here will be elaborated in further posts!

Regards

Mark



3220
µTasker general / Using TCP in the uTasker project
« on: July 20, 2007, 10:18:51 PM »
Hi All

The uTasker demo project uses TCP for several services. These include HTTP, SMTP, FTP, TIME SERVER and TELNET, to name the ones which initially spring to mind.

The demo project enables these services to be easily studied and own services to be written (usually termed clients and servers) based on these example. There is, at the time of writing, no 'official' document which contains a definitive guide.

This is logically the reason why the use of TCP is a frequent question and frequent discussion topic in private mails. It is also a reason why this document, which is long overdue, should soon be made available.

Therefore this thread is designed to be an introduction to the subject to answer the first burning questions and to give first practical examples, as well as more detailed insight into how it works, how it can be used and why it all works like that. If all goes well, the thread comntent can be moved to a more structured document at a later point in time.

TCP is in fact a very simple protocol - in its simpest form. But in order to allow it to perform with the speed and reliability which has enabled it to become originally the standard in the Internet and eventually the standard in almost all networks it does need a few additional frills which can then make it quite complicated indeed.

If you would like to discuss standard TCP details please feel free to create your own topic to get a discussion going. I have always found it very difficult to find any really meaningful discussions about the practical aspects in the Internet so it would be nice to be able to find some good ones here!


A simple TCP server example. (The HTTP service is a good source for reference).

First we get a socket from the TCP socket pool. The size of the socket pool is defined in config.h, where the define USER_TCP_SOCKETS can be incremented for every additional socket which user code (as opposed to standard services like HTTP) will need.
The following configures a socket with the defined characteristic (minimum delay as opposed to maximum throughput or maximum reliability - these are router parameters), a timeout of 10 seconds (after this length of time with no activity it will close the connection. A value 0xffff means no timeout!), and a callback routine called fnTestListener() which will be doing the work later.

Code: [Select]
static USOCKET Test_socket = -1;                                          // declare a static socket variable
...
    Test_socket = fnGetTCP_Socket(TOS_MINIMISE_DELAY, (unsigned short)10, fnTestListener); // from task or sub-routine code

The socket is not in the listening state (which is needed for it to act as a server) so we start it in this state by calling
Code: [Select]
static unsigned short usTestPort = 0x9999;                               // declare a static socket variable (the value could also be fixed)
....
    fnTCP_Listen(test_socket, usTestPort, 0);                             // after getting the socket, bind it to a listening port

Now the socket is listening on port 0x9999, which means if you have a test client (eg. Telnet on this port) send a connection request to it it will start a connection process.
Note that the parameter 0 when setting the listening state is the maximum windows size which the connection can receive - a zero defaults to the standard LAN TCP pay load size of 1460 bytes. For some applications with special buffer restrictions this can be used to improve flow control in the rx sense (CONTROL_WINDOW_SIZE needs to be enabled in config.h) but this won't be described here just yet.

The simple server listener looks something like this.

Code: [Select]
#define TEST_BUFFER_LENGTH 10
typedef struct stTCP_MESSAGE
{
    TCP_HEADER     tTCP_Header;     // reserve header space
    unsigned char   ucTCP_Message[TEST_BUFFER_LENGTH];
} TCP_MESSAGE;

static int fnTestListener(USOCKET Socket, unsigned char ucEvent, unsigned char *ucIp_Data, unsigned short usPortLen) {
   TCP_MESSAGE test_message;

    switch (ucEvent) {
    case TCP_EVENT_CONREQ:                                             
    case TCP_EVENT_CONNECTED:
    case TCP_EVENT_CLOSE:
    case TCP_EVENT_ACK:
    case TCP_EVENT_ARP_RESOLUTION_FAILED:
    case TCP_EVENT_PARTIAL_ACK:
        break;
    case TCP_EVENT_REGENERATE:
    case TCP_EVENT_DATA:
        if ((ucEvent == TCP_EVENT_REGENERATE) || (!uMemcmp((CHAR*)ucIp_Data, "TEST" , 4))) {
            uStrcpy((CHAR*)test_message.ucTCP_Message, "Hi!!");
            if (fnSendTCP(Socket, (unsigned char *)&test_message.tTCP_Header, 4, TCP_FLAG_PUSH) > 0) {
                return APP_SENT_DATA;
            }
        }
        break;
    case TCP_EVENT_ABORT:
    case TCP_EVENT_CLOSED:
        fnTCP_Listen(Socket, ++usTestPort, 0);                    // go back to listening state on next port number
        break;
    }
    return APP_ACCEPT;
}

As you can see it receives events from the TCP layer, some with other details such as a pointer to data.

This is a list of the events which can arrive:

  • TCP_EVENT_ABORT               TCP connection was closed (due to error or a reset from peer)
  • TCP_EVENT_CONNECTED        TCP connection has been successfully established
  • TCP_EVENT_ACK                   Data which we sent have been successfully acknowledged (for all sent data, with outstanding acks)
  • TCP_EVENT_DATA                 Data frame received with data content for us to treat
  • TCP_EVENT_CLOSE                Peer is starting a close of the present TCP connection
  • TCP_EVENT_CLOSED              The TCP connection has been fully closed
  • TCP_EVENT_REGENERATE       The last data frame was lost and must be resent!!!
  • TCP_EVENT_CONREQ              A peer wants to establish a TCP connection (SYN received)
  • TCP_EVENT_ARP_RESOLUTION_FAILED  Generally only when working as client and sending a connection request or data after a longer period of no activity. It means that the the SYN or the data could not be sent by the IP layer since the address of the destination could not be resolved (destination powered down or network problem, or just doesn’t exist). In this cause the application is informed that the connection is either not possible of the connection has broken down due to this.
  • TCP_EVENT_PARTIAL_ACK       This is only used when Windowing is in operation. Presently only TELNET uses it. It means that an ACK has been received for a part of the data which has been sent (rather that all data that has been sent). This is used to acknowledge that only a part of the data has been successfully delivered rather than all outstanding data. This has to be treated differently to a normal ACK event since the ack number has to be used to calculate which outstanding data acks are still open and expect their own ack later.

Now if you are new to TCP, enter in the above test program - best in the simulator - and you can see your first simple TCP server in operation. It won't do a lot but it will at least do the following.

1. When the client requests a connection to port 0x9999 the event TCP_EVENT_CONREQ will be received. Here it would be possible to deny the connection to a black-listed IP for example but our server always allows connections.
2. The TCP connection will be established and the event TCP_EVENT_CONNECTED is received.
3. If the client sends any data it will arrive with the event TCP_EVENT_DATA. The server will only respond to the message "TEST" in which case it will send the string "Hi!!" as answer.
4. After 10s with no activity, the server will close the connection (it is actually TCP that does this after the idle timer fires but the server receives the event TCP_EVENT_CLOSED when the connection has successfully closed).
5. The lister socket is not active after the connection has been closed so the code sets it up as listener again, this time with port number 0x999a.
6. If the connection is repeated, the port number is always incremented each time and the connection always times out after 10s.

Note that when the server sends data it returns APP_SENT_DATA. This informs TCP that the application has just successfully sent something and TCP doesn't have to acknowledge the received data - the ack has already been piggy-backed with the transmitted data.

If the transmission were to fail and need repeating, the server has to handle the event TCP_EVENT_REGENERATE. Since we only ever send one message it is obviouse that this has failed and so it is simply resent. The event TCP_EVENT_ACK will be received when the transmitted message actually has arrived safely.
It is in fact a great shame that messages can and do get lost (but it is not a perfect world and so we have to be ready for it) because regeneration of previously sent messages is probably the most complicated and/or RAM consuming parts of TCP implementations. This example has it real easy, but this is also a real simple example!

Here is a list of all possible return codes from the listener.

  • APP_ACCEPT             This is normal return when no data has been sent. The TCP level will then acknowledge the received frame and the connection will continue
  • APP_SENT_DATA       The listener is informing TCP that it has sent data (be sure that data was really sent when returning this, it should not be returned if a transmission attempt failed)
    The TCP level will therefore not send an ACK of its own since the data will have had a piggy-back ack of its own. If there is a mistake and data is sent and APP_ACCEPT is returned it is not serious – there will simply be an unnecessary ACK sent which doesn’t actually hurt anything (just not so efficient)
  • APP_REJECT             This is used to reject a connection (for example if the IP address is on a black list…) It causes TCP level to return a RESET rather than perform the TCP connection sequence
  • APP_REQUEST_CLOSE    The application informs TCP that the application has just actively started the close of the present TCP connection.
    It is returned after the application calls fnTCP_close(socket); 
  • APP_REJECT_DATA       This is a special case where the application doesn’t want to accept data at the moment. It doesn’t cause the connection to be broken down but TCP will not ACK the data. The peer will then be forced to repeat the data – resulting in a delay (using the peer as a queue, possibly until data can be received).
  • APP_WAIT                Same as previous but delay on TCP connection establishment.

Our example has made use of very few features up to now and there is much more to be explained. However this should allow first steps to be taken and also the servers in the project (HTTP, FTP etc.) to already make a lot more sense.

I will continue the topic later with a first simple client example. If you already have confusions or questions, or corrections etc. please feel free to comment.

Regards

Mark

3221
NXPTM M522XX, KINETIS and i.MX RT / Re: FLASH blocks
« on: July 20, 2007, 09:21:48 PM »
First some facts about the FLASH in the M5223X.

The FLASH granularity is 2k (0x800). If you study the data sheet you will in fact find it very difficult to work this out - I believed that it was larger until really working with the chip!
The granularity (#define FLASH_GRANULARITY    (2*1024)  in m5223x.h) means that this is the smalled block or sector which can be individually erased.

The next thing to know is that it is always necessary to program a long word (32 bits) which must be on a long word boundary (0,4,8,0x0c, 0x10 etc) - this is in fact the &= ~3 which you have seen in the code.

The flash supports 'cumulative writes' which means that it is possible to program individual bits in a word from '1' to '0' (there may be some restrictions due to stresses in the chip when this is done but the technique has been very successful in the Coldfire - and its 'Super' FLASH) - comments welcome!

FLASH writes and deletes block the use of the entire FLASH in teh M5223X so the manipulation routines have to run from SRAM. Interrupts are blocked during the process.

The uTasker routines enable you to program any byte in FLASH once.
If you need to reprogram a byte in a sector (2k) to a value involving setting any bits from '0' to '1' the only possibility is to first delete the sector that it is in and then program everything back. This is called EEPROM emulation.

However the uTasker uses the FLASH normally as File System and Parameter System and in this use it is in fact never necessary to do EEPROM emulation. The parameter system generally uses a 'Swap block' and so changes are made in a second sector. Once complete, the old swap block is deleted and the new used as valid one (this is mostly invisible to the user). The main reason for this and not using EEPROM emulation is quite simple - what happens when you get a reset or power down while you are copying the data (you have copied the original block to RAM, you have changed the bytes you wanted and you are deleting the FLASH section to get ready for copying back. Then the power is pulled. Ooops - all gone and hopefully your device is not on board the next Mars mission and just updating some critical parameters to allow it to find its way back to its docking station...)?

The file system fits files (at least on chips with small granularity) in to the number of sectors needed (no two files ever share a single sector). When a new file is copied the algorithm knows which sectors must be deleted to remove any files which may be in the way (bull dozer method as described in the uFileSystem documentation).

It is of course possible to use the low level calls:
extern int  fnEraseFlashSector(unsigned char *ptrSector);
extern int  fnWriteBytesFlash(unsigned char *ucDestination, unsigned char *ucData, MAX_FILE_LENGTH Length);


but generally you find that you will be rewriting something that resembles either the parameter system routines (to avoid chance of data loss) or the file system, so it is best to be sure than the higher level calls really don't do what you want.

These calls are also processor independent (each processor supported by the uTasker will support them) but there are some processor-specific rules which have to be respected - the processor specific rules are also handled in the higher level routines for the parameter system and file system. For example you obviously need to know the size of the sector to use fnEraseFlashSector() - 2k on the M5223x, 512 byte on the NE64, 256 bytes on the SAM7X, 64K!! on the STR91XF (or 8k in bank 1) and I am not sure on the LPC23XX but it is also quiete big and has different values in different banks.
The M5223X supports cumulative writes - the low level routines should handle details about long word alignment (I think). The NE64, for example, doesn't support cumulative writes and always short words (16 bit) have to be written.

The FLASH is accurately simulated in the uTasker simulator so it is always much simpler to test the use of new FLASH manipulating code in the simulator first. It is also designed to throw an exception if you were to do things which the FLASH can't do to save strange behaviour later on the target, where debugging can be rather tedious..

Regards

Mark

3222
µTasker general / Re: MAC address
« on: July 20, 2007, 08:21:58 PM »
Hi Trevor

There are a few chips which are supplied with a predefined unique MAC address. These MACs belong to the chip manufacturer and you pay a small fee (included in the chip price) for them. But this is very much the exception and, although I did look at one a while back, I can't think of one to reference at this moment.

I have copied a small extract below about the MAC (from the uTasker tutorial) which is a quick overview about the 'rules' and how people can use them for hobby projects without having to purchase anything.

The way that it works in the uTasker project is that the MAC is set to all zeros by default and the web page allows it to be changed once! This is because it is generally necessary to set a unique MAC address for each piece of equipment and then not generally allow it to be changed (since the value needs to be managed by the owner of a block of MAC addresses which has been bought from IEEE). The value with all zeros is easily recognisable as a device which has not have its production MAC address set yet. It works in a network so it allows setting the 'real' MAC via Ethernet. One possible exception is when people set the device up to obtain an IP from a DHCP server because some DHCP servers don't like MAC 0:0:0:0:0:0 and won't give an IP address to it. This is probably not defined anywhere because others have no problem with assigning an IP address to MAC 0 - it seems however to be about 50:50 since it is often a question I get as to why DHCP is not working!

All of the chips supported by the uTasker project have no pre-defined MAC address so they have to be loaded during initialisation (the MAC is passed as a parameter when the Ethernet interface is opened).
The AT91SAM7X can have up to 3 MAC addresses programmed at the same time! This can sometimes be interesting. For example I use it in a project with TCP/IP as maintenance, control and software up-load protocol so that it can operate in an office environment. At the same time a second unrelated Ethernet based protocol runs communicating on a different MAC address. This is practial because the second protocol doesn't need any IP infrastructure or settings. It is proprietory (actually the uNetwork protocol which is a part of the uTasker project - see uNetwork.c) and so can run without needing ARP and is optimised for fast resonse times. A device with only one MAC address needs to share it between this and IP, which can have some disadvantages.
The STR91XF - also supported by the uTasker - has a one-time programmable section of FLASH (about 20 bytes). These can be programmed once (and never deleted or changed - ever again) and the last 6 bytes are defined to be the MAC address of the device. They are even loaded automatically at reset from these addresses to the MAC controller register. But only when the user has set them with the MAC address which it will then always have.

You are also correct that it is not a good idea to have more than 1 device on the network with the same MAC address (they should always be set up to at least be different). Very strange things can happen when this is not respected and sometimes it takes quite a long time to realise just why the strange things are happening - so best avoid.


Quote
Some notes about MAC addresses
If you are using your own device behind a router and it is not visible to the 'outside world' you can in fact program any MAC address that you like because it is in a private area. It just has to be unique in this private area. (This is also valid for a device sitting in a Demiliterized Zone- DMZ)
If however you are selling a product or the device is sitting directly on the Internet then it must have a world wide unique MAC address which has to be purchased from IEEE. It is purchased either as a block (IAB) of 4k MAC addresses at a cost of about $500, or if you are going to produce a large number of pieces of equipment you can purchase a unique company ID (OUI) of 16Million for about $1'600 (plus $2'000 if you don't want the OUI to be registered on the public listing).

It is then your responsibility to manage the assignment of these addresses in your own products.

The registration page is at: http://standards.ieee.org/regauth/index.html
For any one just wanting to make one or two pieces of equipment for hobby use it is a bit much to pay $500 for a bunch of MAC addresses and use just one or two of them. Unfortunately it is no allowed to sell the rest on to people in similar situation because a block must always remain with the individual or organisation purchasing it.

One trick which is often used is to find out what the MAC address is in an old NIC from an old PC which is being scrapped. This MAC address is then used in your own piece of equipment and the old NIC destroyed. You can then be sure that the MAC address is unique and can not disturb when used for any imaginable application.


Regards

Mark




3223
ATMELTM AT91SAM7X and AVR32 / Re: porting uTasker to the winarmgcc
« on: July 20, 2007, 04:34:48 PM »
Emerson

This is OK.

Code: [Select]
.bss           0x00200830        0xc Build\uMalloc.o
 .bss           0x0020083c       0x14 Build\uTasker.o
                0x0020083c                ptMultiStartTable
                0x00200840                JumpTable

It is just showing where the bss section for uTasker.o begins and that it contains 2 global variables (ptMultiStartTable and JumpTable) with their addresses.

uMalloc in comparison does has zero initialised variables (probably 0x0c in total length) but they are not listed since they are declared static and so are private to the file (addresses are not available globally).

The map shows that the linker has done everything correctly. Assuming that these variables are not 0 it means that the initialisation code is not being called or it is making mistakes.

Regards

Mark


3224
ATMELTM AT91SAM7X and AVR32 / Re: Ethernet speed
« on: July 20, 2007, 11:20:39 AM »
Hi Michael

I checked in the recording that you sent me (by private mail).

The PC has a short delay of around 200us and the SAM7X has a delay of around 2.5ms. This is about that what I would expect.
You are sending and receiving 30 echos (1460byte payload) in 80ms which results in an echo throughput of 547kByte / s or 4.38MBit/s.
This is a round trip time which is dictated mainly by the time that it takes the SAM7X to handle the frame reception and send back the echo frame.

In normal circumstances the reaction time will not be influenced by other protocols activated since the other protocols are not operating unless the frame type is for them. Any other tasks in the system are usually sleeping (not polling) until they are woken to do work destined for them. Your test shows a very stable echo response time - although there can be some slightly longer reaction times depending on what other tasks the processor could be performing in a project with multiple functions.

The interrupt itself doesn't process the frame but simply wakes the reception task which then does the work outside of the interrupt routiune. The task scheduling will be in us region so doesn't contribute to the main delay time being seen.

When a frame is received it has to be checked for correct IP contents and then for correct TCP contents. Quite a time intensive part is the calculation of the check sum over the frame - since each byte has to be checked and calculated.
The SAM7X 'unfortunately' also has to do a memcpy of each frame to a linear buffer due to the fact that the Ethernet buffer is made up of a chain of smaller buffers which have to have a circular wrap at the end (this is a characteristic of the chip) - in would be possible to remove the copy for frames which do not actually wrap in the buffer and define as many buffers as possible so that the wrap occurs, say, once every 10 frames - this would reduces the time by maybe 0.4ms for 90% of frames.

When echoing the frame, the TCP header has to be modified and thus also the check sum of the new frame on transmission (as I noted, this tends to be the highest processor overhead). There is finally one memcpy to the transmit buffer (this last copy can be optimised away but it makes the solution very specific, so for general use the copy is performed).

If TCP transmissions are within a LAN it would be possible to remove check sum verification on reception frames (relying on the CRC over the Ethernet frame which is stronger anyway). This would accelerate reception by maybe 50% - it is however not advisable for frames originating from outside of a local network/infranet (which is often the case...)

My conclusion is that your results are as expected for this chip. There are a few points where acceleration are possible but these may make for a less general purpose solution. However the processing power of the chip used finally defines the throughput which is possible. It may be possible to do some project specific optimisation which can reduce throughput (in best case) by possibly factor 2 but this will then be a very specific solution and be at the operating limits of the device. If more reserve is needed and a specific optimisation avoided then more powerful chips (or the use of hardware implementations) may be the best solution.

Regards

Mark

3225
ATMELTM AT91SAM7X and AVR32 / Re: porting uTasker to the winarmgcc
« on: July 20, 2007, 10:36:49 AM »
Hi Emerson

Checking the code the following is not a sequence of lines in the file but the order that the lines of code are executed when stepping with the debugger.
prtInfo = ptMultiStartTable;            //6  step in
   if (prtInfo == 0) {                 // 7 step in
    if (prtInfo->new_hw_init) {    //8 step in


This means that ptMultiStartTable is NOT equal to 0 since it is trying to access a memeber of the structure pointed to by it - causing an abort.

Now I think that ptMultiStartTable is in fact the first variable being used and it is 0 in the demo project (if nothing has been changed).

This suggests to me that your variables are not being correctly initialised.
Check the location of ptMultiStartTable in the map file (it should be in the BSS section) and try to find out why its value has not been set to 0. You can also do the same test with an initialised variable to ensure that it is correctly initialised to the expected value.
All initialisation should have been completed by the time that the code above is executed but I think that you will find that this is not the case. This must be solved to be able to run code from this point.

Good luck!!

Mark


Pages: 1 ... 213 214 [215] 216 217 218