Tuesday 20 September 2005

Batch File to Fix my Internet

The setup of the computers at my flat to access the Internet is like this:

Internet--USB ADSL Modem--Server--Fast Switch--Access Point--Computers
                                             |
                                             |-Computers
Some computers are connected to the server via the router, others by the wireless router. Everything is happy in the networking world, except for one problem.

Sometimes the modem on the server drops the Internet connection, and cannot reconnect. The only way that I could find to fix the problem was to logon to the Server with VNC and restart the computer. Eventually I got sick of doing this (after the second time) and decided to write a batch file to do the job for me (after the millionth time).

The batch file checks every 15s to see if the Internet is still working by pinging Google.com. I did start with Microsoft.com, but they must have some automatic protection, because after about 10min of pinging, all further requests were bounced. If the ping fails consistently after three attempts at the ping command, the computer reboots.

The batch file on the server is like so:

@echo off
set timeouts=
:start
echo Testing Internet Connection...
set timeout=
for /f "tokens=1*" %%r in ( 'ping -n 1 google.com' ) do (
  if "%%r"=="Unknown" (
    set timeout=o
  )
  if "%%r"=="Request" (
    set timeout=o
  )
)

if "!timeout!"=="o" (
  echo Failure
  set timeouts=!timeouts!c
) else (
  echo Success
  set timeouts=
)

if "!timeouts!"=="ccc" (
  echo About to restart computer
  net send vincentp4 The Internet computer is about to restart in 20+10s.
)

choice /Ty,20 Continue? 

if errorlevel 2 goto end

if "!timeouts!"=="ccc" (
  net send vincentp4 The Internet computer is going down now!
  shutdown /r /t:10 "Shutting down to fix Internet!" /c
  echo Command issued
  goto end
)

goto start
:end
This file is stored at "c:\bat\test.bat" the machine has Windows 2000 installed. The bat directory also includes choice.com and shutdown.exe. In my start menu startup folder I have the following batch file:
net send vincentp4 This computer has restarted and the Internet needs to be reconnected.
"C:\Program Files\Alcatel\SpeedTouch USB\STDialUp.exe" /WindowsDial /Entry "Alcatel Speedtouch Connection"
net send vincentp4 The Internet is now connected.
cd c:\battest
Which sends me a message before it dials, and after it dials, then starts test.bat.

If you need any explanation, just leave me a comment and I will elaborate.

Thursday 8 September 2005

Work

I am currently designing an XML language to describe configuration structures and rules to allow our graphical package here at Pertronic to manage configurations in a spreadsheet and graphical format. A couple of the things is that the XML file needs to reference data not stored in the file (e.g. strings for display names) as well as define rules and forced actions, which means I need to have some sort of mini scripting language in it.

It is not the easiest thing to do in the world but it is something that needs to be done. I have been building the core of the new package all this year, using C#, and so far I haven't touched on a single UI aspect. I have been defining the way plugins connect, are loaded, and kept from corrupting the programme. As well as an internal logging system, encryption, built in user security, central multi-language interpreter among other core features.

All of these could have been bludged into the different components seperately and I would have made a working product by now. The fact is that I am building it for maximum speed, expandability and mergability.

However, doing it this way, properly planned out and constructed, I am able to reduce the likelyhood of bugs, and with the componentisation that I am also implementing, I am making it easier for bugs to be found it the future. The negative effect of course is time, but I think the benefits will be seen for years to come.

Well, to tell the truth, I have touched on the UI from time to time, with drawings on paper when I was bored. I even went away and made a few controls, which I may make open source when I have finished them (I did them in my own time, and they are therefore mine). They are not the central controls of the package though, just niceties.

Thursday 19 May 2005

Design and the Importance of.

