Networking Stack Bugs reporting, Features requests & Suggestion

11 Jun 2010

I have just released the new networking stack stack. I have also setup a page here in the wiki that will list the changes for each release:

If you experience any bug, want to contribute some code, improve something in the stack or have features requests this is the right thread to do so.

Hope that this will be useful!


11 Jun 2010

The HTTP Client example has been updated, the others will be on monday.

12 Jun 2010


I think it is very substantial piece of work and great code. Congratulations!!!

I tried the new full stack source ( V1.00) - it does not compile as is. Few kinks are in some files that still include headers with old capitalization, specifically SMTPClient.cpp, emailMessage.h, HTTPServer.h.

Also, netCfg.h needs the following to compile and use HTTPServer example:

#define NET_ETH 1
#define NET_LWIP_STACK 1

After fixing those it compiles and runs.

I was able to use TCPSocket to serve some periodic data, such as sensor readings. See my example here iva2k_NetHttpServerTcpSockets. It runs OK.

The biggest issue now is performance. New HTTPServer has very poor performance compared to old HTTPServer implementation by Rolf.

14 Jun 2010

Hi Ilya,

Thanks for your feedback and comments, I have fixed the capitalization problems. Regarding performance I will try and look at what can be optimized, but the balance between memory use and performance is pretty hard to sort out.

If you want to avoid long compilation times, you can try to use the precompiled packages for your project, which is, by the way, a pretty cool example of working application using the stack:).

I have also added an option in the FSHandler class to mount a directory at a specific path on the server (see the HTTPServerExample program).

14 Jun 2010 . Edited: 14 Jun 2010

(Sorry, double post)

14 Jun 2010

Donatien, Great! I am trying new code now. The reason I keep it in source form is to be able to dive in and add a debug printf or two, and being able to tweak some things (like lwipopts.h). Once I shake the things down to be all satisfactory, I will switch to precompiled libraries.

Regarding performance, I think I know how the slowdown is happening. I'm using local FS, which is quite slow I believe (it goes over JTAG to the MBED chip and to serial Flash). The latency of file reads are long. This is done in series with writes in onWriteable(), which blocks the polling of everything else.

If I remember correctly, old Rolf's code was reading the whole file once into a buffer and then sent it over upon onWriteable. It is not very RAM-efficient, but had decent performance.

If that is what slows things down, the solution would be to convert the FSHandler to non-blocking file reads into a buffer and sending over the socket from this buffer. It may support some sort of a DMA (does LPC1768 provide a DMA?). This should allow to service all sockets at highest speed. What do you think?

14 Jun 2010 . Edited: 14 Jun 2010

>I have also added an option in the FSHandler class to mount a directory at a specific path on the server (see the HTTPServerExample program).

Couple new problems (regressions):

  1. Without any calls to FSHandler::mount I can't get to any files I was able to get to under webfs. Should there be an "automount"?
  2. With mounting "webfs" to "/", I am no longer able to get to /rpc interface. Debug log shows that it picks FSHandler for that. Should it try to pick a handler with the longest path first?
  3. UPDATE: there is also a problem to get to /hello as well as /rpc, with or without webfs mount calls. I tried various variants, none work so far.
  4. UPDATE 2: I reviewed the code and figured out that /rpc/ and /hello/ work, while /rpc and /hello don't work (no slash at the end). These worked before without end slash.
14 Jun 2010 . Edited: 14 Jun 2010

Donatien, I noticed material changes only in a couple of files, and that you rewrote HTTPRequestDispatcher::getRequest(). It seems like new getRequest() causes the above problems. Looking through the code again, I got an idea on how to make it more compact and robust:

  1. Remove rootPath vs subPath parsing from HTTPRequestDispatcher::getRequest(). Return the whole path.
  2. Change handler search algorithm in HTTPRequestDispatcher::dispatchRequest() - instead of using "it = m_pSvr->m_lpHandlers.find(rootPath);", iterate through the m_lpHandlers, and compare (*it).first to the start of the whole path, AND check that next char is '/' or termination zero. If match - that's the handler.
  3. If nothing found - proceed to the existing .find("") for the default handler. BTW, should it be .find("/")?

