diff --git a/libsharperang/CRC32.cs b/libsharperang/CRC32.cs new file mode 100644 index 0000000..01fcb97 --- /dev/null +++ b/libsharperang/CRC32.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace libsharperang { + public class CRC32 { + public uint Initial { get; private set; } = 0xFFFFFFFF; + private uint Polynomial = 0xedb88320; + //private uint Polynomial = 0x04c11db7; + private uint[] Table; + public bool Initialised=false; + public CRC32(uint Initial) => this.Initial=Initial; + public CRC32() { } + public void Initialise() { + Table=Enumerable.Range(0, 256).Select(i => { + uint e=(uint)i; + for (ushort eb = 0; eb<8; ++eb) { + e=((e&1)!=0) + ? (Polynomial^(e>>1)) + : (e>>1); + } + return e; + }).ToArray(); + Initialised=true; + } + public uint Reflect(uint iv) { + uint ivr=0; + for (int i = 0; i<32; i++) { + uint bit=(iv>>i)&1; + ivr |= (bit<<(31-i)); + } + return ~ivr; + } + public uint GetChecksum(IEnumerable bytes) { + if (!Initialised) Initialise(); + try { + return ~bytes.Aggregate(Initial, + (csR, cB) => Table[(csR & 0xFF) ^ Convert.ToByte(cB)] ^ (csR>>8)); + } catch (FormatException e) { + throw new Exception("Could not read stream as bytes", e); + } catch (InvalidCastException e) { + throw new Exception("Could not read stream as bytes", e); + } catch (OverflowException e) { + throw new Exception("Could not read stream as bytes", e); + } + } + } +} diff --git a/libsharperang/DataTransforms.cs b/libsharperang/DataTransforms.cs index 4635f31..84c076d 100644 --- a/libsharperang/DataTransforms.cs +++ b/libsharperang/DataTransforms.cs @@ -3,29 +3,40 @@ using Crc; namespace libsharperang { public class DataTransforms { - public class CrcSum : Crc32Base { + /*public class CrcSum : Crc32Base { public uint CrcKey; public CrcSum(uint Mangled, uint Key) : base(0x04c11db7, Mangled, 0xffffffff, true, true) => CrcKey=Key; } - private uint Bludgeon(uint iv) { - uint ivr=0; - for (int i=0;i<32;i++) { - uint bit=(iv>>i)&1; - ivr |= (bit<<(31-i)); - } - return ~ivr; + + public CrcSum CRC;*/ + public CRC32 hasher; + private uint MagicNumber=0x35769521; + //public bool IsCrcInitialised() => (CRC!=null); + public bool IsCrcInitialised() => (hasher!=null && hasher.Initialised); + //public void InitialiseCrc() => CRC=new CrcSum(Bludgeon(0x77c40d4d^0x35769521), 0x77c40d4d); + //public void InitialiseCrc(uint Key) => CRC=new CrcSum(Bludgeon(Key), Key); + public void InitialiseCrc(uint Key=0x35769521) { + if (hasher==null || (hasher.Initialised && hasher.Initial != Key)) hasher=new CRC32(Key); + hasher.Initialise(); + } + public byte[] GetHashSum(byte[] data) { + if (!IsCrcInitialised()) InitialiseCrc(); + //return CRC.ComputeHash(data); + return BitConverter.GetBytes(hasher.GetChecksum(data)); } - public CrcSum CRC; - public bool IsCrcInitialised() => (CRC!=null); - public void InitialiseCrc() => CRC=new CrcSum(Bludgeon(0x77c40d4d^0x35769521), 0x77c40d4d); - public void InitialiseCrc(uint Key) => CRC=new CrcSum(Bludgeon(Key), Key); public uint GetCrcKey() { if (!IsCrcInitialised()) InitialiseCrc(); - return CRC.CrcKey; + //return CRC.CrcKey; + return (hasher.Initial == MagicNumber? hasher.Initial : hasher.Initial ^ MagicNumber); } public byte[] GetCrcKeyBytes() { if (!IsCrcInitialised()) InitialiseCrc(); return BitConverter.GetBytes(GetCrcKey()); } + public uint SwapEndianness(uint value) => ( + (value & 0x000000FFU) << 24) | + ((value & 0x0000FF00U) << 8) | + ((value & 0x00FF0000U) >> 8) | + ((value & 0xFF000000U) >> 24); } } diff --git a/libsharperang/usb.cs b/libsharperang/usb.cs index 6451efc..9b16755 100644 --- a/libsharperang/usb.cs +++ b/libsharperang/usb.cs @@ -62,6 +62,7 @@ using LibUsbDotNet.Main; namespace libsharperang { public class Frame { public DataTransforms transformer=new DataTransforms(); + public enum Opcode { SessionBegin = 10, SessionEnd, @@ -69,6 +70,8 @@ namespace libsharperang { PrintContinue, CrcTransmit = 30 } + private byte FrameStart = 0x02; + private byte FrameEnd = 0x03; private byte[] ResolveOpcode(Opcode opcode) { switch (opcode) { case Opcode.SessionBegin: return new byte[] { 0x06, 0x00, 0x02, 0x00 }; @@ -81,24 +84,24 @@ namespace libsharperang { } public byte[] Build(Opcode opcode, byte[] data) => Build(opcode, data, transformer); public byte[] Build(Opcode opcode, byte[] data, DataTransforms transformer) { - if (!transformer.IsCrcInitialised()) transformer.InitialiseCrc(); byte[] result=new byte[data.Length+10]; - result[0]=0x02; - result[result.Length-1]=0x03; + result[0]=FrameStart; + result[result.Length-1]=FrameEnd; Buffer.BlockCopy(ResolveOpcode(opcode), 0, result, 1, 4); Buffer.BlockCopy(data, 0, result, 5, data.Length); - Buffer.BlockCopy(transformer.CRC.ComputeHash(data), 0, result, result.Length-5, 4); + Buffer.BlockCopy(transformer.GetHashSum(data), 0, result, result.Length-5, 4); return result; } public byte[] BuildTransmitCrc() { + if (!transformer.IsCrcInitialised()) transformer.InitialiseCrc(0x77c40d4d^0x35769521); DataTransforms _=new DataTransforms(); - _.InitialiseCrc(0x35769521); + _.InitialiseCrc(); return Build(Opcode.CrcTransmit, transformer.GetCrcKeyBytes(), _); } } public class USBPrinter : Base, IPrinter { - // TODO - work out if it's possible to get this working with the default usbprint.inf driver Windows uses on plugging in - // otherwise any user would have to first use Zadig to change the driver to WinUSB + // TODO - work out if it's possible to get this working with the default usbprint.inf driver Windows uses on plugging in + // otherwise any user would have to first use Zadig to change the driver to WinUSB private UsbDevice _uDv; private UsbEndpointWriter _uWr; private UsbEndpointReader _uRd;