diff --git a/liblogtiny/ILogTiny.cs b/liblogtiny/ILogTiny.cs index d352bd7..5b3fe8d 100644 --- a/liblogtiny/ILogTiny.cs +++ b/liblogtiny/ILogTiny.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace liblogtiny { +namespace liblogtiny { public partial class LogTiny { public enum LogLevel { Trace, diff --git a/libpaperang/Helpers/CRC.cs b/libpaperang/Helpers/CRC.cs index 00c68c6..49bb883 100644 --- a/libpaperang/Helpers/CRC.cs +++ b/libpaperang/Helpers/CRC.cs @@ -5,55 +5,57 @@ using System.Linq; namespace libpaperang.Helpers { public class CRC { private uint _iv; - public uint iv { get => ~_iv; private set => _iv=~value; } - public uint mv = 0x35769521; + public uint Iv { get => ~_iv; private set => _iv = ~value; } + public uint Mv => 0x35769521u; private uint poly = 0xedb88320; private uint[] crctable; public bool IsInitialised=false; public CRC(bool autoinit = true) { - iv = 0; - if(autoinit) Initialise(); + Iv = 0; + if(autoinit) + Initialise(); } public CRC(uint iv, bool autoinit = true) { - this.iv = iv; - if (autoinit) Initialise(); + Iv = iv; + if(autoinit) + Initialise(); } public void Initialise() { - crctable=Enumerable.Range(0, 256).Select(i => { + crctable = Enumerable.Range(0, 256).Select(i => { uint e=(uint)i; - for (ushort eb = 0; eb<8; eb++) - e=((e&1)!=0) - ? (poly^(e>>1)) - : (e>>1); + for(ushort eb = 0; eb < 8; eb++) { + e = ((e & 1) != 0) + ? (poly ^ (e >> 1)) + : (e >> 1); + } return e; }).ToArray(); - IsInitialised=true; + IsInitialised = true; } public uint Reflect(uint iv) { uint ivr=0; - for (int i = 0; i<32; i++) { + for(int i = 0; i < 32; i++) { uint b=(iv>>i)&1; - ivr|=(b<<(31-i)); + ivr |= b << (31 - i); } return ~ivr; } public uint GetChecksumUint(IEnumerable data) { - if (!IsInitialised) throw new CrcNotAvailableException(); + if(!IsInitialised) + throw new CrcNotAvailableException(); try { return ~data.Aggregate(_iv, - (cti, cb) => crctable[(cti&0xFF)^Convert.ToByte(cb)]^(cti>>8)); - } catch (FormatException e) { + (cti, cb) => crctable[(cti & 0xFF) ^ Convert.ToByte(cb)] ^ (cti >> 8)); + } catch(FormatException e) { throw new FormatException("Could not read input as a byte stream", e); - } catch (InvalidCastException e) { + } catch(InvalidCastException e) { throw new InvalidCastException("Could not read input as a byte stream", e); - } catch (OverflowException e) { + } catch(OverflowException e) { throw new OverflowException("Could not read input as a byte stream", e); } } public byte[] GetChecksumBytes(IEnumerable data) => BitConverter.GetBytes(GetChecksumUint(data)); - public uint GetCrcIv() => iv == mv - ? iv - : iv ^ mv; + public uint GetCrcIv() => Iv == Mv ? Iv : Iv ^ Mv; public byte[] GetCrcIvBytes() => BitConverter.GetBytes(GetCrcIv()); } } diff --git a/libpaperang/Helpers/Media.cs b/libpaperang/Helpers/Media.cs deleted file mode 100644 index f6c7cb2..0000000 --- a/libpaperang/Helpers/Media.cs +++ /dev/null @@ -1,5 +0,0 @@ - -namespace libpaperang.Helpers { - class Media { - } -} diff --git a/libpaperang/Helpers/Transforms.cs b/libpaperang/Helpers/Transforms.cs index 1d7beac..c0dddb4 100644 --- a/libpaperang/Helpers/Transforms.cs +++ b/libpaperang/Helpers/Transforms.cs @@ -7,23 +7,29 @@ namespace libpaperang.Helpers { public BaseTypes.Opcodes Op; public short OpLen; public Transforms(BaseTypes.Packet FrameConstruction, BaseTypes.Opcodes Operations, short OperLen) { - Frame=FrameConstruction; - Op=Operations; - OpLen=OperLen; + Frame = FrameConstruction; + Op = Operations; + OpLen = OperLen; } public byte[] Oper(BaseTypes.Operations Operation) { - switch (Operation) { - case BaseTypes.Operations.NoOp: return Op.NoOp; - case BaseTypes.Operations.LineFeed: return Op.LineFeed; - case BaseTypes.Operations.CrcTransmit: return Op.TransmitCrc; - case BaseTypes.Operations.Print: return Op.Print; - default: throw new InvalidOperationException(); + switch(Operation) { + case BaseTypes.Operations.NoOp: + return Op.NoOp; + case BaseTypes.Operations.LineFeed: + return Op.LineFeed; + case BaseTypes.Operations.CrcTransmit: + return Op.TransmitCrc; + case BaseTypes.Operations.Print: + return Op.Print; + default: + throw new InvalidOperationException(); } } public byte[] Arg(BaseTypes.Operations Operation, uint Data) { switch(Operation) { - case BaseTypes.Operations.LineFeed: return BitConverter.GetBytes(SwapWordEndianness( - 0x00000000 | ((((( + case BaseTypes.Operations.LineFeed: + return BitConverter.GetBytes(SwapWordEndianness( + 0x00000000 | ((((( Data & 0xffu) << 16) | Data) & 0xffff00u) >> 8))).Skip(2).ToArray(); case BaseTypes.Operations.Print: @@ -31,17 +37,18 @@ namespace libpaperang.Helpers { 0x00010000 | ((((( Data & 0xffu) << 16) | Data) & 0xffff00u) >> 8))); - default: throw new InvalidOperationException(); + default: + throw new InvalidOperationException(); } } public byte[] Packet(byte[] oper, byte[] data, CRC checksum) { byte[] packet = new byte[1+oper.Length+data.Length+5]; packet[0] = Frame.Start; - packet[packet.Length-1] = Frame.End; + packet[packet.Length - 1] = Frame.End; Buffer.BlockCopy(oper, 0, packet, 1, oper.Length); Buffer.BlockCopy(data, - 0, packet, oper.Length+1, data.Length); + 0, packet, oper.Length + 1, data.Length); Buffer.BlockCopy(checksum.GetChecksumBytes(data), 0, packet, packet.Length - 5, 4); return packet; @@ -54,7 +61,7 @@ namespace libpaperang.Helpers { return p; } public uint SwapWordEndianness(uint value) => ( - (value & 0x000000ffu) << 24)| + (value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); diff --git a/libpaperang/IPrinter.cs b/libpaperang/IPrinter.cs index c4a994f..580201e 100644 --- a/libpaperang/IPrinter.cs +++ b/libpaperang/IPrinter.cs @@ -55,6 +55,8 @@ namespace libpaperang { } public interface IPrinter { short LineWidth { get; } + short BasePrintDelay { get; } + uint MaximumDataSize { get; } BaseTypes.Connection ConnectionMethod { get; } BaseTypes.Model PrinterVariant { get; } BaseTypes.State Status { get; } diff --git a/libpaperang/Interfaces/USB.cs b/libpaperang/Interfaces/USB.cs index 7098b85..eccc53e 100644 --- a/libpaperang/Interfaces/USB.cs +++ b/libpaperang/Interfaces/USB.cs @@ -10,7 +10,7 @@ namespace libpaperang.Interfaces { // constants private const ushort iV = 0x4348; private const ushort iP = 0x5584; - private const short MaxDataSize = 1008; + public uint MaximumDataSize => 1008; // types private struct UsbComms { @@ -20,21 +20,35 @@ namespace libpaperang.Interfaces { public UsbEndpointWriter tx; } private UsbComms Printer; - private BaseTypes.Model iModel; - private bool _initialised=false; + public short LineWidth { get { - switch (iModel) { - case BaseTypes.Model.P1: return 48; - case BaseTypes.Model.P2: return 72; - case BaseTypes.Model.P2S: return 72; //assumption - case BaseTypes.Model.T1: throw new PrinterVariantNotSupportedException(); - default: throw new InvalidOperationException(); + switch(PrinterVariant) { + case BaseTypes.Model.P1: + return 48; + case BaseTypes.Model.P2: + return 72; + case BaseTypes.Model.T1: + throw new PrinterVariantNotSupportedException(); + default: + throw new InvalidOperationException(); + } + } + } + public short BasePrintDelay { + get { + switch(PrinterVariant) { + case BaseTypes.Model.P1: + return 80; + case BaseTypes.Model.P2: + return 140; + default: + throw new InvalidOperationException(); } } } public BaseTypes.Connection ConnectionMethod => BaseTypes.Connection.USB; - public BaseTypes.Model PrinterVariant => iModel; + public BaseTypes.Model PrinterVariant { get; private set; } public BaseTypes.State Status => BaseTypes.State.Offline; public List AvailablePrinters { get { @@ -52,33 +66,36 @@ namespace libpaperang.Interfaces { } } public bool PrinterAvailable => AvailablePrinters.Count > 0; - public bool PrinterInitialised => _initialised; + public bool PrinterInitialised { get; private set; } = false; public bool PrinterOpen => Printer.handle?.IsOpen ?? false; + public void OpenPrinter(BaseTypes.Printer printer) { + bool res; + try { + res = ((UsbRegistry)printer.Instance).Open(out Printer.handle); + } catch(Exception) { + throw new PrinterNotAvailableException(); + } + if(!res) + throw new PrinterNotAvailableException(); + } public void ClosePrinter() => Printer.handle?.Close(); + public void Initialise() { + if(!PrinterOpen) + throw new PrinterNotInitialisedException(); + //WinUSB-specific + Printer.iface = Printer.handle as IUsbDevice; + _ = Printer.iface?.SetConfiguration(1); + _ = Printer.iface?.ClaimInterface(0); + Printer.rx = Printer.handle.OpenEndpointReader(ReadEndpointID.Ep01); + Printer.tx = Printer.handle.OpenEndpointWriter(WriteEndpointID.Ep02); + PrinterInitialised = true; + } public void Deinitialise() { Printer.rx?.Dispose(); Printer.tx?.Dispose(); _ = Printer.iface?.ReleaseInterface(0); _ = Printer.iface?.Close(); - } - public void Initialise() { - if (!PrinterOpen) throw new PrinterNotInitialisedException(); - //WinUSB-specific - Printer.iface=Printer.handle as IUsbDevice; - _=Printer.iface?.SetConfiguration(1); - _=Printer.iface?.ClaimInterface(0); - Printer.rx=Printer.handle.OpenEndpointReader(ReadEndpointID.Ep01); - Printer.tx=Printer.handle.OpenEndpointWriter(WriteEndpointID.Ep02); - _initialised = true; - } - public void OpenPrinter(BaseTypes.Printer printer) { - bool res; - try { - res=((UsbRegistry)printer.Instance).Open(out Printer.handle); - } catch (Exception) { - throw new PrinterNotAvailableException(); - } - if (!res) throw new PrinterNotAvailableException(); + ClosePrinter(); } public byte[] ReadBytes() { byte[] readbuf=new byte[1024]; @@ -91,6 +108,6 @@ namespace libpaperang.Interfaces { Thread.Sleep(delay); return _; } - public USB(BaseTypes.Model model) => iModel=model; + public USB(BaseTypes.Model model) => PrinterVariant = model; } } diff --git a/libpaperang/Main/Paperang.cs b/libpaperang/Main/Paperang.cs index 34906c1..9ac91f2 100644 --- a/libpaperang/Main/Paperang.cs +++ b/libpaperang/Main/Paperang.cs @@ -1,8 +1,8 @@ -using libpaperang.Helpers; -using libpaperang.Interfaces; -using liblogtiny; +using System.Collections.Generic; using System.Linq; -using System.Collections.Generic; +using liblogtiny; +using libpaperang.Helpers; +using libpaperang.Interfaces; namespace libpaperang.Main { public class Paperang { @@ -75,7 +75,7 @@ namespace libpaperang.Main { logger?.Trace($"PrintBytes() invoked with data length of {data.Length}"); List segments = data .Select((b,i) => new {Index=i,Value=b }) - .GroupBy(b=>b.Index/1008) + .GroupBy(b=>b.Index/Printer.MaximumDataSize) .Select(b=>b.Select(bb=>bb.Value).ToArray()) .ToList(); logger?.Trace($"data split into {segments.Count} segment(s)"); @@ -84,7 +84,9 @@ namespace libpaperang.Main { Transform.Arg(BaseTypes.Operations.Print, (uint)b.Length), b, Crc), - 200-(b.Length/Printer.LineWidth))); + Printer.BasePrintDelay + (b.Length / Printer.LineWidth))); + if(autofeed) + Feed(185); } } } diff --git a/paperangapp/LUITextbox.cs b/paperangapp/LUITextbox.cs index 04e879a..f6ff40b 100644 --- a/paperangapp/LUITextbox.cs +++ b/paperangapp/LUITextbox.cs @@ -1,5 +1,5 @@ -using liblogtiny; -using System.ComponentModel; +using System.ComponentModel; +using liblogtiny; namespace paperangapp { class LUITextbox : ILogTiny, INotifyPropertyChanged { @@ -11,13 +11,13 @@ namespace paperangapp { //get { return _LogBuffer; } get => _LogBuffer; set { - if (value == _LogBuffer) return; - if (value == "!clearlog") _LogBuffer = ""; - else _LogBuffer = value + "\n" + _LogBuffer; + if(value == _LogBuffer) + return; + _LogBuffer = value == "!clearlog" ? "" : value + "\n" + _LogBuffer; OnPropertyChanged("LogBuffer"); } } - public void ClearBuffer() => LogBuffer="!clearlog"; + public void ClearBuffer() => LogBuffer = "!clearlog"; public void Trace(string msg) => Log(LogTiny.LogLevel.Trace, msg); public void Debug(string msg) => Log(LogTiny.LogLevel.Debug, msg); public void Verbose(string msg) => Log(LogTiny.LogLevel.Verbose, msg); @@ -25,7 +25,7 @@ namespace paperangapp { public void Warn(string msg) => Log(LogTiny.LogLevel.Warn, msg); public void Error(string msg) => Log(LogTiny.LogLevel.Error, msg); public void Critical(string msg) => Log(LogTiny.LogLevel.Critical, msg); - public void Log(LogTiny.LogLevel level, string msg) => LogBuffer=$"{level}: {msg}"; - public void Raw(string msg) => LogBuffer=msg; + public void Log(LogTiny.LogLevel level, string msg) => LogBuffer = $"{level}: {msg}"; + public void Raw(string msg) => LogBuffer = msg; } } diff --git a/paperangapp/MainWindow.xaml.cs b/paperangapp/MainWindow.xaml.cs index 9ed9b29..9619f31 100644 --- a/paperangapp/MainWindow.xaml.cs +++ b/paperangapp/MainWindow.xaml.cs @@ -1,15 +1,14 @@ -using liblogtiny; -using libpaperang; -using libpaperang.Interfaces; -using libpaperang.Main; -using System; -using System.Timers; -using System.Windows; -using System.Windows.Forms; -//testing +using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; +using System.Timers; +using System.Windows; +using System.Windows.Forms; +using liblogtiny; +using libpaperang; +using libpaperang.Interfaces; +using libpaperang.Main; namespace paperangapp { public partial class MainWindow : Window { @@ -25,7 +24,7 @@ namespace paperangapp { UnInitDev, InitDev }; - private AppState state=AppState.UnInitNoDev; + private AppState state=AppState.UnInitDev; // TODO: is it out of scope for this library to provide functionality for printing bitmap data? public MainWindow() { InitializeComponent(); @@ -35,14 +34,14 @@ namespace paperangapp { usbpoll = new System.Timers.Timer(200) { AutoReset = true }; - usbpoll.Elapsed += evtUsbPoll; + usbpoll.Elapsed += EvtUsbPoll; usbpoll.Start(); logger.Verbose("USB presence interval event started"); } - private void evtUsbPoll(object sender, ElapsedEventArgs e) =>_ = Dispatcher.BeginInvoke(new invDgtUsbPoll(dgtUsbPoll)); + private void EvtUsbPoll(object sender, ElapsedEventArgs e) => _ = Dispatcher.BeginInvoke(new invDgtUsbPoll(DgtUsbPoll)); private delegate void invDgtUsbPoll(); - private void dgtUsbPoll() { + private void DgtUsbPoll() { try { if(state == AppState.UnInitNoDev && prtr.PrinterAvailable) { btInitUSB.IsEnabled = true; @@ -63,7 +62,8 @@ namespace paperangapp { ~MainWindow() { logger.Warn("Application closing"); - if(mmj!=null) USBDeInit(); + if(mmj != null) + USBDeInit(); } private void BtClearLog_Click(object sender, RoutedEventArgs e) => logger.Raw("!clearlog"); @@ -115,9 +115,14 @@ namespace paperangapp { } private void BtFeed_Click(object sender, RoutedEventArgs e) => mmj.Feed((uint)slFeedTime.Value); private void BtPrintText_Click(object sender, RoutedEventArgs e) { + if(!(txInput.Text.Length > 0)) { + logger.Warn("PrintText event but nothing to print."); + return; + } Font fnt=new Font(txFont.Text, int.Parse(txSzF.Text)); Graphics g=Graphics.FromImage(new Bitmap(mmj.Printer.LineWidth*8, 1)); - SizeF szText=g.MeasureString(txInput.Text, fnt); + System.Drawing.Size szText = TextRenderer.MeasureText(g, txInput.Text, fnt); + //SizeF szText=g.MeasureString(txInput.Text, fnt); g.Dispose(); Bitmap b=new Bitmap(mmj.Printer.LineWidth*8, (int)szText.Height); g = Graphics.FromImage(b); @@ -125,34 +130,37 @@ namespace paperangapp { g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; - g.DrawString(txInput.Text, fnt, Brushes.Black, new PointF(0,0)); + TextRenderer.DrawText(g, txInput.Text, fnt, new System.Drawing.Point(0, 0), Color.Black); g.Flush(); PrintBitmap(b); g.Dispose(); b.Dispose(); } private void BtPrintImage_Click(object sender, RoutedEventArgs e) { - logger.Debug("Loading image for print"); + logger.Debug("Invoking file selection dialogue."); OpenFileDialog r = new OpenFileDialog { Title="Select 1 (one) image file", Multiselect=false, Filter="PNG files|*.png|JPEG files|*.jpg;*.jpeg|Jraphics Interchange Format files|*.gif|Bitte-Mappe files|*.bmp|All of the above|*.jpg;*.jpeg;*.png;*.gif;*.bmp", AutoUpgradeEnabled=true }; - if (r.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) { - logger.Debug("Image load cancelled"); + if(r.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) { + logger.Warn("PrintImage event but no file was selected."); + r.Dispose(); return; } + logger.Debug("Loading image for print"); Image _=Image.FromFile(r.FileName); logger.Debug("Loaded image " + r.FileName); r.Dispose(); logger.Debug("Disposed of dialog"); - Bitmap bimg=new Bitmap(_, (mmj.Printer.LineWidth*8), - (int)((double)(mmj.Printer.LineWidth*8)*(double)((double)_.Height/(double)_.Width))); + Bitmap bimg=new Bitmap(_, mmj.Printer.LineWidth*8, + (int)(mmj.Printer.LineWidth*8*(double)((double)_.Height/(double)_.Width))); logger.Debug("Loaded image as Bitmap"); _.Dispose(); logger.Debug("Disposed of Image"); PrintBitmap(bimg); + bimg.Dispose(); } private void PrintBitmap(Bitmap bimg) { bimg = CopyToBpp(bimg); @@ -172,17 +180,12 @@ namespace paperangapp { for(int h = 0; h < hSzImg; h++) { for(int w = 0; w < mmj.Printer.LineWidth; w++) { iimg[(mmj.Printer.LineWidth * (hSzImg - 1 - h)) + (mmj.Printer.LineWidth - 1 - w)] = (byte)~ - (img[startoffset + (mmj.Printer.LineWidth * h) + (mmj.Printer.LineWidth - 1 - w)]); + img[startoffset + (mmj.Printer.LineWidth * h) + (mmj.Printer.LineWidth - 1 - w)]; } } - logger.Debug($"Have {img.Length} bytes of print data ({mmj.Printer.LineWidth*8}x{hSzImg}@1bpp)"); + logger.Debug($"Have {img.Length} bytes of print data ({mmj.Printer.LineWidth * 8}x{hSzImg}@1bpp)"); mmj.PrintBytes(iimg, false); - //mmj.Feed(175); } - static uint BitSwap1(uint x) => ((x & 0x55555555u) << 1) | ((x & (~0x55555555u)) >> 1); - static uint BitSwap2(uint x) => ((x & 0x33333333u) << 2) | ((x & (~0x33333333u)) >> 2); - static uint BitSwap4(uint x) => ((x & 0x0f0f0f0fu) << 4) | ((x & (~0x0f0f0f0fu)) >> 4); - static uint BitSwap(uint x) => BitSwap4(BitSwap2(BitSwap1(x))); #region GDIBitmap1bpp static Bitmap CopyToBpp(Bitmap b) { int w=b.Width, h=b.Height; @@ -198,11 +201,11 @@ namespace paperangapp { biXPelsPerMeter=1000000, biYPelsPerMeter=1000000 }; - bmi.biClrUsed=2; - bmi.biClrImportant=2; - bmi.cols=new uint[256]; - bmi.cols[0]=MAKERGB(0, 0, 0); - bmi.cols[1]=MAKERGB(255, 255, 255); + bmi.biClrUsed = 2; + bmi.biClrImportant = 2; + bmi.cols = new uint[256]; + bmi.cols[0] = MAKERGB(0, 0, 0); + bmi.cols[1] = MAKERGB(255, 255, 255); IntPtr hbm0 = CreateDIBSection(IntPtr.Zero,ref bmi,DIB_RGB_COLORS,out _,IntPtr.Zero,0); IntPtr sdc = GetDC(IntPtr.Zero); IntPtr hdc = CreateCompatibleDC(sdc); @@ -248,7 +251,7 @@ namespace paperangapp { [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=256)] public uint[] cols; } - static uint MAKERGB(int r, int g, int b) => ((uint)(b&255)) | ((uint)((r&255)<<8)) | ((uint)((g&255)<<16)); + static uint MAKERGB(int r, int g, int b) => ((uint)(b & 255)) | ((uint)((r & 255) << 8)) | ((uint)((g & 255) << 16)); #endregion } }