Removing the first .find() and replacing it with for loop and string match is roughly equivalent in performance. Performance is increased by removing first pre-parse in TTPRequestDispatcher::getRequest(). It also solves the problem of guessing what is the root path.

UPDATE: Here's the modified code (.h file needs change for getRequest()) with "NEW CODE" comments where changes are. It works nicely, and have no issues with either /rpc/ or /rpc:

void HTTPRequestDispatcher::dispatchRequest()
  string path;
  string meth;
  HTTP_METH methCode;
  DBG(DBG_SECTION "Dispatching req\r\n");
  if( !getRequest(&path, &meth ) )
    return; //Invalid request
  if( !"GET") )
    methCode = HTTP_GET;
  else if( !"POST") )
    methCode = HTTP_POST;
  else if( !"HEAD") )
    methCode = HTTP_HEAD;
    close(); //Parse error
  DBG(DBG_SECTION "Looking for a handler\r\n");
  map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) >::iterator it;
//  it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that
  int root_len = 0;
  for (it = m_pSvr->m_lpHandlers.begin(); it != m_pSvr->m_lpHandlers.end(); it++) {
    root_len = (*it).first.length();
    if ( root_len &&
      0 == 0, root_len, (*it).first ) && 
      (path[root_len] == '/' || path[root_len] == '\0')
    ) {
	  // Found!
	  break;	// for
   if(it == m_pSvr->m_lpHandlers.end())
    it = m_pSvr->m_lpHandlers.find(""); //Use default handler if it exists
    root_len = 0;
  if(it == m_pSvr->m_lpHandlers.end())
    close(); //No handler found
  DBG(DBG_SECTION "Handler found.\r\n");
//  HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), subPath.c_str(), m_pTCPSocket);
   HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, m_pTCPSocket);
  m_pTCPSocket = NULL; //We don't own it anymore
  case HTTP_GET:
  case HTTP_POST:
  case HTTP_HEAD:
  DBG(DBG_SECTION "Req handled (or being handled)\r\n");

bool HTTPRequestDispatcher::getRequest(string* path, string* meth)
  char req[128];
  char c_path[128];
  char c_meth[128];
  const int maxLen = 128;
  char* p = req;
  //Read Line
  int ret;
  int len = 0;
  for(int i = 0; i < maxLen - 1; i++)
    ret = m_pTCPSocket->recv(p, 1);
    if( (len > 1) && *(p-1)=='\r' && *p=='\n' )
    else if( *p=='\n' )
  *p = 0;
  DBG(DBG_SECTION "Parsing request : %s\r\n", req);
  ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path);
  if(ret !=2)
    return false;
  *meth = string(c_meth);
// NEW CODE (old code removed):
   *path = string(c_path);
  return true;


What do you think?

14 Jun 2010

Here's one more code change (it is independent from my previous post):

void FSHandler::doGet()
  DBG(DBG_SECTION "In FSHandler::doGet()\r\n");
  //FIXME: Translate path to local/path
  string filePath = m_lFsPath[rootPath()];
  if (path().size() > 1)
    filePath += path();
    filePath += "/index.htm";
  m_fp = fopen(filePath.c_str(), "r");
This one makes URL "http://<mbed_ip>/" to get index.htm page.

It checks off last issue on my testcase list (first 6 are fixed by the above proposed code):

  • http://<mbed_ip>/rpc
  • http://<mbed_ip>/rpc/
  • http://<mbed_ip>/hello
  • http://<mbed_ip>/hello/
  • http://<mbed_ip>/files/index.htm
  • http://<mbed_ip>/index.htm
  • http://<mbed_ip>/
15 Jun 2010 . Edited: 19 Jun 2010

I did some benchmarking of the performance using local file system and Google Chrome browser. UPDATE2 - updated with v1.02 data.

File Size Donatien's Stack v1.01 v1.02 Rolf's Stack D's 1.02 time / R's time
/stress.htm 1.6kB 1500ms 97ms 442ms (latency 435ms + download 7ms) 0.2
/rpc/led4/write,1 few bytes 230ms 147ms 452ms (latency 449ms + download 3ms) 0.3
/hello few bytes 86ms 95ms N/A -
/rpc few bytes 21ms 72ms 403ms 0.18
/index.htm 15.8kB 16200ms 1800ms 793ms (latency 514ms + download 235ms) 2.2
/img.png 4.12kB 3750ms 580ms 477ms (latency 408ms + download 69ms)

