• Quick .Net api#

  • Jester Reply #1, 5 months ago

    Reply
    I did a quick (partial) port of the PyMetaWatch to .Net. This enables desktop and MonoDroid integration. It should get our Windows/C# programmers going.

     //REF: https://github.com/travisgoodspeed/PyMetaWatch/blob/master/pymw.py
    
        public class MetaWatchProtocol
        {
            public static byte[] BuildMessage()
            {
                //TEST:
                return null;
            }
    
            enum ScreenMode { MODE_IDLE = 0, MODE_APPLICATION = 1, MODE_NOTIFICATION = 2, MODE_SCROLL = 3 };
            enum StatusChange {STATUS_CHANGE_MODE = 0, STATUS_CHANGE_DISPLAYIMEOUT = 1};
            enum Button { A=0, B=1, C=2, D=3, E=5, F=6 };
            enum ButtonType { Immediate = 0, PressAndRelease = 1, HoldAndRelease = 2, LongHoldAndRelease = 3 };
    
            // Time to pause between packets
            //#_TX_PACKET_WAIT_SEC = 0.025 #per Javier's empirical values.
            float _TX_PACKET_WAIT_SEC = 0.2f;
            //#_TX_PACKET_WAIT_SEC = 0.1   #per Goodspeed's less optimistic values.
    
            #region CRC
            class CRC_CCITT
            {
                // Implementation of CRC-16-CCITT
    
                bool inverted = true;
                static uint[] table = null;
                static uint[] flipmask = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
    
                public CRC_CCITT()
                {
                    init();
                }
    
                void init()
                {
                    if (null != table)
                        return;
    
                    uint crc = 0xFFFF;          // initial value
                    const uint polynomial = 0x1021;   // 0001 0000 0010 0001  (0, 5, 12) 
                    table = new uint[256];
                    uint c;
                    for (uint idx = 0; idx < table.Length; idx++)
                    {
                        crc = 0;
                        c = idx << 8;
                        for(int j=0; j<8; j++)
                            if (0x8000 == ((crc^c) & 0x8000))
                                crc = (crc<<1)^polynomial;
                            else
                                crc <<= 1;
                        c <<= 1;
                        crc &= 0xFFFF;
                        table[idx] = crc;
                    }
                }
    
                
                public uint update_crc(uint crc, uint c)
                {
                    c = 0x00ff & (c % 256);
                    if (inverted)
                        c = flip(c);
                    
                    uint tmp = ((crc >> 8) ^ c) & 0xffff;
                    crc = (((crc << 8) ^ table[tmp])) & 0xffff;
                    return crc;
                }
    
                public uint checksum(byte[] bytes)
                {
                    uint v = 0xFFFF;
                    for(int i=0; i< bytes.Length - 2; i++)
                        v = update_crc(v, (uint)bytes[i]);
                    return v;
                }
    
                uint flip( uint c)
                {
                    // MetaWatch/Fossil requires bitflipping
                    return (flipmask[c & 0x0F] << 4) + flipmask[ (c & 0xF0) >> 4 ];
                }
            }
            #endregion
    
            public string SetDisplayInverted(bool value)
            {
                return value ? "\x41\x00\x00\x01" : "\x41\x00\x00\x00";
            }
    
            public byte[] Buzz()
            {
                return Buzz( 500, 500, 1);
            }
            public byte[] Buzz( int millisecOn, int millisecOff, int cycles )
            {
                //Buzz the buzzer.
                return new byte[] { 0x23, 0x00, 0x01, 
                                 (byte)(millisecOn >> 8), (byte)(millisecOn & 0xFF),
                                 (byte)(millisecOff >> 8), (byte)(millisecOff & 0xFF),
                                 (byte)(cycles & 0xFF )
                             };
            }
    
            CRC_CCITT CRC = new CRC_CCITT();
    
            public byte[] BuildMessage( byte[] cmd )
            {
                byte[] sendbuf = new byte[4 + cmd.Length];
                sendbuf[0] = 0x01;
                sendbuf[1] = (byte)((cmd.Length + 4) & 0xFF);
                Buffer.BlockCopy(cmd, 0, sendbuf, 2, cmd.Length);
                uint crc = CRC.checksum(sendbuf);
                //Little Endian
                sendbuf[sendbuf.Length-2] = (byte)(crc & 0xFF);
                sendbuf[sendbuf.Length-1] = (byte)(crc >> 8);
                return sendbuf;
            }
        }


    And to use, simple generate the byte buffer and send it to the serial port.

    for MonoDroid (but desktop is trivial. Just use SerialPort:
    void Talk()
            {
                BluetoothAdapter bluetooth = BluetoothAdapter.DefaultAdapter;
                if (!bluetooth.IsEnabled)
                    bluetooth.Enable();
    
                ICollection<BluetoothDevice> devices = bluetooth.BondedDevices;
                foreach (BluetoothDevice device in devices)
                {
                    if (device.Name.Contains("Watch"))
                    {
                        BluetoothSocket socket = device.CreateRfcommSocketToServiceRecord(Java.Util.UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
                        socket.Connect();
                        try
                        {
                            MetaWatchProtocol protocol = new MetaWatchProtocol();
                            byte[] message = protocol.BuildMessage(protocol.Buzz());
                            socket.OutputStream.Write( message, 0, message.Length);
                            socket.OutputStream.Flush();
    
                        }
                        finally
                        {
                            socket.Close();
                        }
                    }
                }
            }

  • magicroomy Reply #2, 4 months, 2 weeks ago

    Reply
    Hi Jester,
    thanx for your port of the Py Lib, but i have trouble with it.
    I try to use it in a little test program.
    I managed to manipulate my MetaWatch when i send predefined byte arrays i picked from somewhere as example. They contain all the bytes including the CRC. This works fine.
    An example is: 0x01,0x0c,0x23,0x00,0x01,0xf4,0x01,0xf4,0x01,0x01,0x81,0xb1

    Now i would like to send my own sequences to control the Watch. I use your CRC port (Actually the MetaWatchProtocol Class). It does not work so i decided to check the crc routine within the MetaWatchProtocol.
    The data i give to the public byte[] BuildMessage(byte[] cmd) method is:
    0x23,0x00,0x01,0xf4,0x01,0xf4,0x01,0x01
    Only the command, and no crc. The example is taken from above.
    I would expect that the generated CRC checksum is 0x81,0xb1, but it is not.
    It is 0x00 and 0x00.
    I could need some help on that.
    Thanx
    Volker



  • magicroomy Reply #3, 4 months, 2 weeks ago

    Reply
    Hi Jester,
    thanx for your port of the Py Lib, but i have trouble with it.
    I try to use it in a little test program.
    I managed to manipulate my MetaWatch when i send predefined byte arrays i picked from somewhere as example. They contain all the bytes including the CRC. This works fine.
    An example is: 0x01,0x0c,0x23,0x00,0x01,0xf4,0x01,0xf4,0x01,0x01,0x81,0xb1

    Now i would like to send my own sequences to control the Watch. I use your CRC port (Actually the MetaWatchProtocol Class). It does not work so i decided to check the crc routine within the MetaWatchProtocol.
    The data i give to the public byte[] BuildMessage(byte[] cmd) method is:
    0x23,0x00,0x01,0xf4,0x01,0xf4,0x01,0x01
    Only the command, and no crc. The example is taken from above.
    I would expect that the generated CRC checksum is 0x81,0xb1, but it is not.
    It is 0x00 and 0x00.
    I could need some help on that.
    Thanx
    Volker