Laurent Ellerbach

Ce blog est principalement destiné à publier des informations relatives à Microsoft, à ses technologies, aux outils Visual Studio et à ses versions Express notamment Visual Basic

April, 2012

  • Laurent Ellerbach

    Using netduino and .NET Microframework to pilot any Lego Power Function thru Infrared (part 3)

    • 0 Comments

    In the previous post, I’ve explain how to create a class and the hardware that will be able to pilot any Lego Power Function. In this article, I will explain how to create a web server (like IIS or Apache but much much much more simpler) and create a simple way to call the class.

    I’ve already explained how to create such a web server into one of my previous article. So Il will use the same idea. I will only explain the implementation of the specific part to call the Combo Mode function as I already take it in the past articles.

    The function is part of the LegoInfrared class and looks like

    public bool ComboMode(LegoSpeed blue_speed, LegoSpeed red_speed, LegoChannel channel)
    

    LegoSpeed and LegoChannel are both enums.

    The simple view of the HTTPServer Class is the following:

    public static class MyHttpServer
    {
        const int BUFFER_SIZE = 1024;
        // Strings to be used for the page names
        const string pageDefault  = "default.aspx";
        const string pageCombo  = "combo.aspx";
        // Strings to be used for the param names
        const string paramComboBlue = "bl";
        const string paramComboRed = "rd";
        const string paramChannel = "ch";
        // Strings to be used for separators and returns
        const char ParamSeparator = '&';
        const char ParamStart = '?';
        const char ParamEqual = '=';
        const string strOK = "OK";
        const string strProblem = "Problem";
        
        // Class to be used to find the parameters
        public class Param
        // Create a Lego Infrared object
        private static LegoInfrared myLego = new LegoInfrared();
        public static void StartHTTPServer()
        {
            // Wait for DHCP (on LWIP devices)
            while (true)
            {
                IPAddress ip = IPAddress.GetDefaultLocalAddress();
    
                if (ip != IPAddress.Any) 
                {
                    Debug.Print(ip.ToString());   
                    break;
                }
    
                Thread.Sleep(1000);
            }
            
    
            // Starts http server in another thread.
            Thread httpThread = new Thread((new PrefixKeeper("http")).RunServerDelegate);
            httpThread.Start();
    
            // Everything is started, waiting for commands :-)
            Debug.Print("Everything is started, waiting for command");
        }
    

    There are of course couple of other functions part of the class but I make it simple here. I created couple of const to be able to handle the name of pages and as explained in past articles, I will use URL like combo.aspx?bl=8&rd=2&ch=1

    Here by convention, bl will contains the value of the blue speed, rd, the red one and ch the Channel. the combo.aspx is the page name to call the ComboMode function. And yes, I do not need to use any extention, I can use just combo? or cb? or whatever I want. But I feel it’s cool to see .aspx as an extension in a board with only couple of kb of memory Sourire

    Now let have a look at the ProcessClientGetRequest function which will allow us to switch from one page to another.

    private static void ProcessClientGetRequest(HttpListenerContext context)
    {
    
        HttpListenerRequest request = context.Request;
        HttpListenerResponse response = context.Response;
    
        string strFilePath = request.RawUrl;
        // Switch to the right page 
        // Page Combo
        if (strFilePath.Length > pageCombo.Length)
        {
            if (strFilePath.Substring(1, pageCombo.Length).ToLower() == pageCombo)
            {
                ProcessCombo(context);
                return;
            }
         }
         // Brunch other pages + Start HTML document
    }
    

    This function is called when a GET request is done to the Web Server. The request.RawURL return the name of the URL with all the parameters. So we just need to compare the name of the page with the first part of the URL. All URL start with /, so we start at position 1. If it does match, then, go to the ProcessCombo function. Otherwise, continue and do switches like that for all needed pages. And finally, you can build your own code. And that is what we will do later. Yes, we will generate a bit of HTML Sourire

    private static void ProcessCombo(HttpListenerContext context)
    {
        HttpListenerRequest request = context.Request;
        HttpListenerResponse response = context.Response;
        string strParam = request.RawUrl;
        string strResp = "";
        if (DecryptCombo(strParam))
            strResp = strOK;
        else
            strResp = strProblem;
        OutPutStream(response, strResp);
    }
    
    

    This function is very simple and just do a branch depending on the result of the DecryptCombo function. If it is successful, then it will return OK, if not, it will return Problem.

    private static bool DecryptCombo(string StrDecrypt)
    {
        // decode params
        Param[] Params = decryptParam(StrDecrypt);
        int mChannel = -1;
        int mComboBlue = -1;
        int mComboRed = -1;
        bool isvalid = true;
        if (Params != null)
        {
            for (int i = 0; i < Params.Length; i++)
            {
                //on cherche le paramètre strMonth
                int j = Params[i].Name.ToLower().IndexOf(paramChannel);
                if (j == 0)
                {
                    mChannel = Convert.ToInt32(Params[i].Value);
                    if (!((mChannel >= (int)LegoInfrared.LegoChannel.CH1)
    && (mChannel <= (int)LegoInfrared.LegoChannel.CH4))) isvalid = false; } j = Params[i].Name.ToLower().IndexOf(paramComboBlue); if (j == 0) { mComboBlue = Convert.ToInt32(Params[i].Value); if (!((mComboBlue == (int)LegoInfrared.LegoSpeed.BLUE_BRK)
    || (mComboBlue == (int)LegoInfrared.LegoSpeed.BLUE_FLT) || (mComboBlue == (int)LegoInfrared.LegoSpeed.BLUE_FWD)
    || (mComboBlue == (int)LegoInfrared.LegoSpeed.BLUE_REV))) isvalid = false; } j = Params[i].Name.ToLower().IndexOf(paramComboRed); if (j == 0) { mComboRed = Convert.ToInt32(Params[i].Value); if (!((mComboRed >= (int)LegoInfrared.LegoSpeed.RED_FLT)
    && (mComboRed <= (int)LegoInfrared.LegoSpeed.RED_BRK))) isvalid = false; } } } // check if all params are correct if ((isvalid) && (mComboRed != -1) && (mChannel != -1) && (mComboBlue != -1)) { if (!Microsoft.SPOT.Hardware.SystemInfo.IsEmulator) isvalid = myLego.ComboMode((LegoInfrared.LegoSpeed)mComboBlue,
    (LegoInfrared.LegoSpeed)mComboRed, (LegoInfrared.LegoChannel)mChannel); else Debug.Print("Sent Combo blue " + mComboBlue.ToString()
    + " red " + mComboRed.ToString() + " channel " + mChannel.ToString()); } else isvalid = false; return isvalid; }

    I’ve been thru this kind of explanation couple of times in the previous examples. The code is quite simple, it first call a decrypt function that will return a table containing the parameter name and the value, both as string. More info here. If I take the previous example combo.aspx?bl=8&rd=2&ch=1, it will return 3 params with the pair (bl, 8), (rd, 2), (ch, 1). The idea is to convert and validate those parameters. When one is found, it is converted to the right type and compare to the enums values to check is everything is correct.

    If all parameters are converted correctly and the values are valid, then the ComboMode function is called. If the function is successful, then the value true is return form the function and see the previous section, it will return OK. If not, Problem will be returned.

    As you can see, I check if I’m in the emulator or in a real board. If I’m in the emulator, I will not physically send the signal as it is just an emulator Sourire That allow me to do development in the planes and test the code. Of course, back home, I test them for real, just in case Sourire

    So we now have a way to call our ComboMode function thru a simple URL. I can also create a simple UI to be able to send commands very simply thru a web page. For this, I’ll need to do some HTML. And I have to admit, I don’t really like HTML… The idea of this simple UI is to be able to have dropdown box to select the speed for both the Blue and the Red output but also select the channel. At the end, the UI will looks like this:

    image

    The HTML code to do it is the following for the ComboMode:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head><title></title></head><body>
    <form method="get" action="combo.aspx" target="_blank"><p>Combo Mode<br />
    Speed Red<select id="RedSpeed" name="rd">
    <option label='RED_FLT'>0</option>
    <option label='RED_FWD'>1</option>
    <option label='RED_REV'>2</option>
    <option label='RED_BRK'>3</option>
    </select> Speed Blue<select id="BlueSpeed" name="bl">
    <option label='BLUE_FLT'>0</option>
    <option label='BLUE_FWD'>4</option>
    <option label='BLUE_REV'>8</option>
    <option label='BLUE_BRK'>12</option>
    </select> Channel<select id="Channel" name="ch">
    <option label='CH1'>0</option>
    <option label='CH2'>1</option>
    <option label='CH3'>2</option>
    <option label='CH4'>3</option>
    </select>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <input id="Submit1" type="submit" value="Send" /></p></form>
    </body>
    </html>
    

    Nothing rocket science, just a bit of HTML. Please note that the form will be send in get mode so with a URL exactly like the one we want. the target=”_blank” attibute of form is to open it in a new window when the submit button will be clicked. I prefer this as it allow to keep the main windows open and change easily one of the value without changing everything.

    The label attibute of the option tag in a select allow you to put the name you want in the combo list. The value inside the option tag is what will be send. So you can display a friendly name instead of a “stupid” number.

    In terms of code, here is what I have done. This code is part of the ProcessClientGetRequest function:

    // Start HTML document
    string strResp = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional
    //EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
    ; strResp += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title></title></head><body>"; // first form is for Combo mode strResp += "<form method=\"get\" action=\"combo.aspx\" target=\"_blank\">
    <p>Combo Mode<br />Speed Red<select id=\"RedSpeed\" name=\"rd\">"
    ; strResp += "<option label='RED_FLT'>0</option><option label='RED_FWD'>1</option>
    <option label='RED_REV'>2</option><option label='RED_BRK'>3</option>"
    ; strResp += "</select> Speed Blue<select id=\"BlueSpeed\" name=\"bl\">
    <option label='BLUE_FLT'>0</option><option label='BLUE_FWD'>4</option>
    <option label='BLUE_REV'>8</option><option label='BLUE_BRK'>12</option>"
    ; strResp += "</select> Channel<select id=\"Channel\" name=\"ch\">
    <option label='CH1'>0</option><option label='CH2'>1</option>
    <option label='CH3'>2</option><option label='CH4'>3</option>"
    ; strResp += "</select>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <input id=\"Submit1\" type=\"submit\" value=\"Send\" /></p></form>"
    ; strResp = OutPutStream(response, strResp);

    I just create the form as it should be, very simply. Filling a string and outputting the string to the response object. Be careful as in netduino, the maximum size of any object, so including strings is 1024. The strResp object can’t contain more than 1024 caracters, so it is necessary to empty it. The way I do it is thru the OutPutStream function which output the string value into the response stream. I’ve already explained it in a past article.

    So here is it for this part. I’ve explained how to be able to create a set of Web API, very simple to control this infrared emitter. This principle can be apply to anything! I have couple of ideas for the next step. I can implement a system with sensors (can be ILS for examples) and signals (green/red lights) and switch management. But I’m not there yet! Any feedback and ideas welcome.

  • Laurent Ellerbach

    Using netduino and .NET Microframework to pilot any Lego Power Function thru Infrared (part 2)

    • 2 Comments

    In a previous post, I’ve started to describe the Lego Power Function protocol and how I’ve implemented it on a netduino board using .NET Microframework. My work is based on ideas and implementation Mario explain in his blog. We’ve exchange couple of emails to make both our projects work Sourire

    To continue where I stopped, The message_pause function is like this:

     

    private void message_pause(uint channel, uint count)
    {
    
        int a = 0;
        // delay for first message
        // (4 - Ch) * Tm
        if (count == 0)
            a = 4 - (int)channel + 1;
        // next 2 messages
        // 5 * Tm
        else if (count == 1 || count == 2)
            a = 5;
        // last 2 messages
        // (6+2*Ch) * Tm
        else if (count == 3 || count == 4)
            a = 5 + ((int)channel + 1) * 2;
    
        // Tm = 16 ms (in theory 13.7 ms)
        System.Threading.Thread.Sleep(a * 16);
    

    It is a bit more comprehensive if you look at this picture. Each dot represent a signal sent. and each space the time you have to wait.

    image_thumb[10]

    The Lego protocol says you have to wait 16 ms minimum between 2 messages as it is the max size of a message. How did they arrive to this magic number?

    Back to our protocol, we know that the frequency is 38KHz, that the structure of a message starts and stop with a start/stop bit which is composed by 6 pulses IR and 39 pauses. A low bit is a 6 IR pulse and 10 pauses, a high bit a 6 IR pulse and 21 pauses. So we can do a ^simple table like this to have the length in µ seconds and the length in ushort:

    Type Total
    start µs           1 184  
    start ushort                 45  
    stop µs           1 184  
    stop ushort                 45  
    low µs              421  
    low ushort                 16  
    hight µs              711  
    hight ushort                 27  

    And we can also have the view of the full size of a message. The minimum size (if all bits are low) and the maximum one (if all bits are high):

      Total Start Toggle Escape C C a M M M D D D D L L L L stop
    Min size µs 9104 1184 421 421 421 421 421 421 421 421 421 421 421 421 421 421 421 421 1184
    Min size ushort 346 45 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 45
    Max size µs 13744 1184 711 711 711 711 711 711 711 711 711 711 711 711 711 711 711 711 1184
    Max size ushort 522 45 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 45

    So if you do the sum, you can see that the maximum length is 13 744 µ seconds which is 13.744 mili seconds and not 16ms as Lego describe. But lets take the Lego recommendation there. As you can see also the maximum length of a message is 522 ushort. And that’s the perfect transition to have a look at the spi_send function:

    private void spi_send(ushort code)
    {
        try
        {
            ushort[] tosend = new ushort[522]; // 522 is the max size of the message to be send
            ushort x = 0x8000;
            int i = 0;
    
            //Start bit
            i = FillStartStop(tosend, i);
    
            //encoding the 2 codes
            while (x != 0)
            {
                if ((code & x) != 0)
                    i = FillHigh(tosend, i);
                else
                    i = FillLow(tosend, i);
                x >>= 1;  //next bit
            }
            //stop bit
            i = FillStartStop(tosend, i);
            MySerial.Write(tosend);
        }
        catch (Exception e)
        {
            Debug.Print("error spi send: " + e.Message);
        }
    
    }
    
    

    The code starts with the creation of a ushort buffer of 522 elements. It is the max size of a message. The I create a short “x” (ok, I’m not creative for this little increment, but any developer has to use some crappy small names time to time Sourire). I will use it as a mask to see what is the value to send.

    There are now 3 functions called here: FillStartStop, FillHigh and FillLow. They are like this:

    private int FillStartStop(ushort[] uBuff, int iStart)
    {
        //Bit Start/stop = 6 x IR + 39 x ZE
        int inc;
        int i = iStart;
        //startstop bit
        for (inc = 0; inc < 6; inc++)
        {
            uBuff[i] = _high;
            i++;
        }
        for (inc = 0; inc < 39; inc++)
        {
            uBuff[i] = _low;
            i++;
        }
        return i;
    }
    
    private int FillHigh(ushort[] uBuff, int iStart)
    {
        //Bit high = 6 x IR + 21 x ZE
        int inc;
        int i = iStart;
        //High bit
        for (inc = 0; inc < 6; inc++)
        {
            uBuff[i] = _high;
            i++;
        }
        for (inc = 0; inc < 21; inc++)
        {
            uBuff[i] = _low;
            i++;
        }
        return i;
    }
    
    private int FillLow(ushort[] uBuff, int iStart)
    {
        //Bit low = 6 x IR + 10 x ZE
        int inc;
        int i = iStart;
        //Low bit
        for (inc = 0; inc < 6; inc++)
        {
            uBuff[i] = _high;
            i++;
        }
        for (inc = 0; inc < 10; inc++)
        {
            uBuff[i] = _low;
            i++;
        }
        return i;
    }
    

    Those functions take the buffer as an input and where to fill it. And then depending if it is a start/stop, low or high bit will fill the buffer correctly. For example, the low bit is 6 times IR pulses (_high = 0xFE00) and 10 times pauses (_low = 0x0000). And it return the new start position.

    Back to the spi_send function, after calling a first time the FillStartStop, the while loop use the “x” variable as a mask, call FillHigh if it is a high bit and FillLow if it is a low bit. And I change the mask for each bit. High bits have to be send first.

    while (x != 0)
    {
        if ((code & x) != 0)
            i = FillHigh(tosend, i);
        else
            i = FillLow(tosend, i);
        x >>= 1;  //next bit
    }
    

    When all the bits are transformed and the waveform is created, the signal is sent with MySerial.Write(tosend);

    The MySerail object is an SPI object:

    private SPI MySerial;
    

    Initialization is done like this:

    try
    {
        //Frequency is 38KHz in the protocol
        float t_carrier = 1 / 38.0f;
        //Reality is that there is a 2us difference in the output as there is always a 2us bit on on SPI using MOSI
        float t_ushort = t_carrier - 2e-3f;
        //Calulate the outpout frenquency. Here = 16/(1/38 -2^-3) = 658KHz
        uint freq = (uint)(16.0f / t_ushort);
    
        SPI.Configuration Device1 = new SPI.Configuration(
        Pins.GPIO_NONE, // SS-pin
        true,             // SS-pin active state
        0,                 // The setup time for the SS port
        0,                 // The hold time for the SS port
        true,              // The idle state of the clock
        true,             // The sampling clock edge
        freq,              // The SPI clock rate in KHz
        SPI_Devices.SPI1);   // The used SPI bus (refers to a MOSI MISO and SCLK pinset)
    
        MySerial = new SPI(Device1);
    
    }
    catch (Exception e)
    {
        Debug.Print("Error: " + e.Message);
    }
    

    Details on on the math can be found in Mario article. This is a very precise math, the tolerance for the Lego protocol is about 30%. The official document gives the following range value:

    Low bit range 316 - 526 us
    High bit range 526 – 947 us
    Start/stop bit range 947 – 1579 us

    That said, it is better to be in the right domain, make it work better.

    So we’ve seen how to create the waveform, send it over the MOSI output. Now, let see how to use all this in a very simple way.

        public class Program
        {
            public static void Main()
            {
                LegoInfrared myLego = new LegoInfrared();
                for (int i = 0; i < 10; i++)
                {
                    myLego.ComboMode(LegoInfrared.LegoSpeed.BLUE_FWD, LegoInfrared.LegoSpeed.RED_FWD, LegoInfrared.LegoChannel.CH1);
                    System.Threading.Thread.Sleep(1000);
                }
            }
    
        }
        public class LegoInfrared
    

    The LegoInfrared class does contains all the functions and enums I’ve explained. Here the usage is extremely simple. I create an object like this and call 10 times a forward command for both the Blue and Red output on channel 1. I wait 1 second and do it again. And the good news is that it is really working. I’m of course using the electronic schema that Mario proposed.

    If you are interested in the full source code of the full protocol, just let me a comment.

    More to come to show how to pilot it thru a web server and how to use it from another program. And again, depending of my inspiration, we will go a bit further and use sensors to raise events and be a bit smarter. Stay tune Sourire. If you want to implement other protocols like RC5, you can directly go to Mario blog and use his code. If you have a more complex protocol like the Lego one, you’ll be able to reuse most of the implementation I’ve done. Let me know if you want the full code.

  • Laurent Ellerbach

    Using netduino and .NET Microframework to pilot any Lego Power Function thru Infrared (part 1)

    • 2 Comments

    I’m part of FREELUG, the French Enthusiast Lego User Group. And in this group, there are lots of discussions on Lego of course. In one of the thread someone ask the question if it was possible to pilot an Lego train using the new Power Function with a PC. The need is during expo, it makes it easier to run trains, stop them in a programmatic way.

    image

    I did a quick answer on the list saying that it can be quite easy if the protocol was not too complex and the IR technology used was close to RC5 from Philips. A small oscillator behind a serial or parallel port would do the trick. Philo, one of the FREELUG member answer me with a link to the protocol. And also tell me it should not be as easy as I was thinking. And he was more than right! No real way to make this work with a simple serial or parallel port on a PC. The protocol is more complex and need quite a bit of work to implement. I’ll come later on the first explanation on how to do it.

    So I decided to see if it was possible to implement this on netduino using .NET Microframework. this board has lots of IO, analogic and digital, do implement busses like I2C but also SPI. As any project, I started my project with my friend Bing. And start searching for similar projects. And I found Mario Vernari who I’ve mentioned in my previous post who was doing something similar. And we’ve exchange couple of emails to find a good way to implement an Infrared emitter using .NET Microframework. We will create the wave form in a buffer and then send it thru the MOSI port of an SPI port linked to the infrared led. So I will use the ideas and implementation Mario explain in his blog to pilot the Lego Power Function.

    I let go thru Mario article to get the basics of the IR protocol in general. And I will focus here on the specific Lego implementation and of course the specific code to make it work.

    Reading the 14 pages of the Lego protocol, we learn that the IR signals are using 38 kHz cycles. An IR Mark is 6 on and off signals as shown in the next picture

    image

    Each message will start and stop with a Start/Stop bit. This bit is 6 IR Mark and 39 pauses. So if I represent it in a binary way it will be:

    101010101010000000000000000000000000000000000000000000000000000000000000000000000000000000

    As Mario described in his post, we will use ushort to create the wave length. So in this case it will looks like

    0xFF00 0xFF00 0xFF00 0XFF00 0xFF00 0xFF00 and 39 times 0x0000

    Reality is a bit different as when using MOSI on a SPI to output a signal it is always a 1 for couple of µ seconds. So the right value to use is 0xFE00

    The low bit is working the same way, it is 6 IR Mark and 10 cycles of pause, the high one 6 IR Mark and 21 cycles of pause.

    So if I want to send the binary value 10011 I will send 6 IR Marks, 21 pauses, 6 IR Marks, 10 pauses, 6 IR Marks, 10 pauses, 6 IR Marks, 21 pauses, 6 IR Marks, 21 pauses. And I will create a ushort buffer which will contains 6 times 0xFE00, 21 times 0x0000, 6 times 0xFE00, 10 times 0x0000, 6 times 0xFE00, 10 times 0x0000, 6 times 0xFE00, 21 times 0x0000, 6 times 0xFE00, 21 times 0x0000

    All this make the Lego protocol complex compare to the RC5 and other similar protocols where the Low bit and high bits are usually the same size, the IR Mark is just inverted and the pause same size as the IR Mark.

    Now let have a look at the protocol itself.

    image

    The protocol start and stop with our Start/Stop bit describe up in the article. And then have 4 nibble. One nibble is a 4 bit data. The last nibble is used to to a check sum and is called LRC LLLL = 0xF xor Nibble 1 xor Nibble 2 xor Nibble 3.

    There are 4 channels possible going from 1 to 4 represented as CC from 0 to 3.

    a is not used in this protocol for the moment and kept for a future implementation. So it has to be set to 0.

    E is 0 for most modes except one specific mode (PWM)

    Toggle is an interesting one. The value has to change each time a new command is sent. So if the first time you send a command on a specific Channel (let say 1), it is 0, the next command send on Channel 1 will have to set Toggle as 1.

    The Power Function have different modes available (MMM):

    000 Not used in PF RC Receiver
    001 Combo direct (timeout)
    010 Single pin continuous (no timeout)
    011 Single pin timeout
    1xx Single output

    To know which mode is doing what, just refer to the protocol. I will detail the Combo direct (timeout) mode as an example for the rest of the article. It is easy to understand how it is working. The others are not much more complex and the logic is the same.

    image

    Mode (MMM) here is 001. Channel (CC) will vary form 0 to 3 depending which channel you want to pilot. So here, the Data nibble is split into 2 parts BB and AA. The documentation give this:

    B output BB,, called Red in all receivers

    00xx Float output B
    01xx Forward on output B
    10xx Backward on output B
    11xx Brake output B

    A output AA, called Blue in all receivers

    xx00 Float output A
    xx01 Forward on output A
    xx10 Backward on output A
    xx11 Brake output A

    And an interesting information is that Toggle bit is not verified on receiver. So if you don’t want to implement it, it’s possible.

    So it’s time to write some code Sourire Let start with couple of enums to facilitate the usage:

    //mode public enum LegoMode {
        COMBO_DIRECT_MODE = 0x1,
        SINGLE_PIN_CONTINUOUS = 0x2,
        SINGLE_PIN_TIMEOUT = 0x3,
        SINGLE_OUTPUT = 0x4
    };
    
    //speed public enum LegoSpeed {
        RED_FLT = 0x0,
        RED_FWD = 0x1,
        RED_REV = 0x2,
        RED_BRK = 0x3,
        BLUE_FLT = 0x0,
        BLUE_FWD = 0x4,
        BLUE_REV = 0x8,
        BLUE_BRK = 0xC
    };
    
    //channel public enum LegoChannel {
        CH1 = 0x0,
        CH2 = 0x1,
        CH3 = 0x2,
        CH4 = 0x3
    };
    

    The LegoMode one will be used to setup the mode (MMM), the LegoSpeed for the AA and BB output and the LegoChannel to select the Channel.

    private uint[] toggle = new uint[] { 0, 0, 0, 0 };
    
    public void ComboMode(LegoSpeed blue_speed, LegoSpeed red_speed, LegoChannel channel)
    {
        uint nib1, nib2, nib3, nib4;
    
        //set nibs nib1 = toggle[(uint)channel] | (uint)channel;
        //nib1 = (uint)channel; nib2 = (uint)LegoMode.COMBO_DIRECT_MODE;
        nib3 = (uint)blue_speed | (uint)red_speed;
        nib4 = 0xf ^ nib1 ^ nib2 ^ nib3;
    
        sendMessage((ushort)nib1, (ushort)nib2, (ushort)nib3, (ushort)nib4, (uint)channel);
    }
    

    I have defined a toggle table which will contain the value of the toggling. The function ComboModo takes as argument, the channel and the AA and BB parameters.

    The code is quite straight forward, I build the 4 nibbles like in the description.

    nib1 contains the Toggle plus escape (0) plus the channel. Toggle is not mandatory in this one but I’ve implemented to show you how to do it. and the values the Toggle will take will be in binary 1000 or 0000 so 8 or 0 in decimal.

    nb2 is E (which is 0) and the Mode (MMM) which is 1 in our case.

    nib3 combine AA and BB to select the Blue and Red orders.

    nib4 is the check sum.

    And then I call a function called sendMessage. I’ve build all the modes the same way, implementing simply the protocol.

    Now, let have a look at the sendMessage function:

    private void sendMessage(ushort nib1, ushort nib2, ushort nib3, ushort nib4, uint channel)
    {
        ushort code = (ushort)((nib1 << 12) | (nib2 << 8) | (nib3 << 4) | nib4);
        for (uint i = 0; i < 6; i++)
        {
            message_pause(channel, i);
    
            spi_send(code);
        }
        if (toggle[(int)channel] == 0)
            toggle[(int)channel] = 8;
        else toggle[(int)channel] = 0;
    
    }
    

    4 nibbles of 4 bits is 16 bits so a ushort. And I’m building this ushort simply with all the nibbles. OK, the protocol is a bit more complex than only sending 1 time a command. Each command has to be sent 5 times. What make the protocol not easy is that you have to wait different amount of time depending on the channel and the number of time you’ve already send a command! That is the job of the message_pause function. The spi_send send the code Sourire. The rest is about toggling the toggle bit of the channel.

    That’s it for today. In the next blog post, I’ll continue to go more in the details, show the implementation of the missing functions. And when I’ll finish to explain all the protocol code, I’ll go a bit further with a way to remotely using a web page or equivalent send commands to the netduino board which will send the IR command. And if I have more time, I will also implement sensors to detect if a train or a vehicle is on a specific place. This will be extremely easy as I’ve already explain how to use sensors like this.

Page 1 of 1 (3 items)