It is very good practice to design any applications well and thouroughly before commencing work on them. Here is the process that I prefer to take (and have taken in all recent projects):

  1. Harvest as many customer requirements as possible.
  2. Try to understand the way that your customers think, and write a small document listing the requirements as you understand them, trying to fit them into what the customers are trying to tell you.
  3. Hand the document to co-workers and benevolent customers, asking them for as much feedback as possible.
  4. Think seriously about the feedback, do not be offended to matter how scathing some of it may be. Try to put as much feedback back into the document as possible.
  5. Create a preliminary specification covering as many points in the requirements as possible. Leave placeholders where you are unsure.
  6. Hand this document to the same people to be checked again. Repeat the process until you are satisfied.
  7. Design a structural specification. Define how different modules in your application are going to plug in to each other, and how they will communicate.
  8. Hand the structural specification to your co-workers (after first proof-reading it), and correct any fallacies that they may find.
  9. Test your concepts. Write several small applications to test certain ideas in the structural specification where you do not have experience. DO NOT use any of this code in the final product.
  10. Once you have a good handle on how the application is going to fit together, hand out different modules to the correct people (perhaps only yourself) and begin coding. Again, if you become unsure about certain aspects, write some more proof of concept applications. You really should document anything that you have been unsure about, and found the right answer for.
  11. After that, it is up to the QA of your company and yourself to find any bugs. Document all bugfixes that you make. This will help prevent you from making the same mistakes in the future.
  12. All bugs found should be properly documented. Something like Bugzilla is really good.

Remember that proper planning may make the project seem slow at first, but it will save a lot of money and time in the long run. It will also majorly enhance the quality of the end product. The proof of concept applications will also serve to improve your programming skills to no end, before you even begin work on the actual project. If proper planning is not undertaken from the start, the price will be paid. As the project become larger and more convoluted, you will spend most of your time maintaining it with very little time for adding more features, and working on new products.

In the past, I have taken what were the requirements at the time, with no regard to the future. I delved directly into coding without thinking about future expandibility. This is biting me right now as I struggle to add new protocols, new parameters and features without ruining the structure of the application. I am very fortunate that I am fixing more bugs than I am creating, but I am certainly spending far far far too much time on it.

Another note, if people say bad things about your product, they are probably right. Maybe not fully correct, but correct enough for you to rethink your strategy. Luckily most of my complaints come from co-workers, and not from the customer. But I do know that my unplanned project has been becoming more and more awkward to use. The new one that I am working on now has been designed with all my past mistakes in mind.

Ammendation to code in previous post

I recommend that when using hidden child and parent id's in nested tables, that they should be in the last column. This is because if they are not saved in the XML file, the .NET dataset will automatically add them into the last column. So putting them in the last column at the start will ensure that they are always in the same place.

On a second note, it is usually better practice to save the schema along with the XML file and to leave the child and parent id's intact in the XML file (i.e. do not set them their mapping types as hidden). However, in my place, the consumers of data are very likely to include non .NET platforms such as linux and embedded code (e.g. in this case the Atmel AVR).

My first intended use for this is to create XML files to store different phrases in different languages for a globalised application that I am working on at work. When I have perfected my method of internationalisation in .NET, I will probably write a little article about that and how to make a sample application.

Embedded Tables in XML

Recently, I've been working on the design of new project that will be making extensive use of XML to store data. The project is also going to have to be translated into Chinese and Thai to begin with.

What I like about XML is of course the ability to embed data within data within data ad infinum. Yesterday I started researching the ability of .NET to read and write XML, and I found out that the DataSet object has XMLWrite and XMLRead methods. This made me quite interested. Having never used the DataSet object I read Microsoft's documentation about it which was inconsistent and unclear but understandable.

At first I had a little trouble while trying to get tables to embed properly. I was setting up relationships using parent ID columns and it all looked fine displayed in a DataGrid, but when I saved it to XML, it did not embed the data (which in the end was only one extra line of code to do).

Anyhow, I came across the solution this morning, which was very simple: when creating the DataRelation object, simply set the Nested property to true. Anyway, I thought seeing as I wasted several hours trying to find the answer to this (cursing Google everytime it gave me irrelavent sites), I decided that it would be worthwhile to publish it on this blog. So here is the code (with comments):

      //Declarations
      DataSet myDataSet = new DataSet("root");
      DataTable Ptable = new DataTable("object");
      DataTable Ctable = new DataTable("item");

      //Set up parent table (object)
      Ptable.Columns.Add("ID");
      Ptable.Columns[0].ColumnMapping = MappingType.Hidden; //hidden because I do
      //not want the Parent and Child ID's to show up in the XML, making it messy
      Ptable.Columns.Add("objectdata1",typeof(string));
      Ptable.Columns.Add("objectdata2",typeof(string));

      //Set up child table (item)
      Ctable.Columns.Add("parentID");
      Ctable.Columns[0].ColumnMapping = MappingType.Hidden;
      Ctable.Columns.Add("Age",typeof(int));

      myDataSet.Tables.Add(Ptable);
      myDataSet.Tables.Add(Ctable);

      // set up relation (Relation Name, Parent Column, Child Column)
      DataRelation myRelation = new DataRelation("objectitem",Ptable.Columns[0],Ctable.Columns[0]);
      myRelation.Nested = true; //this makes the tables embedded when written to XML
      myDataSet.Relations.Add(myRelation);

      //Add some meaningless data
      for (int i = 0; i < 4; i++)
      {
        DataRow parentTableRow = Ptable.NewRow();
        parentTableRow[0] = i; // ID to be referenced by the Child
        parentTableRow[1] = "some data " + i.ToString();
        parentTableRow[2] = "more data " + i.ToString();
        Ptable.Rows.Add(parentTableRow);

        for (int j = 0; j < 7; j++)
        {
          DataRow childTableRow = Ctable.NewRow();
          childTableRow[0] = parentTableRow[0]; //ID of the Parent row
          // I like using indexes because sometimes I change column names, but I
          // never change the column index.
          childTableRow[1] = j;  
          Ctable.Rows.Add(childTableRow);
        }
      }
      
      myDataSet.WriteXml("d:\\documents and settings\\vincent\\desktop\\childparent.xml");

