Quantcast
Channel: James's Programming Page
Viewing all articles
Browse latest Browse all 141

Problems writing to Skylander RFID portal

$
0
0

For fun I wanted to to play around with the skylander rfid portal. This is an USB Hid device and the "protocol" is quite simple or so it appears from SKyDumper project (h**ps://github.com/capull0/SkyDumper). This tool SkyDumper works on my linux computer, but when I try to convert it to hidsharp it won't work.

To be more specific.
* I can detect the portal just fine and get the device.
* I can open a HidStream
* I then try to send the "restart" message. Basically report Zero and the letter R, the rest all zeros.
* As soon as this is send out the portal starts sending status messages which I receive continuously. So the message did wake up something.
* However the write errors out with an exception. On my linux laptop its and I/O exception hardcoded in the output source code of hidsharp and on windows its a timeout exception.

I'm no usb export and have little clue why this happens.

I converted portalIO.cpp to the C# code below. I must be missing something silly I think. No reason for it to work using the original cpp code and not thru HidSharp. The first write failure occurs on the call to restartportal. After that I am buried in status output from the portal but nothing else. Any further write messages give the same result

If anyone has a clue or suggestion on what to try next? That would be appreciated.

using System;
using System.Text;
using HidSharp;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using HidSharp.Reports;
using HidSharp.Reports.Input;

namespace SkyReaderLib
{
    public class PortalIO
    {
        public const int rw_buffer_size = 0x21;
        public const int TIMEOUT = 30000;
        public const int SKYLANDER_SIZE = 1024;
        public const int MAX_STR = 255;
        private HidDevice portal;
        private HidStream portalStream;

        private bool initialized = false;


        public event EventHandler<StatusChangedEventArgs> StatusEvent;


        public static IEnumerable<HidDevice> ListPortals()
        {

            IEnumerable<HidDevice> devices = DeviceList.Local.GetHidDevices()
                .Where(x => (x.VendorID == 0x12ba || x.VendorID == 0x54c || x.VendorID == 0x1430)
                    && (x.ProductID == 0x150 || x.ProductID == 0x967));

#if DEBUG
            if (devices.Any())
            {
                Console.WriteLine("Found portal usb devices:");
                foreach (HidDevice device in devices)
                {
                    Console.WriteLine($"\t{device.GetFriendlyName()}");
                }

            }
#endif
            return devices;
        }




        // Send a command to the portal
        private void Write(byte[] message)
        {

            try
            {
                byte[] buffer = new byte[portal.GetMaxOutputReportLength()];
                message.CopyTo(buffer, 0);
#if DEBUG
                Console.WriteLine("Issued report out:");
                Console.WriteLine(string.Join(" ", buffer));
#endif
                portalStream.Write(buffer);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception while issuing a report occured: {e}");
            }
       

        }

        private bool CheckResponse(out RWBlock response, byte expect)
        {
            response = new RWBlock();
#if DEBUG
            Console.WriteLine(">>> CheckResponse\n");
#endif

            int result = portalStream.Read(response.buffer, 0, rw_buffer_size);

            if (result < 0)
                throw new Exception("Could not read response");

#if DEBUG
            Console.WriteLine("CheckResponse read = {0} bytes\n", result);
#endif

            response.dwBytesTransferred = result;

   

            // found wireless USB but portal is not connected
            if (response.buffer[0] == 'Z')
                throw new Exception("Found portal dongle, but portal not connected");

            // Status says no skylander on portal
            // if (response->buffer[0] == 'Q' && response->buffer[1] == 0)
            //     throw 11;


#if DEBUG
            Console.WriteLine("<<< CheckResponse\n");
#endif
            return (response.buffer[0] != expect);

        }

        //
        public void PortalStatus()
        {
            byte[] buffer = new byte[portal.GetMaxOutputReportLength()];

            buffer[0] = 0;
            buffer[1] = (byte)'S';
           
            Write(buffer);
        }


        // Start portal
        public void RestartPortal()
        {
            byte[] buffer = new byte[portal.GetMaxOutputReportLength()];

            buffer[0] = 0;
            buffer[1] = (byte)'R';
            Write(buffer);
                       
        }

        // Antenna up / activate
        public void ActivatePortal(int active)
        {
            byte[] buffer = new byte[portal.GetMaxOutputReportLength()];
           
            buffer[0] = 0;
            buffer[1] = (byte)'A';
            buffer[2] = (byte)active;

            Write(buffer);
        }

        // Set the portal color
        public void SetPortalColor(byte r, byte g, byte b)
        {
            byte[] buffer = new byte[portal.GetMaxOutputReportLength()];

            buffer[0] = 0;
            buffer[1] = (byte)'C';
            buffer[2] = r; // R
            buffer[3] = g; // G
            buffer[4] = b; // B

            Write(buffer);
        }

        // Release hPortalInstance
        ~PortalIO()
        {
            ActivatePortal(0);
            portalStream.Close();
        }

        public void Flash()
        {

            for (; ; )
            {
                ActivatePortal(1);
                ActivatePortal(0);
            }
        }



        public PortalIO(HidDevice portal)
        {
            Console.WriteLine("Connecting to portal.\n");

            this.portal = portal;

            initialized = OpenPortal(portal);
            if (initialized)
            {
                RestartPortal();
                ActivatePortal(1);
                SetPortalColor(0xC8, 0xC8, 0xC8);
            }
            else
            {
                Console.WriteLine("Error initializing portal.");
            }
        }

        private bool OpenPortal(HidDevice portal)
        {
            Console.WriteLine(portal.GetMaxInputReportLength());
            ReportDescriptor descriptor = portal.GetReportDescriptor();

            HidDeviceInputReceiver reciever = descriptor.CreateHidDeviceInputReceiver();
            bool opened = portal.TryOpen(out portalStream);

            var x = portal.GetReportDescriptor();

            reciever.Start(portalStream);
            reciever.Received += OnReceiverReceived;
           
            portalStream.Closed += PortalStreamOnClosed;
           
            return opened;
        }

        private void PortalStreamOnClosed(object? sender, EventArgs e)
        {
            Console.WriteLine("Closed!");
        }

        private void OnReceiverReceived(object sender, EventArgs args)
        {
            try
            {
                var receiver = (HidDeviceInputReceiver)sender;

                if (receiver.Stream?.Device == null)
                {
                    return;
                }

                var length = receiver.Stream.Device.GetMaxInputReportLength();

                var buffer = new byte[length];

                if (receiver.TryRead(buffer, 0, out Report report))
                {
                   // Console.WriteLine($"Received report with id: {report.ReportID}, type: {report.ReportType}");

                    report.Read(buffer, 0, (bytes, offset, item, dataItem) =>
                    {
                       // Console.WriteLine(string.Join(" ", bytes));
                    });

                    switch((char)buffer[1])
                    {
                        case 'S':
                            StatusEvent?.Invoke(this, new StatusChangedEventArgs(buffer));
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    Console.WriteLine("Failed to read report.");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception while reading report occured: {e}");
            }
        }




    }
}


Viewing all articles
Browse latest Browse all 141

Trending Articles