Latency in Donatien's stack is pretty stable at 150-200ms, with the rest of the time taken by the download.

In short files Donatien's stack beats old stack hands down with better than half time, which is a good indication supporting for the new architecture (dispatch/handler selection).

In longer files, once the doWriteable loop kicks in, there is a big problem - 1kB/s throughput. What is interesting, is the latency in Rolf's stack is longer than the download and proportional to the size of the file.

UPDATE1: I checked Rolf's code, and there is a 700 bytes buffer for the file, so my previous comment about buffering the whole file was incorrect. What Rolf's code uses differently is tcp_sndbuf() - it sends up to that size of data before moving on in the poll cycle.

15 Jun 2010

Hi Ilya,

Wow, thanks for this great feedback!

I agree on your comments, I have started to implement your proposals and I should be able to release a new version tomorrow (with this new implementation, I can serve a 15kB image in less than 2s, which is much more reasonable;)).


17 Jun 2010

Hello Donatien,

I was trying the HTTPClient example, but with own paramteres, the Package compiles when you type

EthernetNetIf eth(
IpAddr(192,168,0,101), //IP Address
IpAddr(255,255,255,0), //Network Mask
IpAddr(192,168,0,1), //Gateway
IpAddr(192,168,0,1)  //DNS

The eth did not appear in the Getting started EthernetNetIf.



17 Jun 2010

Hi Donatien and All,

Great Work on the MySQL/mbed interface! This is a great accomplishment and milestone for microcontrollers such as the LPC1768 family. Previously we've had to resort to less automated techniques to get data from a remote "internet appliance" to a host computer system. These older techniques include serial dial-up modems, custom TCP routines exchanging binary or ASCII data packets, FTP of files, and even removable thumb-drives or SD cards via "sneaker-net". In these older techniques some type of intervention at the host was required to make the data usable at the host. Sometimes daemons were written to intercept incoming data, reformatting it, and then INSERTing it into an SQL database. Other times human intervention was needed to prepare the data for use.

Being able to have a processor such as the LPC1768 gather the data remotely in real-time, and then INSERT the data into a remote SQL database makes this data available to users immediately. Once the data is in an SQL database on a larger machine, web applications can interrogate, format and display any of this data immediately. Great work, Donatien and team.

Ideas for future enhancements: It is unlikely that a remote processor like the LPC1768 will ever need to retrieve collected data from the SQL server. However the processor may occasionally need to interrogate the server for information about the information it has been storing. Future enhancements in this area include, but not limited to, the ability for the LPC1768 to:

  • STORED PROCEDURES            Execute a procedure stored on the host.
  • SHOW PROCEDURE STATUS  Shows status of a stored procedure.
  • SHOW DATABASES                    Shows database names on server
  • SHOW TABLES                             Shows table names in database
  • SHOW STATUS                             Shows server status information.

Or maybe these could all be done by executing a Stored Procedure (similar to an RPC) on the host. For any of these, the mbed code must be able to receive the results data back from the host.

I know the above is a lot to consider. If I were to select just one it would be the ability to send a remote procedure request, and receive maybe 128 bytes of return information.

Anyways, the current mySQL code that Donatien has put in place is working well for my application.

Thanks again, Donatien.


18 Jun 2010

Thanks for pointing that out Michael, I've just updated the wiki page.

Thank you for your comments Doug!

I'll have a look at your proposals, it could actually be useful to be able to retrieve limited data.

By the way, v1.02 is out, I hope it's not too buggy but I have implemented Ilya's proposals and the HTTP Server is perfoming way better now!



18 Jun 2010

Hi Donatien:

Thinking more about SQL data retrieval, I think much of the work can be shoved off to the host stored procedure with a simple response coming back to the LPC-1786. Hera are some examples:

Stored Procedure                             Response to mbed
Is database ABC_123 present? --------------> True/False
Is table "dbase1.whoopy" present? ---------> True/False
How many records in table "whoopy" --------> int (# of records)
What is the ID of last record sent? -------> long (timestamp and key).
Send my configuration info. ---------------> long (option bits).

With a little forethought from the programmer, most stored procedures can get away with sending a response such as:  Yes/No, T/F, int, or long. Maybe, and I can't think of a case right now, a short string might be returned (char[32]).


18 Jun 2010 . Edited: 18 Jun 2010

Hi Donatien

Again great work on the MySql client. I believe the capability to run a query would be very usefully i.e. remote configuration of a device based on its serial number or to seq the time of a device to the server time using "select curtime();"

Regards, Tom.

19 Jun 2010 . Edited: 19 Jun 2010

Donatien, Great improvement! I've tried new v1.02 and updated the benchmark in my previous post I should mention that I kept some of the configs higher in my build (netCfg.h and lwipopts.h).

The stack is pretty stable, and at this point I will start putting it into my existing applications.

I'm still getting some occasional "This webpage is not available." on single page refreshes. Looking into debug messages I can see some truncated request when browser shows an error. The stack was busy sending favicon.ico file (which I had at 15kB). Looks like input buffer overflow / latency problem:


[src/if/net/netservice.cpp : 62 : servicesPoll()] Service 100023b8 is flagged as closed
[src/if/net/netservice.cpp : 40 : ~NetService()] [ - 100021c8 ] 1
[src/services/http/server/HTTPRequestHandler.cpp : 211 : onTCPSocketEvent()] Event 3 in HTTPRequestHandler
[src/services/http/server/impl/FSHandler.cpp : 128 : onWriteable()] FSHandler::onWriteable() event
[src/if/net/net.cpp : 194 : registerNetTcpSocket()] NetTcpSocket [ + 100021c8 ] 4
[src/if/lwip/lwipNetTcpSocket.cpp : 36 : LwipNetTcpSocket()] New NetTcpSocket 100021c8
[src/if/lwip/lwipNetTcpSocket.cpp : 49 : LwipNetTcpSocket()] NetTcpSocket created.
[src/services/http/server/HTTPServer.cpp : 59 : onTCPSocketEvent()] Event 1
[src/if/net/netservice.cpp : 33 : NetService()] [ + 10002540 ] 2
[src/services/http/server/HTTPRequestDispatcher.cpp : 205 : onTCPSocketEvent()] Event 2
[src/services/http/server/HTTPRequestDispatcher.cpp : 48 : dispatchRequest()] Dispatching req

[src/services/http/server/HTTPRequestDispatcher.cpp : 188 : getRequest()] Parsing request : nt: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4

[src/if/lwip/lwipNetTcpSocket.cpp : 401 : cleanUp()] Deallocating unread data.
[src/if/lwip/lwipNetTcpSocket.cpp : 276 : close()] connection closed successfully.
[src/if/net/netservice.cpp : 80 : close()] Service 10002540 to be closed
[src/if/net/net.cpp : 199 : unregisterNetTcpSocket()] NetTcpSocket [ - 100021c8 ] 3
[src/if/net/netservice.cpp : 62 : servicesPoll()] Service 100023b8 is flagged as closed
[src/if/net/netservice.cpp : 40 : ~NetService()] [ - 10002540 ] 1
[src/services/http/server/HTTPRequestHandler.cpp : 211 : onTCPSocketEvent()] Event 3 in HTTPRequestHandler
[src/services/http/server/impl/FSHandler.cpp : 128 : onWriteable()] FSHandler::onWriteable() event
[src/services/http/server/HTTPRequestHandler.cpp : 211 : onTCPSocketEvent()] Event 3 in HTTPRequestHandler
[src/services/http/server/impl/FSHandler.cpp : 128 : onWriteable()] FSHandler::onWriteable() event
[src/services/http/server/HTTPRequestHandler.cpp : 211 : onTCPSocketEvent()] Event 3 in HTTPRequestHandler
[src/services/http/server/impl/FSHandler.cpp : 128 : onWriteable()] FSHandler::onWriteable() event
[src/services/http/server/HTTPRequestHandler.cpp : 211 : onTCPSocketEvent()] Event 3 in HTTPRequestHandler
[src/services/http/server/impl/FSHandler.cpp : 128 : onWriteable()] FSHandler::onWriteable() event


Maybe in the send loop while writing the output data it should look for input buffer level and give it a chance to process the request before it is lost?

17 Jul 2010

Hallo ...

is there any public program to see all codes

best regards


18 Jul 2010

Can anyone help me get started with socket programming on the mbed module? I am trying to use DHCP and sockets, specifically UDP. I cannot find an example that shows how to get the socket support up and running. I have tried, but don't know the correct settings in the lwipopts.h file, and I can't get past the error trying to resolve lwip_socket_init(). Any help would be greatly appreciated.

Thank you,


19 Jul 2010

Russ, this program has some TCP and UDP socket use.

05 Sep 2010

Hi Guys,

Wonder if someone can help me, is there a module available for the ethernet that will allow me to take a txt file on the mbed local file system and send it across the network and save it to a network drive?

I cant seem to find any reference to this on the mbed website, just wondered if any one had tried to do this.


13 Sep 2010 . Edited: 14 Sep 2010

Hi Donatien / Simon

I've just updated to the latest EthernetNetIf library and got quite a shock with the amount of RAM consumed by the libraries. Using the old ethapi, the libraries RAM of my build was 2.4 kB. With the new library, the libraries RAM has gone to 12 kB. Is it possible the EthernetNetIf code is pulling in some C++ features that consume a lot of RAM (see here)?


Edit ...

The reported values depend on whether in beta mode or not. I know there is an issue about how AHB RAM is reported, but it's not just the code RAM that is different between beta or not, it is also the library RAM - highly confusing.

 Also, as a test, I compiled the NetServicesSource (after modifying the netCfg.h file to limit the build), and created an EthernetNetIf object, and the beta compiler claimed 0.6 kB library (good) and 12 kB code (not so good because there are no objects apart from one). Help! I wasn't expecting this, it seems the opposite way round compare to using the precompiled ethernetNetIf library, in terms of code and library RAM usage.

Edit again ...

I think I understand now what is happening when I compile NetServicesSource myself; because it is not a library the memory usage is attributed to code. However, 13 kB for the stack (however split between code and library) still seems too much.

17 Sep 2010

More info here.

12 Nov 2010

Hi All!

Im kinda of new to this networking stack. I'm trying to learn it as much as I can but its inevitable to take this opportunity to ask just few questions:

In my project, Im' trying to understand the program HTTPServerExample. I'm paying attention to files HTTPServer.h/cpp , HTTPRequestDispatcher.h/cpp, HTTPRequestHandler.h/cpp. I guess that my first question has to do with a "field" called "setOnEvent" of the TCPSocket that is constantly changed whenever I am in HTTPServer.cpp, or HTTPRequestDispatcher.cpp or HTTPRequestHandler. And the reason why I mentioned this is because I'm trying to figure out, in the highest level of abstraction, like in HTTP service, what happens if there is new data in that socket. I'm kinda of aware that either netservices.h or net.h has the function that needs to be polled ( Net::poll() ) in order to detect new activity on the network (right?). So who is the first responsible to handle data when there is new data on the socket? I know that at least in these 3 files there is a function "onTCPSocketEvent", does this has something to do with my question? If not, what is the purpose of this function that gets defined in each file?

Another question is what exactly is a handler? I kind of have an idea but I need more in order to fully understand it. After "assigning it" in the main.cpp (of the mentioned program), in HTTPRequestDispatcher.cpp, we look for a handler (which by the way, I don't know much about C plus plus and I'm having a hard time to understand how in this part of the code works, with iteration it?) in m_pSvr->m_lpHandler. Once we found it (let's say we did) we create:

HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, m_pTCPSocket);

(by the way, we are creating a pointer pHdlr and to what are we making it equal? and why is there a coma(,)?

and the invoke the function, lets say doGet().

(another spin off: we search for handlers in HTTPRequestDispatche.cpp but this is inside the function dispatchRequest() that is called in the onTCPSocketEvent(), who could call this function (kind of the same question as earlier)?

I hope you can help me. I know that for some (if not all hehe) this is very easy. It's just that I'm trying to really understand how it works.

I really thank you for your time!

01 Mar 2011

At first, thank's for the work on ip stack.

I have following question, maybe improvement. Whet I tried to use HTTP Server I didn't found a way how to get IP of connected client. I supposes this IP address should be accesible from TCPSocket passed to HTTPRequestHandler c'tor.

Would it be possible to add method like pTcpSocket->getHost() to get this info? Or is there another way?


01 Mar 2011


I have a problem on a "product board":

I make an own LPC1768 board with DP83848 PHY.

When i use the standard Ethernet lib, the implemented mbed_mac_address() function is already called, but with your tcp stack, this function isn't called, and the program hangs.

#include "mbed.h"

extern "C" void mbed_mac_address(char *mac){
 printf("called mbed_mac_address()\r\n");
 mac[0]=  0x1E;
 mac[1]=  0x30;
 mac[2]=  0x6c;
 mac[3]=  0xa2;
 mac[4]=  0x45;
 mac[5]=  0x5e;

#include "HTTPServer.h"
#include "HTTPDynamicPage.h"
#include "pages.h"
#include "URLParser.h"

You can help in this?

Thank you...

07 Mar 2011


where I can find the stress.htm? If I go to the site I get an 404 error.

and is there any example for switch an Output via an Html form?

tia Klaus

15 Apr 2011


I'm a beginner in MBED programming, and my goal is to develop a gateway application to connect a local sensor network to the Internet. On one hand, this connection means that a HTTP client on MBED sends measured values as a HTTP GET request to a remote server. On the other hand, a HTTP server must also run on MBED, this is used for configuring this gateway application over the Internet. Developing with MBED is really fast thanks to the HTTP Client and Server (and many other) libraries. I've first implemented the server function, based on the HTTPServer Example application, and it's worked fine. Then later I've inserted the HTTP Client functionality. My client sends HTTP GET requests periodically based on an asynchronous external event (UART message). This part of code:

//Start listening
  // Timer for LED blinking (showing that we're alive)
  Timer tm;
  //Listen indefinitely
    Net::poll(); // What is this line doing? It is necessary for the server, that's clear
    //Handling an UART based event...
    if (msg_flag)
				// Some file writing...
                MyClient.doGet(url, NULL);
    // For blinking LED:
      led1=!led1; //Show that we are alive
  return 0;



Without accessing to HTTP Server, the HTTP client part works fine. My program has been running for days without error. BUT accessing the HTTP server (from a browser) makes the program dead, but ONLY IF a HTTP Client transmission has done before. In other words: after the start of the program, the HTTP server works fine, until the sending of the first HTTP GET message. What did I wrong? I suppose it is not a bug of the libraries, but I made some mistakes that I can't recognise.

Thanks for your help and sorry if my English is poor :)


P.S.: I've attached my main.c file, but I've deleted the irrelevant parts, so you can take a look at the structure of my program: /media/uploads/fodorg01/main_cutted.h

25 Aug 2011

Klaus Kastler wrote:


where I can find the stress.htm? If I go to the site I get an 404 error.

and is there any example for switch an Output via an Html form?

tia Klaus

@Klaus you can find one at

25 Aug 2011

another example with 3 buttons

Home Server

<h1>Home Server</h1>
<h4>Designed by Lotfi - v0.2</h4>
<script language="javascript">

var Button = 0;
var X10DeviceState=new Array(3);
//var X10DeviceChannel= new Array(1,2,9);	// X10 Channel
var X10DeviceChannel= new Array(2,3,4);	// LED

function X10_On(device)
var elt = document.getElementById( "FormButton"+X10DeviceChannel[device])
if (X10DeviceState[device]==0)
	X10DeviceState[device] = 1;
	elt.value = "Off";
	X10DeviceState[device] = 0;
	elt.value = "On";			
//	alert(X10DeviceState[device]);
var req = new XMLHttpRequest();
//var cmd= "" + X10DeviceChannel[device] +"/write+" + X10DeviceState[device];
var cmd= "http://" + + "/rpc/led" + X10DeviceChannel[device] +"/write+" + X10DeviceState[device];
//	alert(cmd);"GET", cmd, true);

 <form name="Form" action="#">
 <input type="button" value="On" id="FormButton2" onclick="X10_On(0)">
 <input type="button" value="On" id="FormButton3" onclick="X10_On(1)">
 <input type="button" value="On" id="FormButton4" onclick="X10_On(2)">