The output is the following:

<?xml version="1.0" standalone="yes"?>
<root>
  <object>
    <objectdata1>some data 0</objectdata1>
    <objectdata2>more data 0</objectdata2>
    <item>
      <Age>0</Age>
    </item>
    <item>
      <Age>1</Age>
    </item>
    <item>
      <Age>2</Age>
    </item>
    <item>
      <Age>3</Age>
    </item>
    <item>
      <Age>4</Age>
    </item>
    <item>
      <Age>5</Age>
    </item>
    <item>
      <Age>6</Age>
    </item>
  </object>
  <object>
    <objectdata1>some data 1</objectdata1>
    <objectdata2>more data 1</objectdata2>
    <item>
      <Age>0</Age>
    </item>
    <item>
      <Age>1</Age>
    </item>
    <item>
      <Age>2</Age>
    </item>
    <item>
      <Age>3</Age>
    </item>
    <item>
      <Age>4</Age>
    </item>
    <item>
      <Age>5</Age>
    </item>
    <item>
      <Age>6</Age>
    </item>
  </object>
  <object>
    <objectdata1>some data 2</objectdata1>
    <objectdata2>more data 2</objectdata2>
    <item>
      <Age>0</Age>
    </item>
    <item>
      <Age>1</Age>
    </item>
    <item>
      <Age>2</Age>
    </item>
    <item>
      <Age>3</Age>
    </item>
    <item>
      <Age>4</Age>
    </item>
    <item>
      <Age>5</Age>
    </item>
    <item>
      <Age>6</Age>
    </item>
  </object>
  <object>
    <objectdata1>some data 3</objectdata1>
    <objectdata2>more data 3</objectdata2>
    <item>
      <Age>0</Age>
    </item>
    <item>
      <Age>1</Age>
    </item>
    <item>
      <Age>2</Age>
    </item>
    <item>
      <Age>3</Age>
    </item>
    <item>
      <Age>4</Age>
    </item>
    <item>
      <Age>5</Age>
    </item>
    <item>
      <Age>6</Age>
    </item>
  </object>
</root>

, which is exactly what I intended. This file can then be read directly into a DataSet, and it will set up the two tables as before, without the need for a schema or for the parent and child id's to be saved. It also makes the XML look a whole lot prettier.

In order to leave the child and/or parent ID's in the XML, set the ColumnMapping properties to MappingType.Element. When that is done, it is possible to seperate the items into a separate area within the XML by changing the Nested attribute on myRelation to false. For this to load correctly back into a DataSet object, the schema will need to be saved by adding the argument "XmlWriteMode.WriteSchema" to "myDataSet.WriteXML".

Tuesday 1 March 2005

First Post

Welcome to my programming blog! Here I hope that I can be of some use to people who find this blog, and I also hope that it can be a little interesting. I also started my personal blog today at clearmyhead.blogspot.com and I hope that you can find that an interesting read as well.

I failed High School (well I passed 6th form just, the equivalent of grade 12 I think), but nonetheless I have a job doing programming for a successful fire protection company in New Zealand and Australia. Here my job is to administer a change approval and notification web programme and database. I also look after the PC based configuration utilities for our electronic equipment as well as an upcoming monitoring package.

I am able to go to university this year, but I have worked here for such a long time now (I started when I was 13) and I'm not sure if I really want to go back to studying.

Well thats enough about me because that belongs in the other blog ;). Anyway I hope that this can become a useful resource.