Shop OBEX P1 Docs P2 Docs Learn Events
Simple P2 WiFi WX remote Programmer — Parallax Forums

Simple P2 WiFi WX remote Programmer

By using a simple adapter board I wired up quickly I was able to connect my Plug and Play WX module to my P2.

I then created a P2 C# loader program to interface to the WX module so I could send a program over to the P2.

Here is a picture of the setup with the Hello World program which blinked LED 56.
P2WXModule.jpg

Here is the C# programing screen setup to load the Hello World Program.
P2Programmer.png

This is the C# code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Net.NetworkInformation;
using System.Threading;

namespace WiFiP2loader
{
    public partial class Loader : Form
    {
        string PropHex = "> Prop_Hex 0 0 0 0";
        string PropCheck = "> Prop_Chk 0 0 0 0  ";
        TcpClient tcpClient;
        NetworkStream NS;
        byte[] program;

        public Loader()
        {
            InitializeComponent();
        }

        private void FindWX(object sender, EventArgs e)
        {
            byte[] packet;
            UdpClient udp;
            ESP esp;
            IPAddress address;

            DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(ESP));
            address = null;
            NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
            for (int i=0;i<adapters.Length;i++)
            {
                NetworkInterface n = adapters[i];
                if (n.OperationalStatus == OperationalStatus.Up)
                {
                    IPInterfaceProperties p = n.GetIPProperties();
                    UnicastIPAddressInformationCollection c = p.UnicastAddresses;
                    foreach (UnicastIPAddressInformation f in c)
                    {
                        address = f.Address;
                        i = adapters.Length;
                        break;
                    }
                }
                
            }
            esp = null;
            byte[] b = address.GetAddressBytes();
            b[b.Length - 1] = 255;
            address = new IPAddress(b);
            IPEndPoint iP = new IPEndPoint(address, 32420);
            byte[] discover = new byte[4];
            udp = new UdpClient(32420);
            udp.Send(discover, 4, iP);
            System.Threading.Thread.Sleep(500);
            tcpClient = new TcpClient();
            WXName.Text = "Not Found";
            while (udp.Available > 0)
            {
                packet = udp.Receive(ref iP);
                if (packet.Length > 4)
                {
                    MemoryStream S = new MemoryStream(packet);
                    esp = (ESP)js.ReadObject(S);
                    esp.IP = iP;
                    esp.IP.Port = 80;
                    tcpClient.Connect(esp.IP);
                    NS = tcpClient.GetStream();
                    b = Encoding.UTF8.GetBytes("GET /propeller/reset HTTP/1.1\r\n\r\n");
                    NS.Write(b, 0, b.Length);
                    NS.Close();
                    tcpClient.Close();
                    tcpClient = new TcpClient();
                    esp.IP.Port = 23;
                    tcpClient.Connect(esp.IP);
                    NS = tcpClient.GetStream();
                    WXName.Text = esp.name;
                    WXIP.Text = esp.IP.Address.ToString();
                }
            }
            udp.Close();
        }

        private void DoSend(object sender, EventArgs e)
        {
            byte[] b;
            byte[] data = new byte[256];
            int i;
            string s;


            b = Encoding.UTF8.GetBytes(PropCheck);
            NS.Write(b, 0, b.Length);
            Thread.Sleep(500);
            if (NS.DataAvailable)
            {
                i = NS.Read(data, 0, data.Length);
            }
            i = data[11];
            if ((i < 'A') || (i > 'G'))
            {
                Message.Text = "No Propeller Found!";
                return;
            }
            b = Encoding.UTF8.GetBytes(PropHex);
            NS.Write(b, 0, b.Length);

            //bootstrap bs = new bootstrap();
            program = File.ReadAllBytes("hello.binary");
            for (i = 0; i < program.Length; i++)
            {
                s = string.Format(" {0,2:x2}", program[i]);
                b = Encoding.UTF8.GetBytes(s);
                NS.Write(b, 0, b.Length);
            }
            data[0] = (byte)'~';
            NS.Write(data, 0, 1);
            NS.Flush();
            Message.Text = "Program Loaded";
        }
    }

    [DataContract]
    public class ESP
    {
        [DataMember]
        public string name;
        [DataMember]
        public string description;
        [DataMember(Name = "reset pin")]
        public string resetpin;
        [DataMember(Name = "rx pullup")]
        public string rxpullup;
        [DataMember(Name = "mac address")]
        public string macaddress;
        public IPEndPoint IP;
    }

}

The code sends out a UDP packet to discover the IP address of the WX module. From there it accesses the WX reset code to reset the P2.

Then it opens a telnet connection to the P2.

When I hit the Send button it sends out the "> Prop_Chk 0 0 0 0 " which is the P2 check code that returns a message".
After receiving this message it goes ahead and sends the programming message "> Prop_Hex 0 0 0 0" and sends the Hello World program.

Once the program is sent it sends the "~" to tell the P2 to run the program.

So the hardest part was building code to find the WX module.

I made no changes to the WX module.

Mike

Comments

  • That looks superb.

    Would you mind if this gets included on a Parallax download page at some point ? Maybe I could extend the GUI a little bit with some logos/etc...

    One thing I'm thinking to add would be an auto "file-watcher" feature, so you can set a certain binary filename, and then every time that gets updated (recompiled by some other tool), then this loader could automatically re-download it to the target P2 device. Save a lot of button presses during development!


    If you don't mind, I'm thinking of creating a mini-project tutorial around this topic in January, and I think this would be a great help to many users.
  • Most of the pieces are there to update the loadp2 code to do this.

    We need @ersmith to add the find WX code to the FlexProp tool so that a WX module could be selected and when he builds the upload script he passes an IP address instead of a com port.

    The proploader already has code in it to do remote code loading for the P1. We need the same thing for the P2.

    Mike
  • I agree.

    What I was proposing was to share your solution as an interim (and ready-to-go today) option to a wider audience.
    Perhaps that was misplaced enthusiasm though. Sure- we can wait for the guys to add the feature to the various programmers. Probably it needn't be too far away.

    Regardless.. I'm sure your code sample here will be handy in the future for someone starting out with a comms project. Great that you shared it.
  • iseries wrote: »
    Most of the pieces are there to update the loadp2 code to do this.

    We need @ersmith to add the find WX code to the FlexProp tool so that a WX module could be selected and when he builds the upload script he passes an IP address instead of a com port.

    The proploader already has code in it to do remote code loading for the P1. We need the same thing for the P2.

    Mike

    Please don't wait for me -- I don't even have the hardware right now. What we need is for someone to add WX code to the loadp2 loader, and I can then add whatever GUI changes are needed for that (probably trivial, since the P1 loader already supports it).
  • roglohrogloh Posts: 5,151
    edited 2020-12-18 06:19
    What is required is some type of cross platform conversion/adaptation of the C# code @iseries put together to pretty much do the same things but in C and which works on Linux/MAC/Win platforms. Then it could be integrated into loadp2 fairly easily. The main problem appears to be the C# API/library inherently provides a lot of functionality that would otherwise need to be replaced/implemented natively using sockets etc.

    But basically the same steps are pretty much already done in loadp2:
    Identifying an interface/P2 module to download to,
    resetting the board,
    downloading the code in the correct format,
    and finally optionally opening a console (currently done via serial instead of over a telnet type of interface)
Sign In or Register to comment.